neo4j导入知识图谱初体验

前言

好久没更新过了- -最近被人工智能压垮了…研究了rnn、lstm、bert、word2vec…虽然一个都没看懂但是颇有心得,但是今天都不说这些,记录下neo4j怎么导入csv格式的数据

环境

  1. python 3.6
  2. neo4j

数据准备

用的是ownthink开源的1.4亿中文知识图谱,堪称目前最强了吧。可以关注他的公众号下载数据集,下载下来是个巨大的csv文件,还需要对这个文件进行处理。

这个文件太大了,所以得分块处理,目标是拆成两个文件,一个entity.csv放的是实体,一个rel.csv放的是实体间的关系

entity.csv的结构

:ID name :LABEL
实体id(不可重复) 实体名 实体标签

rel.csv的结构

:START_ID name :END_ID :TYPE
实体ID 关系名 实体ID 类型

直接放代码吧= =

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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import pandas as pd
import time

# 记录开始时间
start = time.time()

# 常量定义
ENTITY_LABEL = 'ENTITY'
ENTITY_LABEL_1 = 'ENTITY1'
TYPE = 'RELATIONSHIP'

# 读取文件
file = pd.read_csv('e:/ownthink_v2.csv', iterator=True, chunksize=1000000, encoding="utf_8")
# 定义转存结构
entity_map = {":ID": [], "name": [], ':LABEL': []}
rel_map = {":START_ID": [], "name": [], ':END_ID': [], ":TYPE": []}
# 记录当前实体
current_entity_name = ''
current_entity_id = ''
# 循环计次
j = 1
i = 1

# 循环
print('开始第{}次写入'.format(j))
for chunk in file:
for _, row in chunk.iterrows():
if current_entity_name != row['实体']:
current_entity_name = str(row['实体']).replace('\r', '').replace('\n', '')
current_entity_id = 'entity' + str(i) + 'e'
entity_map[':ID'].append(current_entity_id)
entity_map['name'].append(current_entity_name)
entity_map[':LABEL'].append(ENTITY_LABEL)
entity_map[':ID'].append('entity' + str(i))
entity_map['name'].append(str(row['值']).replace('\r', '').replace('\n', ''))
entity_map[':LABEL'].append(ENTITY_LABEL_1)
rel_map[':START_ID'].append(current_entity_id)
rel_map['name'].append(str(row['属性']).replace('\r', '').replace('\n', ''))
rel_map[':END_ID'].append('entity' + str(i))
rel_map[':TYPE'].append(TYPE)
if i % 1000000 == 0:
if j == 1:
pd.DataFrame(entity_map, columns=[":ID", "name", ':LABEL']) \
.to_csv('e:/tp/entity/entity{}.csv'.format(j), encoding="utf_8_sig", index=False)
pd.DataFrame(rel_map, columns=[":START_ID", "name", ':END_ID', ":TYPE"]) \
.to_csv('e:/tp/rel/rel{}.csv'.format(j), encoding="utf_8_sig", index=False)
else:
pd.DataFrame(entity_map, columns=[":ID", "name", ':LABEL']) \
.to_csv('e:/tp/entity/entity{}.csv'.format(j), encoding="utf_8_sig", index=False, header=False)
pd.DataFrame(rel_map, columns=[":START_ID", "name", ':END_ID', ":TYPE"]) \
.to_csv('e:/tp/rel/rel{}.csv'.format(j), encoding="utf_8_sig", index=False, header=False)
entity_map = {":ID": [], "name": [], ':LABEL': []}
rel_map = {":START_ID": [], "name": [], ':END_ID': [], ":TYPE": []}
j += 1
print('开始第{}次写入'.format(j))
i += 1

pd.DataFrame(entity_map, columns=[":ID", "name", ':LABEL']) \
.to_csv('e:/tp/entity/entity{}.csv'.format(j+1), encoding="utf_8_sig", index=False)
pd.DataFrame(rel_map, columns=[":START_ID", "name", ':END_ID', ":TYPE"]) \
.to_csv('e:/tp/entity/rel{}.csv'.format(j+1), encoding="utf_8_sig", index=False)
print('运行时间{}'.format(time.time() - start))

把拆出来的文件合并

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import glob


from itertools import islice
inputfile_dir = ''
outputfile = 'e:/tp/rel.csv'

path =r'e:/tp/rel' # use your path
csv_list = glob.glob(path+'/*.csv')
print(u'共发现%s个CSV文件'% len(csv_list))
print(u'正在处理............')
for i in csv_list: #循环读取同文件夹下的csv文件
fr = open(i,'rb').read()
with open(outputfile,'ab') as f: #将结果保存为result.csv
f.write(fr)

print(u'合并完毕!')

ok这样我们就得到两个csv了

数据导入

导入的数据比较大,所以用的是neo4j-import

  1. 关闭neo4j

    1
    neo4j stop
  2. 把处理完的两个csv放到neo4j安装目录下的import文件夹内

  3. 在neo4j安装目录下的bin文件夹内执行命令

    1
    2
    3
    4
    5
    6
    7
    8
    neo4j-admin import  
    --mode csv
    --database common.db    
    --nodes:entity ../import/entity.csv
    --relationships ../import/rel.csv
    --ignore-extra-columns=true  
    --ignore-missing-nodes=true
    --ignore-duplicate-nodes=true

    注意在data/databases目录下不能存在common.db

  4. 把common.db的名字改成graph.db(没办法默认就是这个,初学者还不知道怎么改…什么?问我为什么不直接指定成graph.db?我开心!)

  5. 打开neo4j控制台localhost:7474,点左边的小星星,点Basic Queries,点get some data 就能看到数据了

后记

知识图谱只是聊天机器人的一部分,怎么让ai能够看懂用户输入的话来找知识才是难。。。下篇更新拜拜