知识图谱小鲸鱼队之 Task 1 知识图谱介绍
知识图谱
“知识图谱本质上是语义网络(Semantic Network)的知识库”。但这有点抽象,换个角度,从实际应用的角度出发其实可以简单地把知识图谱理解成多关系图(Multi-relational Graph)。从语言中提取关键信息,省略不必要的词,将关键信息及其联系进行可视化(多关系图),形成图谱,从而获取相关知识。
多关系图
多关系图是一种图,图在数据结构中的定义是由节点(Vertex)和边(Edge)来构成,但这些图通常只包含一种类型的节点和边。而多关系图一般包含多种类型的节点和多种类型的边。
实体
在知识图谱中,我们通常用“实体(Entity)”来表达图里的节点、用“关系(Relation)”来表达图里的“边”。
知识图谱的价值
知识图谱是人工智能很重要的一个分支, 人工智能的目标为了让机器具备像人一样理性思考及做事的能力 -> 在符号主义的引领下,知识工程(核心内容即建设专家系统)取得了突破性的进展 -> 在整个知识工程的分支下,知识表示是一个非常重要的任务 -> 而知识图谱又恰恰是知识表示的重要一环。
搜索领域的Google搜索、百度搜索,社交领域的领英经济图谱,企业信息领域的天眼查企业图谱等都涉及知识图谱。
交叉研究包含有:自然语言处理与语义web、数据挖掘、机器学习、知识表示与推理、认知计算、信息检索与抽取。
怎么构建知识图谱呢?
知识图谱的构建过程分为四个功能模块:分别是数据获取、信息获取、知识融合和知识处理。
数据获取
数据源主要来自两种渠道:
第一种:业务本身的数据。这部分数据通常包含在公司内的数据库表并以结构化的方式存储,一般只需要简单预处理即可以作为后续AI系统的输入;
第二种:网络上公开、抓取的数据。这些数据通常是以网页的形式存在所以是非结构化的数据,一般需要借助于自然语言处理等技术来提取出结构化信息。
信息获取
信息获取分为三个关键技术:实体提取、关系提取和属性提取。这也是多关系图的性质及知识图谱的一个非常重要的概念Schema所要求的。
知识融合
知识融合就是把“信息获取”过程中得到的散乱信息整合起来。它分为两个部分,实体链接和知识合并。
知识处理
知识处理主要包括三个关键技术:本体构建、知识推理和质量评估。
知识图谱的具体构建技术
实体关系识别技术(Named Entity Recognition)
从文本里提取出实体并对每个实体做分类/打标签
关系抽取技术(Relation Extraction)
将实体间的关系从文本中提取出来
实体统一(Entity Resolution)
对于有些实体写法上不一样,但其实是指向同一个实体。其不仅可以减少实体的种类,也可以降低图谱的稀疏性(Sparsity)。
指代消解(Disambiguation)
文本中出现的“it”, “he”, “she”这些词到底指向哪个实体
知识图谱的存储
知识图谱主要有两种存储方式:
- 一种是基于RDF的存储;
- 另一种是基于图数据库的存储。
区别:
RDF | 图数据库 |
---|---|
数据的易发布以及共享 | 高效的图查询和搜索 |
三元组的方式来存储数据 | 以属性图为基本的表示形式 |
不包含属性信息 | 包含属性,更容易表达现实的业务场景 |
标准的推理引擎 | 没有标准的推理引擎 |
其中Neo4j系统目前仍是使用率最高的图数据库,它拥有活跃的社区,而且系统本身的查询效率高,但唯一的不足就是不支持准分布式。相反,OrientDB和JanusGraph(原Titan)支持分布式,但这些系统相对较新,社区不如Neo4j活跃,这也就意味着使用过程当中不可避免地会遇到一些刺手的问题。如果选择使用RDF的存储系统,Jena或许一个比较不错的选择。
Neo4j
Neo4j采用的是Cypher图形查询语言,允许用户不必编写图形结构的遍历代码,就可以对图形数据进行高效的查询。
设计目的:类似SQL,适合于开发者以及在数据库上做点对点模式(ad-hoc)查询的专业操作人员。
其具备的能力包括:
创建、更新、删除节点和关系
通过模式匹配来查询和修改节点和关系 - 管理索引和约束等
Neo4j实战
1. 创建节点
- 删除数据库中以往的图,确保一个空白的环境进行操作【注:慎用,如果库内有重要信息的话】:
MATCH (n) DETACH DELETE n';
- 创建一个人物节点:
CREATE (n:Person {name:'John'}) RETURN n
CREATE是创建操作,Person是标签,代表节点的类型。
花括号{}代表节点的属性,属性类似Python的字典。
这条语句的含义就是创建一个标签为Person的节点,该节点具有一个name属性,属性值是John。
创建完一个人物实体后,会出现结果,点击左边一列的Graph即可看到创建的任务实体John:
- 创建更多的人物节点,并分别命名:
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;
创建成功后,这时候发现看不到上面的图了,这时候可以查看网页左边的Database Information中的Node Labels,点击Person旁边的即可出现类似创建一个任务后的结果。
接着点击Graph出现创建的6个人物实体:
- 创建地区节点
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'})
再次查看Database Information中的Node Labels,发现新增了Location属性。
感兴趣的同学也可以试试点击Node Labels下三个不同的东西,看看有什么结果,我就不剧透咯~
得到的图如下:
2. 创建关系
- 朋友关系
MATCH (a:Person {name:'Liz'}),
(b:Person {name:'Mike'})
MERGE (a)-[:FRIENDS]->(b)
方括号[]即为关系,FRIENDS为关系的类型。
注意这里的箭头–>是有方向的,表示是从a到b的关系。 这样,Liz和Mike之间建立了FRIENDS关系
- 关系增加属性
MATCH (a:Person {name:'Shawn'}),
(b:Person {name:'Sally'})
MERGE (a)-[:FRIENDS {since:2001}]->(b)
- 增加更多的朋友关系
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)
于是点击左边栏中的Relationship Types下的东西得到:
3. 创建出生地点
建立不同类型节点之间的关系-人物和地点的关系
MATCH (a:Person {name:'John'}), (b:Location {city:'Boston'}) MERGE (a)-[:BORN_IN {year:1978}]->(b);
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)
创建节点的时候就建好关系
CREATE (a:Person {name:'Todd'})-[r:FRIENDS]->(b:Person {name:'Carlos'})
最终形成图谱:
4. 图数据库查询
- 查询下所有在Boston出生的人物
MATCH (a:Person)-[:BORN_IN]->(b:Location {city:'Boston'}) RETURN a,b
2. 查询所有对外有关系的节点
MATCH (a)--() RETURN a
3. 查询所有有关系的节点,以及关系类型(type®)
MATCH (a)-[r]->() RETURN a.name, type(r)
这里不清楚为什么,出不了图
- 查询所有有结婚关系的节点
MATCH (n)-[:MARRIED]-() RETURN n
5. 查找某人的朋友的朋友
MATCH (a:Person {name:'Mike'})-[r1:FRIENDS]-()-[r2:FRIENDS]-(friend_of_a_friend) RETURN friend_of_a_friend.name AS fofName
通过 Python 操作 Neo4j
neo4j模块:执行CQL ( cypher ) 语句
# 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")
输出结果:
py2neo模块:通过操作python变量,达到操作neo4j的目的
# step 1:导包
from py2neo import Graph, Node, Relationship
# step 2:构建图
g = Graph()
# 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()
在执行代码的时候遇到了一点小问题创建Graph不成功,于是找到以下解决办法:
g = Graph(“bolt://localhost:7687”, user=“neo4j”, password=“password”)
输出结果: