知识图谱——Python操作Neo4j导入CSV文件建立图谱

Posted 学习学习~~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识图谱——Python操作Neo4j导入CSV文件建立图谱相关的知识,希望对你有一定的参考价值。

首先Neo4j是图数据库,最重要的就是结点和边的关系,每两个结点和边都可以看成三元组,主谓宾的关系,当然结点也是可以添加属性的,但是首先要有结点,在添加属性。本片文章就是用简单的方式一次性给大家讲解清楚。

简单起见,我们用西游记师徒四人为例子(手动写的,为了理解),来体现出本章要讲的操作

一、先把人物和关系罗列出来

注意,要将文件保存为.csv格式

 ps:知识图谱的建立,数据来源主要分为三种,一种是非结构化数据(文本)、半结构化数据(可以爬虫技术在一些网站上获取),结构化数据(关系型数据)。

二、要建立结点,只有有了结点才会有关系,和之后的属性等。代码如下:

from py2neo import Graph, Node, Relationship
import csv

fr= open("G:\\四人关系.csv", mode="r", encoding="gbk") # 如果路径是在工程目录下直接下相对路径,如果不在就写绝对路径
lst = []
node = []
for row in csv.reader(fr):
    lst_ = []
    lst_.append(row[0])
    lst_.append(row[1])
    lst_.append(row[2])
    lst_.append(row[3])
    lst_.append(row[4])
    lst.append(lst_)
    node.append(row[0]+' '+row[1])
    node.append(row[3]+' '+row[4])
# print(lst)
graph = Graph('bolt://localhost:7687',name="neo4j",password="******")
node = set(node) # 消除重复结点
#  建立结点:
for item in node:
    shiti,label = item.split()
    cypher_ = "CREATE (:" + label + " name:'" + shiti + "')     "
    graph.run(cypher_)
# 建立关系 :
for item in lst:
    cypher_ = "MATCH  (a:" + item[1] + "),(b:" + item[4] + ") WHERE a.name = '" + item[0] + "' AND b.name = '" + item[3] + "' CREATE (a)-[r:" + item[2] + "]->(b)"
    graph.run(cypher_)

建立是先根据第1,2列、4,5列建立结点后,才根据第3列建立的关系,运行后,师徒四人的图谱就建立好了,效果如下图:

 三、增加属性

和以上操作一样,现在EXCEL上写好属性,如图(只写了一点),自己做的时候把自己要的属性像这样写清楚:

代码和上面的一样,只是换了cypher语句:

from py2neo import Graph, Node, Relationship
import csv

fr= open("属性.csv", mode="r", encoding="gbk")
lst = []
node = []
for row in csv.reader(fr):
    lst_ = []
    lst_.append(row[0])
    lst_.append(row[1])
    lst_.append(row[2])
    lst_.append(row[3])
    lst.append(lst_)
    node.append(row[0]+' '+row[1])
    node.append(row[2]+' '+row[3])
graph = Graph('bolt://localhost:7687',name="neo4j",password="******")
for item in lst:
    cypher_ = "MATCH (a:" + item[1] + "name:'" + item[0] + "') SET a." + item[2] + " = '" + item[3] +"'"
    graph.run(cypher_)

运行之后,点击结点就可以看到属性的信息啦。

知识图谱构建《射雕三部曲》图谱(CSV文件导入)

下载 CSV 文件

打开 Xfce 终端,进入 /var/lib/neo4j/import 目录,下载本节实验所需要的 CSV 文件

cd /var/lib/neo4j/import
wget https://labfile.oss.aliyuncs.com/courses/1354/data.zip
unzip data.zip

在这里插入图片描述
将 csv文件下载解压到 import中。

一共有三个 CSV 文件,在本节实验中,我们用 LOAD CSV 方法导入 射雕三部曲.csv 文件,用 Neo4j-admin import 方法导入 nodes.csvrelationships.csv 文件。

LOAD CSV 构建

load csv 文件

LOAD CSVCypher 提供的 ETL(Extract-Transform-Load) 工具, 允许从本地或者互联网上导入 CSV 文件。 导入本地文件时,Neo4j 默认的设置是把文件导入的根目录限制在当前库的 import 文件夹下。

射雕三部曲.csv 文件结构如下
在这里插入图片描述

一个单元格中可能为,或者一个实体,或者多个实体。多个实体之间用中文逗号隔开。

同时,sudo neo4j stop 停止 Neo4j 服务,在 /etc/neo4j/neo4j.conf 文件里,最下面增加一行

cypher.lenient_create_relationship=true

这一句命令的目的是在构建关系时遇到 null-[]-() 一类的情况时可以自动跳过而不报错,在下面的实验中会用到。
在这里插入图片描述
启动 Neo4j 服务,登录 Neo4j 客户端,在命令行中导入 CSV文件

load csv from 'file:///射雕三部曲.csv' as line return line

在这里插入图片描述
可以看到 load csv 命令返回了一个按行组成的列表,取列表中的元素通过如 line[0] 这样的取下标操作。

同时 load csv 接收可变参数 WITH HEADERS, 从文件中读取第一行作为参数名,在使用了该参数后返回一个 key-value 的数据结构。

load csv with headers from 'file:///射雕三部曲.csv' as line  return line

在这里插入图片描述
这样就可以用如 line.人物 这样的方法来取列表的元素了

构建节点

首先构建第一列的角色节点,同时第一列的人物拥有 描述 的属性,为了避免重复录入,在这里使用 merge 来创建节点。

load csv with headers from 'file:///射雕三部曲.csv' as line
merge(n:角色{name:line.人物,desc:line.描述}) return n

在这里插入图片描述
接下来创建作品节点

因为一个人可能会在多个作品中出现,因此先使用 split 将一个单元格中的多个作品拆分开来,然后用 foreach 分别创建

load csv with headers from 'file:///射雕三部曲.csv' as line
merge(n:角色{name:line.人物,desc:line.描述})
foreach (a in split(line.作品,',') | merge(n:作品{name:a}))

剩下的节点同理,除了配偶,父和母只包含单个实体,其他都先用 split 拆分再用 merge 创建

完整语句如下:

load csv with headers from 'file:///射雕三部曲.csv' as line
merge(n:角色{name:line.人物,desc:line.描述})
foreach (a in split(line.作品,',') | merge(n:作品{name:a}))
foreach (a in split(line.武功,',') | merge(n:武功{name:a}))
foreach (a in split(line.门派,',') | merge(n:门派{name:a}))
foreach (a in split(line.师傅,',') | merge(n:角色{name:a}))
foreach (a in split(line.子女,',') | merge(n:角色{name:a}))
foreach (a in line.| merge(n:角色{name:a}))
foreach (a in line.| merge(n:角色{name:a}))
foreach (a in line.配偶 | merge(n:角色{name:a}))

在这里插入图片描述

构建关系

构建关系的目标是给 CSV 中第一列的人物与后面几列的人物、作品、武功和门派之间构建关系。

load csv with headers from 'file:///射雕三部曲.csv' as line
match (book:作品),(person:角色),(skill:武功)
    where
        book.name in split(line.作品, ',') and
        person.name = line.人物 and
        skill.name in split(line.武功, ',')
merge (person)-[:所在作品]-(book)
merge (person)-[:武功]-(skill)

在创建关系的时候,要注意到 CSV 中有些单元格为空,此时使用 match 语句时用where and并排查询条件是匹配不到单元格为空的节点的,此时就需要用到 optional match ,如果有匹配到的,返回匹配到的节点,如果没有匹配到,返回 null,同时跳过 null 与角色之间的关系的建立,这部分在实验开始时已经设置好了。

如构建 角色-父 之间的关系

load csv with headers from 'file:///射雕三部曲.csv' as line
match (book:作品),(person:角色),(skill:武功)
    where
        book.name in split(line.作品, ',') and
        person.name = line.人物 and
        skill.name in split(line.武功, ',')
optional match (father:角色)
    where
        father.name = line.父
merge (person)-[:所在作品]-(book)
merge (person)-[:武功]-(skill)
merge (person)-[r:]-(father)
return (person)-[r:]-(father)

在这里插入图片描述

同理构建其他角色,同时要注意到,配偶关系是互相的,即如 小龙女杨过 的配偶,同时 杨过 也是 小龙女 的配偶,因此构建关系时这两个节点之间需要有两条异向的边,即通过箭头 ()-[]->() 来实现。

构建关系的语句如下:

load csv with headers from 'file:///射雕三部曲.csv' as line
match (book:作品),(person:角色),(skill:武功)
    where
        book.name in split(line.作品, ',') and
        person.name = line.人物 and
        skill.name in split(line.武功, ',')
optional match (father:角色)
    where
        father.name = line.父
optional match (mother:角色)
    where
        mother.name = line.母
optional match (spouse:角色)
    where
        spouse.name = line.配偶
optional match (sect:门派)
    where
        sect.name = line.门派
optional match (children:角色)
    where
        children.name in split(line.子女, ',')
optional match (master:角色)
    where
        master.name in split(line.师傅, ',')
merge (person)-[:所在作品]-(book)
merge (person)-[:师傅]-(master)
merge (person)-[:武功]-(skill)
merge (person)-[:]-(father)
merge (person)-[:]-(mother)
merge (person)-[:配偶]->(spouse)
merge (person)-[:所在门派]-(sect)
merge (person)-[:子女]-(children)

在这里插入图片描述
此时,所有的节点和关系都已经导入好了,通过下面的命令进行查看:

MATCH p=()-->() RETURN p

在这里插入图片描述

neo4j-admin import 构建

Neo4j 官方提供了 neo4j-admin import 来解决数据量非常大时导入的性能瓶颈。

参数设置如下

  • --nodes 节点所在 CSV 文件
  • --relationships 关系所在 CSV 文件

nodes 节点所在 CSV 文件格式形式如下:
在这里插入图片描述
第一列为 ID 号,在构建关系时必须用过 ID 号来对应关系,第二、三列为属性值,第四列为节点类型。

relationships 关系所在 CSV 文件格式形式如下:
在这里插入图片描述
第一列表示起始节点的 ID 号,第二列表示截至节点的 ID 号,第三列为关系类型

在使用 neo4j-admin import 时,需要先 sudo neo4j stop 停止 Neo4j 服务,同时删除旧的 graph.db 文件(通过 neo4j.conf 可以知道在 /var/lib/neo4j/data/databases 目录下)。

./neo4j-admin import --nodes=../import/nodes.csv --relationships=../import/relationships.csv

在这里插入图片描述

导入csv文件

可是使用命令行将相关节点和关系的csv文件导入,但是csv文件需要符合一定的格式。

指定csv文件格式

csv文件主要是对文件的表头有一定的格式要求,下文将分别记录节点文件关系文件的表头格式。

  1. 节点文件表头格式如下:
    :ID :LABEL
  2. 关系文件表头格式如下:
    :START_ID :END_ID :TYPE
    分别代表图关系中的起始节点ID、尾节点ID和两个ID之间的关系。

使用命令行导入csv文件

  1. 首先将节点和关系的csv文件放在neo4j根目录下的import文件夹中
  2. 切换至neo4jbin文件夹下,使用如下命令将节点和关系的csv文件导入,在导入之前必须保证所导入的数据库为空,即在导入之前将数据库删掉(数据库路径为neo4jdata/database文件夹中),导入数据时会自动创建新的数据库。
./neo4j-admin import --database=graph.db  --nodes=/neo4j-community-3.5.19-unix/import/node.csv --relationships=/neo4j-community-3.5.19-unix/rel.csv --delimiter='\\t'
  • database 代表所指定的数据库
  • nodes 代表节点文件
  • relationships 代表节点间关系文件
  • delimiter 代表节点/关系文件的分隔符

参考博客 Link

总结

在这里插入图片描述

加油!

感谢!

以上是关于知识图谱——Python操作Neo4j导入CSV文件建立图谱的主要内容,如果未能解决你的问题,请参考以下文章

知识图谱Neo4j 数据导入与数据库切换

Neo4j批量导入大量csv数据

知识图谱Neo4j基本操作及数据库文件导入(graph.db.dump)

KG构建《红楼梦》知识图谱

KG构建《红楼梦》知识图谱

KG构建《红楼梦》知识图谱