图数据库

传统数据库难以处理复杂多跳的关系运算。需要一种支持海量、复杂、且结构灵活的关系运算数据库,图数据库应运而生。

1 相关概念

1.1 简介

图数据库由顶点和边组成;

主要用于对图数据的增删改查;

目前常用的图数据库有 Neo4j,JanuxGraph 等

1.2 使用场景

  • 常用于社交、电商、金融、零售、物联网等行业
  • 用于关系查询
  • 用于遍历复杂关系
  • 用于实现复杂的规则:如子图比较、推荐等
  • 对于结构化数据,常可使用关系型数据库;对于关系比较多,数据不太规律的情况,则用图数据库

1.3 分类

  • 属性图数据库
    • 构成:顶点、边、顶点属性、边属性
  • RDF 图数据库(不支持属性,比较古老,已经不怎么用了)
    • 针对文本语义场景产生
    • 三元组:subject->predicate->object

1.4 原生图数据库

  • 原生图数据库:使用图模型进行数据存储,可以针对图数据做优化,从而带来更好的性能,例如 Neo4j。
  • 非原生图数据库:底层存储使用非图模型,在存储之上封装图的语义,适合与其它数据应用配合使用,例如 Titan、JanusGraph 底层 采用 KV 存储非图模型。

1.5 技术栈

  • 技术架构
    • 接口层、计算层(图算法)、存储层
  • 主流查询语言
    • Cypher(CQL,类 SQL),Neo4j 使用这种查询
    • Gremlin(类 Scala)
    • SPARQL(用于 RDF 框架),适用于语义场景
  • 图数据的计算
    • 图遍历(局部查询:深度优先、广度优先)
    • 路径发现(两点间最短路径)
  • 图处理引擎
    • 用于分析复杂图
    • 常用引擎:GraphX,GraphLab, Giraph

1.6 基本概念

包括以下四种概念:

  • 标签:节点所属类别,一个节点可以有一个以上的标签
  • 节点:实体对象
  • 关系:实体间的关系
  • 属性:节点和关系都可以拥有属性,以 key:value 方式描述

2 Neo4j

Neo4j 是一个常用的图数据库。

2.1 安装

1
2
$ docker search neo4j # 查看所有Neo4j相关镜像
$ docker pull neo4j # 下载最新版本

最新版本约 500 多 M

2.2 运行

1
2
$ sudo adduser neo4j
$ docker run -d --name neo4j -p 7474:7474 -p 7687:7687 -v /home/neo4j/data:/data -v /home/neo4j/logs:/logs -v /home/neo4j/conf:/var/lib/neo4j/conf -v /home/neo4j/import:/var/lib/neo4j/import --env NEO4J_AUTH=neo4j/password neo4j

浏览器打开

http://localhost:7474

输入用户名:neo4j,密码:password(启动 docker 时通过 NEO4J_AUTH 设置)

语法非常简单,点击按钮,即可在左侧栏查看帮助,左侧栏和 VSCode,Obsidian 用法相似。

image.png

2.3 使用 CQL 处理数据

点击左侧的”星“图标,可查看示例代码,试建立两个节点一个关系:

1
CREATE (database:Database {name:"Neo4j"})-[r:SAYS]->(message:Message {name:"Hello World!"}) RETURN database, message, r

建立结构后可以通过左侧的 Database Infomation 查看数据情况。

2.4 使用 Python 访问图数据库

2.4.1 安装

1
$ pip install py2neo

2.4.2 构建图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# coding:utf-8
from py2neo import Graph, Node, Relationship

# 连接neo4j数据库,输入地址、用户名、密码
graph = Graph("http://192.168.1.106:7474", name="neo4j")
graph.delete_all()
# 创建结点
test_node_1 = Node('ru_yi_zhuan', name='皇帝') # 修改的部分
test_node_2 = Node('ru_yi_zhuan', name='皇后') # 修改的部分
test_node_3 = Node('ru_yi_zhuan', name='公主') # 修改的部分

graph.create(test_node_1)
graph.create(test_node_2)
graph.create(test_node_3)

# 创建关系
# 分别建立了test_node_1指向test_node_2和test_node_2指向test_node_1两条关系,关系的类型为"丈夫、妻子",两条关系都有属性count,且值为1。
node_1_zhangfu_node_1 = Relationship(test_node_1, '丈夫', test_node_2)
node_1_zhangfu_node_1['count'] = 1
node_2_qizi_node_1 = Relationship(test_node_2, '妻子', test_node_1)
node_2_munv_node_1 = Relationship(test_node_2, '母女', test_node_3)

node_2_qizi_node_1['count'] = 1

graph.create(node_1_zhangfu_node_1)
graph.create(node_2_qizi_node_1)
graph.create(node_2_munv_node_1)

print(graph)
print(test_node_1)
print(test_node_2)
print(node_1_zhangfu_node_1)
print(node_2_qizi_node_1)
print(node_2_munv_node_1)

此时,即可以界面中看到新建的数据:

2.4.3 查询图

查询节点
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
from py2neo import Graph, NodeMatcher

graph = Graph("http://192.168.1.106:7474", name="neo4j")

# 列出所有节点类型
print(graph.schema.node_labels)

# 列出所有关系类型
print(graph.schema.relationship_types)

nodematcher= NodeMatcher(graph)
# 方法一
items = nodematcher.match('ru_yi_zhuan', name='公主')
# 方法二(模糊匹配,结果同方法一)
items = nodematcher.match('ru_yi_zhuan').where("_.name =~ '.*公.*'")

for item in items:
for key in item.keys():
print(key, item[key]) # 直接打印可能出现中文乱码

使用 where 方法支持更多模糊和条件匹配

查询关系

至少有两个参数:节点,关系

1
2
3
4
5
6
7
from py2neo import RelationshipMatcher

# 接上例
rmatcher = RelationshipMatcher(graph)
items = rmatcher.match({item}, None)
for item in items:
print(item)
直接使用查询语句

搜索示例

1
2
3
4
cypher_ = "MATCH (n:ru_yi_zhuan)-[r]->(m:ru_yi_zhuan) \
WHERE m.name='公主' \
RETURN type(r) AS type,m.name AS name"
print(graph.run(cypher_).to_data_frame())

模糊搜索示例

1
cypher_ = "MATCH (n:`ICD9_条目`) where n.name =~ '.*髋.*' RETURN n LIMIT 25"

3 参考

docker安装部署neo4j

Neo4j基本入门

python操作neo4j