暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

知识图谱系列:Task 1 知识图谱介绍

网安杂谈 2021-01-11
561


本文是Datawhale知识图谱组队学习打卡笔记

学习资源地址:

https://github.com/datawhalechina/team-learning-nlp/tree/master/KnowledgeGraph_Basic

感谢Datawhale社区的无私分享

想学习的小伙伴可以一起来


1.知识图谱

知识图谱本质上是语义网络(Semantic Network)的知识库。
从实际应用的角度出发其实可以简单地把知识图谱理解成多关系图(Multi-relational Graph)。

知识图谱是人工智能很重要的一个分支, 人工智能的目标为了让机器具备像人一样理性思考及做事的能力 -> 在符号主义的引领下,知识工程(核心内容即建设专家系统)取得了突破性的进展 -> 在整个知识工程的分支下,知识表示是一个非常重要的任务 -> 而知识图谱又恰恰是知识表示的重要一环。

图的概念:
图(Graph)是由节点(Vertex)和边(Edge)来构成,多关系图一般包含多种类型的节点和多种类型的边。实体(节点)指的是现实世界中的事物比如人、地名、概念、药物、公司等,关系(边)则用来表达不同实体之间的某种联系。


Schema的概念:
知识图谱另外一个很重要的概念是 Schema,限定待加入知识图谱数据的格式;相当于某个领域内的数据模型,包含了该领域内有意义的概念类型以及这些类型的属性。用于规范结构化数据的表达,一条数据必须满足Schema预先定义好的实体对象及其类型,才被允许更新到知识图谱中。

上图中的DataType限定了知识图谱节点值的类型为文本、日期、数字(浮点型与整型)
图中的Thing限定了节点的类型及其属性(即图中的边)
举例说明:基于下图Schema构建的知识图谱中仅可含作品、地方组织、人物;其中作品的属性为电影与音乐、地方组织的属性为当地的商业(eg:饭店、俱乐部等)、人物的属性为歌手
tips:本次组队学习不涉及schema的构建
Ontology本体:
Ontology:通常翻译为“本体”。本体本身是个哲学名词。在上个世纪80年代,人工智能研究人员将这一概念引入了计算机领域。Tom Gruber把本体定义为“概念和关系的形式化描述”。通俗点讲,本体相似于数据库中的Schema,比如足球领域,主要用来定义类和关系,以及类层次和关系层次等。OWL是最常用的本体描述语言。本体通常被用来为知识图谱定义Schema。

2.知识图谱构建

2.1数据来源

知识图谱的构建是后续应用的基础,而且构建的前提是需要把数据从不同的数据源中抽取出来。对于垂直领域的知识图谱来说,它们的数据源主要来自两种渠道:
第一种:业务本身的数据。这部分数据通常包含在公司内的数据库表并以结构化的方式存储,一般只需要简单预处理即可以作为后续AI系统的输入;
第二种:网络上公开、抓取的数据。这些数据通常是以网页的形式存在所以是非结构化的数据,一般需要借助于自然语言处理等技术来提取出结构化信息。

如下图所示,难点是非结构化数据的处理。

2.2处理技术

构建知识图谱过程当中,主要涉及以下几个方面的自然语言处理技术:

2.2.1实体命名识别(Name Entity Recognition)简称NER

实体命名识别目标就是从文本里提取出实体并对每个实体做分类/打标签;
比如从上述文本里,我们可以提取出实体-“NYC”,并标记实体类型为 “Location”;我们也可以从中提取出“Virgil's BBQ”,并标记实体类型为“Restarant”。
这种过程称之为实体命名识别,这是一项相对比较成熟的技术,有一些现成的工具可以用来做这件事情。

2.2.2关系抽取(Relation Extraction)简称 RE

通过关系抽取技术,把实体间的关系从文本中提取出来;
比如实体“hotel”和“Hilton property”之间的关系为“in”;“hotel”和“Time Square”的关系为“near”等等。

2.2.3实体统一(Entity Resolution)简称 ER

对于有些实体写法上不一样,但其实是指向同一个实体;
举例说明:比如“NYC”和“New York”表面上是不同的字符串,但其实指的都是纽约这个城市,需要合并。
价值:实体统一不仅可以减少实体的种类,也可以降低图谱的稀疏性(Sparsity)


2.2.4指代消解(Coreference Resolution)

指代消解(Disambiguation)指文本中出现的“it”, “he”, “she”这些词到底指向哪个实体,比如在本文里两个被标记出来的“it”都指向“hotel”这个实体。



2.3知识图谱的存储

知识图谱主要有两种存储方式:
一种是基于RDF的存储;
另一种是基于图数据库的存储。

两者的区别:
RDF一个重要的设计原则是数据的易发布以及共享,图数据库则把重点放在了高效的图查询和搜索上。其次,RDF以三元组的方式来存储数据而且不包含属性信息,但图数据库一般以属性图为基本的表示形式,所以实体和关系可以包含属性,这就意味着更容易表达现实的业务场景。

图数据库的比较:

Neo4j系统目前仍是使用率最高的图数据库,它拥有活跃的社区,而且系统本身的查询效率高,但唯一的不足就是不支持准分布式。相反,OrientDB和JanusGraph(原Titan)支持分布式,但这些系统相对较新,社区不如Neo4j活跃,这也就意味着使用过程当中不可避免地会遇到一些棘手的问题。如果选择使用RDF的存储系统,Jena或许一个比较不错的选择。

3.Neo4J环境配置

3.1下载

首先在 Neo4J官网 下载 Neo4J
Neo4J分为社区版和企业版:
企业版:收费,在横向扩展、权限控制、运行性能、HA等方面都比社区版好,适合正式的生产环境;
社区版:免费,普通的学习和开发采用免费社区版就好。

3.2Neo4J 安装

在Mac或者Linux中,安装好jdk后,直接解压下载好的Neo4J包,运行命令:

bin/neo4j start

windows系统下载好neo4j和jdk 1.8.0后,输入以下命令启动后neo4j:

neo4j.bat console(要设置好环境变量)

浏览器,输入http://127.0.0.1:7474/browser/就可以打开neo4j的使用界面。默认用户名密码neo4j,可以修改成自己的。

3.3 Cypher查询语言

Cypher:是Neo4J的声明式图形查询语言,允许用户不必编写图形结构的遍历代码,就可以对图形数据进行高效的查询。类似SQL,适合于开发者以及在数据库上做点对点模式(ad-hoc)查询的专业操作人员。
其具备的能力包括:
创建、更新、删除节点和关系
通过模式匹配来查询和修改节点和关系 - 管理索引和约束等
具体使用参考http://neo4j.com.cn/topic/5818519dcdf6c5bf145675c7

4.neo4j案例实战

案例来源于https://zhuanlan.zhihu.com/p/88745411
这个案例的节点主要包括人物和城市两类,人物和人物之间有朋友、夫妻等关系,人物和城市之间有出生地的关系。

4.1. 清空数据库文件


    MATCH (n) DETACH DELETE n
    MATCH是匹配操作,小括号()代表一个节点node(可理解为括号类似一个节点),括号里面的n为标识符。

    4.2创建节点

    1.创建人物节点
    CREATE (n:Person {name:'John'}) RETURN n
    CREATE是创建操作,Person是标签,代表节点的类型。花括号{}代表节点的属性,属性类似Python的字典。这条语句的含义就是创建一个标签为Person的节点,该节点具有一个name属性,属性值是John。
    创建完成后效果如下:

    2.创建更多的人物节点,并分别命名:
      CREATE (n:Person {name:'Sally'}) RETURN n
      CREATE (n:Person {name:'Steve'}) RETURN n
      CREATE (n:Person {name:'Mike'}) RETURN n
      CREATE (n:Person {name:'Liz'}) RETURN n
      CREATE (n:Person {name:'Shawn'}) RETURN n
      多条命令同时执行,中间用;分隔

      现在有6个节点了

      3.创建地区节点
        CREATE (n:Location {city:'Miami', state:'FL'})
        CREATE (n:Location {city:'Boston', state:'MA'})
        CREATE (n:Location {city:'Lynn', state:'MA'})
        CREATE (n:Location {city:'Portland', state:'ME'})
        CREATE (n:Location {city:'San Francisco', state:'CA'})


        4.3创建关系

        1.创建关系
        MATCH (a:Person {name:'Liz'}), (b:Person {name:'Mike'}) MERGE (a)-[:FRIENDS]->(b)
        方括号[]即为关系,FRIENDS为关系的类型。注意这里的箭头-->是有方向的,表示是从a到b的关系

        2.关系增加属性

        MATCH (a:Person {name:'Shawn'}),(b:Person {name:'Sally'})

        MERGE (a)-[:FRIENDS {since:2001}]->(b)

        在关系中,同样的使用花括号{}来增加关系的属性,也是类似Python的字典,这里给FRIENDS关系增加了since属性,属性值为2001,表示他们建立朋友关系的时间。

        下面增加更多关系

          MATCH (a:Person {name:'Shawn'}), (b:Person {name:'John'}) MERGE (a)-[:FRIENDS {since:2012}]->(b)
          MATCH (a:Person {name:'Mike'}), (b:Person {name:'Shawn'}) MERGE (a)-[:FRIENDS {since:2006}]->(b)
          MATCH (a:Person {name:'Sally'}), (b:Person {name:'Steve'}) MERGE (a)-[:FRIENDS {since:2006}]->(b)
          MATCH (a:Person {name:'Liz'}), (b:Person {name:'John'}) MERGE (a)-[:MARRIED {since:1998}]->(b)
          人物之间的关系构建完成

          3. 建立不同类型节点之间的关系-人物和地点的关系
          MATCH (a:Person {name:'John'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1978}]->(b)
          关系是BORN_IN,表示出生地,同样有一个属性,表示出生年份
          建立更多的关系
            MATCH (a:Person {name:'Liz'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1981}]->(b)
            MATCH (a:Person {name:'Mike'}), (b:Location {city:'San Francisco'}) MERGE (a)-[:BORN_IN {year:1960}]->(b)
            MATCH (a:Person {name:'Shawn'}), (b:Location {city:'Miami'}) MERGE (a)-[:BORN_IN {year:1960}]->(b)
            MATCH (a:Person {name:'Steve'}), (b:Location {city:'Lynn'}) MERGE (a)-[:BORN_IN {year:1970}]->(b)

            4.4.查询

            图数据库已建好,可以开始查询了
            a.查询所有在Boston出生的人物
            MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Boston'}) RETURN a,b
            b.查询所有对外有关系的节点
            MATCH (a)--() RETURN a
            c.查询所有对外有关系的节点,以及关系类型
            MATCH (a)-[r]->() RETURN a.name, type(r)
            d. 查询所有有结婚关系的节点
            MATCH (n)-[:MARRIED]-() RETURN n

            e.创建节点的时候就建好关系
            CREATE (a:Person {name:'Todd'})-[r:FRIENDS]->(b:Person {name:'Carlos'})

            4.5. 增/删/改

            a.增加/修改节点的属性
              MATCH (a:Person {name:'Liz'}) SET a.age=34
              MATCH (a:Person {name:'Shawn'}) SET a.age=32
              MATCH (a:Person {name:'John'}) SET a.age=44
              MATCH (a:Person {name:'Mike'}) SET a.age=25
              SET表示修改操作
              设置完就可以看到Mike这个人的属性了

              b.删除节点的属性

              删除属性操作主要通过REMOVE
                MATCH (a:Person {name:'Mike'}) SET a.test='test'
                MATCH (a:Person {name:'Mike'}) REMOVE a.test

                c.删除节点

                删除节点操作是DELETE
                  MATCH (a:Location {city:'Portland'}) DELETE a

                  d.删除有关系的节点
                    MATCH (a:Person {name:'Todd'})-[rel]-(b:Person) DELETE a,b,rel
                    5.通过 Python 操作 Neo4j

                    5.1利用neo4j模块:执行CQL ( cypher ) 语句

                    安装neo4j模块(pip install neo4j)



                      # step 1:导入 Neo4j 驱动包
                      from neo4j import GraphDatabase  
                      # step 2:连接 Neo4j 图数据库driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "password"))  # 添加 关系 函数def add_friend(tx, name, friend_name):    tx.run("MERGE (a:Person {name: $name}) "            "MERGE (a)-[:KNOWS]->(friend:Person {name: $friend_name})", name=name, friend_name=friend_name)
                      # 定义 关系函数
                      def print_friends(tx, name):
                      for record in tx.run("MATCH (a:Person)-[:KNOWS]->(friend) WHERE a.name = $name "
                      "RETURN friend.name ORDER BY friend.name", name=name):
                      print(record["friend.name"])
                      # step 3:运行
                      with driver.session() as session:
                      session.write_transaction(add_friend, "Arthur", "Guinevere")
                      session.write_transaction(add_friend, "Arthur", "Lancelot")
                      session.write_transaction(add_friend, "Arthur", "Merlin")
                      session.read_transaction(print_friends, "Arthur")



                      5.2利用py2neo模块

                      安装py2neo模块

                      优点,模块符合python的习惯,可以完全不会CQL也能写。

                      基本用法参考:https://zhuanlan.zhihu.com/p/81175725

                        # step 1:导包
                        from py2neo import Graph, Node, Relationship
                        # step 2:构建图
                        g = Graph("http://localhost:7474",auth=("neo4j","password"))
                        # step 3:创建节点
                        tx = g.begin()
                        a = Node("Person", name="Alice")
                        tx.create(a)
                        b = Node("Person", name="Bob")
                        # step 4:创建边
                        ab = Relationship(a, "KNOWS", b)
                        # step 5:运行
                        tx.create(ab)
                        tx.commit()


                        6.批量导入图数据

                        单个创建节点,不适合大批量导入。可以使用批量数据导入的方法。   导入方法可参考:https://zhuanlan.zhihu.com/p/93746655

                        这里介绍下neo4j-admin import命令导入导出
                        语法
                        neo4j-admin import[--mode=csv][--database=]
                        [--additional-config=]
                        [--report-file=]
                        [--nodes[:Label1:Label2]=<"file1,file2,...">]
                        [--relationships[:RELATIONSHIP_TYPE]=<"file1,file2,...">]
                        [--id-type=]
                        [--input-encoding=]
                        [--ignore-extra-columns[=]]
                        [--ignore-duplicate-nodes[=]]
                        [--ignore-missing-nodes[=]]
                        [--multiline-fields[=]]
                        [--delimiter=]
                        [--array-delimiter=]
                        [--quote=]
                        [--max-memory=</max-memory-that-importer-can-use></max-memory-that-importer-can-use></max-memory-that-importer-can-use></max-memory-that-importer-can-use></max-memory-that-importer-can-use></max-memory-that-importer-can-use></max-memory-that-importer-can-use></max-memory-that-importer-can-use>]</max-memory-that-importer-can-use>
                        [--f=]
                        [--high-io=]
                        其中:
                        --ignore-extra-columns=true 忽略多余列参数
                        --ignore-missing-nodes=true 忽略失去节点参数
                        --ignore-duplicate-nodes=true 忽略重复节点参数



                        在对Neo4j数据进行备份、还原、迁移的操作时,首先要关闭neo4j;
                        cd %NEO4J_HOME%/bin
                        ./neo4j stop
                        数据备份到文件,graph.db要和我们自己的数据库名对应起来
                        ./neo4j-admin  dump --database=graph.db --to=try.dump
                        之后,进行数据还原,将生成的存储文件拷贝到另一个相同版本的环境中
                        (测试中可以进行清空Neo4j库操作:match (n) detach delete n )
                        还原、迁移之前 ,关闭neo4j服务。操作同上;
                        数据导入:
                        ./neo4j-admin load --from=try.dump --database=neo4j –force
                        或者./neo4j-admin import --from=try.dump --database=neo4j –force

                        重启服务:
                        ./neo4j start(window下: neo4j.bat console)
                        好哒,数据都回来了!
                        使用neo4j-admin import命令导入,适合部署在docker环境下的neo4j。通过neo4j-admin方式导入,需要暂停服务,并且需要清除graph.db,这样才能导入进去数据。而且,只能在初始化数据时,导入一次之后,就不能再次导入。


                        文章转载自网安杂谈,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

                        评论