Neo4j图数据库 批量写入与查询

news2024/11/16 7:53:40

1 前言 

1-1 简介

      工作中需要对所有的实体数据进行存储构建实体知识图谱,为基于知识图谱的问答提供数据基础。选择使用Neo4j作为数据库进行存储。以下是关于Neo4j的简介。

 1-2 任务背景

        将处理好的实体数据(共计1100万)写入图数据库中,并且提供查询接口,供下游(KBQA)进行查询。由于数据量比较大,所以需要批量更新、批量删除。

1-3 任务难点

        任务难点有两个:

        (1)因为数据处理的缘故,每个实体的属性不一致。比如“芈月”这一实体,其中存在{"name": "中文名", "value": "芈月"}, {"name": "别名", "value": "月儿、月公主、太后、公主、芈夫人、芈八子、月妹妹、王妹、母后、姐姐、小霸星、小老虎"}, {"name": "饰演", "value": "孙俪(成年)、柴蔚(少年)、李景儿(童年)、刘楚恬(童年)"}, {"name": "登场作品", "value": "芈月传"}等属性。而“布巴洛”则有{"name": "中文名", "value": "布巴洛"}, {"name": "运动项目", "value": "足球"}, {"name": "所属运动队", "value": "芭提雅联足球俱乐部"}, {"name": "场上位置", "value": "前锋"}等属性。如何根据不同的属性做出个性化的Node是面临的第一个难点。经过探索,解决此问题借助了字典的方式。

        (2) 因为数据量庞大,如何将创建好的Node快速写入Neo4j中成为另一个难点。经过探索,解决此问题,采用了子图写入的方式。

1-3 数据来源

         数据来源于百度百科的词条数据,对百科词条进行处理。部分样例如下所示:

{"lemmaTitle": "芈月", "lemmaDesc": "电视剧《芈月传》女主角", "lemmaSummary": {"value": "芈月,古装电视剧《芈月传》中的女主角。由演员孙俪饰演。芈月的历史原型为秦国的宣太后,她是中国历史上第一位太后。"}, "basicInfo": [{"name": "中文名", "value": "芈月"}, {"name": "别名", "value": "月儿、月公主、太后、公主、芈夫人、芈八子、月妹妹、王妹、母后、姐姐、小霸星、小老虎"}, {"name": "饰演", "value": "孙俪(成年)、柴蔚(少年)、李景儿(童年)、刘楚恬(童年)"}, {"name": "登场作品", "value": "芈月传"}, {"name": "所处时代", "value": "战国时期楚国→秦国"}, {"name": "民族族群", "value": "华夏族"}, {"name": "出生地", "value": "荆州"}, {"name": "出生日期", "value": "不详"}, {"name": "逝世日期", "value": "前265年"}, {"name": "主要成就", "value": "在秦国长期执政、杀义渠王、灭义渠国、囚死楚怀王"}, {"name": "心腹", "value": "葵姑、香儿、惠儿、穆辛"}, {"name": "谥号", "value": "宣"}, {"name": "父亲", "value": "羋(熊)商(楚威王)"}, {"name": "母亲", "value": "向氏"}, {"name": "丈夫", "value": "嬴驷"}, {"name": "弟弟", "value": "芈戎(同父同母)、魏冉(同母异父)、白起(义弟)"}, {"name": "初恋", "value": "黄歇"}, {"name": "情人", "value": "翟骊(义渠王)"}, {"name": "儿子", "value": "嬴稷(和嬴驷所生)、嬴芾(和翟骊所生)"}, {"name": "姐姐", "value": "芈姝(已决裂)、羋茵(天生不和)"}, {"name": "哥哥", "value": "羋(熊)槐(楚怀王、同父异母)"}, {"name": "侄子", "value": "羋(熊)横(楚顷襄王)"}, {"name": "好姐妹", "value": "樊长使、卫良人、唐夫人、孟赢、魏美人"}, {"name": "养母", "value": "莒姬"}, {"name": "仇人", "value": "魏琰、虢美人、孟昭氏、魏颐、甘茂、玳瑁、珍珠、珊瑚、靳尚、赢荡、芈姝、羋茵、楚威后、冯甲、羋(熊)槐、羋菁、郑袖、赢华"}, {"name": "师傅", "value": "屈原"}, {"name": "男宠", "value": "魏丑夫"}, {"name": "玄孙", "value": "秦始皇嬴政"}, {"name": "身份", "value": "楚国公主→芈八子→燕国质子→秦国太后(宣太后)"}, {"name": "好友", "value": "张仪、庸睿、樗里疾"}, {"name": "入秦宫身份", "value": "八子"}, {"name": "字号", "value": "宣"}, {"name": "朝代", "value": "战国时期"}, {"name": "国籍", "value": "楚国→秦国"}, {"name": "本名", "value": "芈月"}, {"name": "饰演者", "value": "孙俪"}, {"name": "性别", "value": "女"}], "order": 0, "category": "人物,虚拟人物,影视人物,文学角色,历史人物", "tags": "文化;出版物", "synonyms_lemmaTitle": ["芈月 电视剧《芈月传》女主角", "宣太后", "芈月"], "synonyms": "芈月\t电视剧《芈月传》女主角,宣太后,芈月"}
{"lemmaTitle": "布巴洛", "lemmaDesc": "塞尔维亚足球运动员", "lemmaSummary": {"value": "布巴洛是塞尔维亚足球运动员。"}, "basicInfo": [{"name": "中文名", "value": "布巴洛"}, {"name": "运动项目", "value": "足球"}, {"name": "所属运动队", "value": "芭提雅联足球俱乐部"}, {"name": "场上位置", "value": "前锋"}], "order": 0, "category": "人物", "tags": "人物", "synonyms_lemmaTitle": "布巴洛", "synonyms": "布巴洛"}

 

2  任务实现

2-1 安装Neo4j

安装版本为Community-4.4.8,进入到安装包目录下执行命令:

tar -xf neo4j-community-4.4.8-unix.tar.gz

安装完成后会生成如下目录:

conf目录下存放配置文件,可以根据自己服务器配置进行修改。

 启动:

 进入bin目录执行./neo4j start

2-2 引入必要的库

import jsonlines
from tqdm import tqdm
import jsonlines
import pandas as pd

2-3 连接图数据库

2-3-1 连接图数据库

        使用py2neo作为连接工具,完成对Neo4j的操作。引入必要的库函数,首先根据网址、用户名和密码建立连接。之后可以借助NodeMatcher方法生成查询。

#连接数据库
from py2neo import Graph, Node, Relationship,Subgraph,NodeMatcher
graph = Graph(
        'http://xx.xx.xx.xxx:7474/browser/',
        auth=('neo4j', 'Neo4j'))
#创建查询
node_matcher = NodeMatcher(graph)
#数据库清空
#graph.delete_all() #DatabaseError: [Statement.ExecutionFailed] Java heap space

2-4 写入节点

 2-4-1 创建Node

        针对每条实体,将其中的key_value键值对进行整合,并生成字典。建立node,再使用node[key] = val,将每一条属性与属性值写入node中。

#读入数据
with open('/ssd/Spider/Neo4j_dataRelation1.jsonl',"r+")as reader :
    entity_lines = reader.readlines()
def get_Node(entity):
    test_dict = eval(entity)
    test_list = []
    for item_key in test_dict:
        if item_key == 'basicInfo':
            for basc_info in test_dict['basicInfo']:
                if basc_info['name'] and basc_info['value']:
                    test_list.append((test_dict['lemmaTitle'],basc_info['name'],basc_info['value']))
        elif item_key == 'lemmaSummary':
            if test_dict['lemmaSummary']['value']:
                 test_list.append((test_dict['lemmaTitle'],'lemmaSummary',test_dict['lemmaSummary']['value']))
        elif item_key=='synonyms_lemmaTitle' or item_key=='synonyms' :
            continue
        elif item_key=='category':
            if test_dict[item_key] !='':
                test_list.append((test_dict['lemmaTitle'],item_key,test_dict[item_key]))
            else:
                test_list.append((test_dict['lemmaTitle'],item_key,"None"))
        elif item_key=='tags':
            if test_dict[item_key] !='':
                test_list.append((test_dict['lemmaTitle'],item_key,test_dict[item_key]))
            else:
                test_list.append((test_dict['lemmaTitle'],item_key,"None"))
        
        elif item_key =='star_relations':
            for item in test_dict[item_key]:
                if item['name'] and item['value']:
                    test_list.append((test_dict['lemmaTitle'],item['name'],item['value']+"_"+item['lemmaId']))
        elif item_key == 'lemma_relations':
            for item in test_dict[item_key]:
                if item['name'] and item['value']:
                    test_list.append((test_dict['lemmaTitle'],item['name'],item['value']+"_"+item['lemmaId']))
        elif item_key == 'Relation':
            continue
        else:
            test_list.append((test_dict['lemmaTitle'],item_key,test_dict[item_key]))
    #建立字典
    entity_dict = {}
    for item in test_list:
        #entity_dict.setdefault(item[1],[]).append(item[2])
        entity_dict[item[1]] = item[2]
    label = 'Common_test'
    entity_name = entity_dict['lemmaTitle']
    node = Node(label,name=entity_name)
    #graph.create(node)
    for key, val in entity_dict.items():
        node[key] = val
    #graph.push(node)
    return node

2-4-2 建立子图

        在写入时,选择了开销最小并且最为稳妥的子图写入方式, subgraph = Subgraph(node_ls, relation_ls),需要对Subgraph()传入两个参数,node_ls表示节点列表,relation_ls表示关系列表,如果只是想写入节点,那就将relation_ls用[]代替。

def write_neo4j(node_ls):
    #构建子图
    subgraph = Subgraph(node_ls, [])
    #构建事务
    Transaction = graph.begin() 
    Transaction.create(subgraph)
    #提交
    graph.commit(Transaction)

2-4-3 子图写入

        使用子图的方式写入节点,本次写入中以1万为一个批次写入,写入之后将节点列表清空。 写入100万数据用时9分钟。

Node_list = []
for entity in tqdm(entity_lines[:1000000]):
    node = get_Node(entity)
    Node_list.append(node)
    if len(Node_list) == 10000:
        write_neo4j(Node_list)
        Node_list = []

2-5 创建索引

说明:为label是Common_test的实体的lemmaTitle创建索引,

#index_command = 'create index on:Common(lemmaTitle)'
index_command = 'create index on:Common_test(lemmaTitle)'
result = graph.run(index_command)

2-6 查询

说明:创建索引后,在100万节点的库中查询单实体,查询一条用时59ms

#查询
search_result = graph.nodes.match("Common_test").where(lemmaTitle='中国').all()  # [0].items()
#search_result
#search_result[0].items()

3 后记

        在处理数据时,每条实体数据的存储形式都是以key:value的形式存储,每条实体数据都有不同的key和value。所以做数据导入时,要根据每一条实体数据做’个性化处理‘。将数据中的属性写到列表中,然后再通过key、value的方式push到节点中。初次写入时,每个实体都单独处理,首先create node,然后再形成字典,进行push,这样的方法效率非常慢,因为每次创建节点再进行push都需要进行查库,并且随着库中数据量大增多,导致写入速度越来越慢。后面尝试够使用Load CSV 的方式写入,但是由于实体数量庞大,每个实体会有不同的属性,从而导致csv的维度有60W维,并且csv的维度及其稀疏,写入都需要占用巨大的内存,后遂放弃。最后了解到使用子图的方式可以写入,先将node存放到列表中,当然也可以存放关系形成subgraph = Subgraph(node_ls, relation_ls)的形式,如果relation_ls为空则写成ubgraph = Subgraph(node_ls, [])。随后可以控制节点列表的长度,文中在写入时设置的大小为1万,当列表的长度到达1万之后,便一次性提交。将一万多节点批次写入。这样既满足了节点数据个性化的要求,又实现了批量写入。

        写入数据后,便是创建索引,因为每个实体节点在写入时,为其贴上了标签(label),本次写入时的label设置为Common_test,所以在创建索引时,需要用到标签信息。之后就可以为实体的具体属性创建索引。创建索引后查询速度提升80%。 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/140595.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

量子计算(二十):量子算法简介

文章目录 量子算法简介 一、概述 二、量子经典混合算法 量子算法简介 一、概述 量子算法是在现实的量子计算模型上运行的算法,最常用的模型是计算的量子电路模型。经典(或非量子)算法是一种有限的指令序列,或一步地解决问题的…

乐视--996、内卷、裁员环境下一朵“奇葩”

在2022.12.28日我们发表了一篇“为什么四天工作制才是企业良药,而非裁员”,大家认为四天工作制与我们的距离就像实现“一个小目标”一样,不太可能。这不他来了,乐视来了,他真的来了,“鸡毛真的上天了”。他来了他来了他…

SQL技巧:使用AVG()函数计算占比

计算方式对比 一般计算占比,比如转换率、留存率等,都是先分组求和再相除得到结果,但是在一定的条件下,可以直接使用AVG()求出百分比。 比如,要求统计报名转化率,报名转化率公式为转化率报名人数/浏览人数…

内核解读之内存管理(8)内存模型

文章目录基本的术语CONFIG_FLATMEM(平坦内存模型)稀疏的内存模型基本的术语 在介绍内存模型之前需要了解一些基本的知识。 1、什么是page frame? 在linux操作系统中,物理内存被分成一页页的page frame来管理,具体pa…

c++11 标准模板(STL)(std::deque)(八)

定义于头文件 <deque> std::deque 修改器 擦除元素 std::deque<T,Allocator>::erase iterator erase( iterator pos ); (1)(C11 前) iterator erase( const_iterator pos ); (C11 起) iterator erase( iterator first, iterator last ); (2)(C11 前) iterator …

即时编译助力人大金仓KES分析能力飞跃

随着数字化技术对各行各业的不断渗透&#xff0c;人大金仓在金融、能源、电信等行业逐步进入深水区&#xff0c;面临越来越多的核心类系统改造升级&#xff0c;这些系统不仅需要满足在线交易系统运行的高实时性要求&#xff0c;还需要保证高效分析能力以帮助客户进行业务决策。…

红米pro14笔记本系统故障怎么U盘重装系统?

红米pro14笔记本系统故障怎么U盘重装系统&#xff1f;今天和大家一起来分享如何使用U盘重装系统的方法分享。有用户的红米pro14笔记本系统出现了一些问题需要进行重新安装&#xff0c;那么今天我们就一起来分享看看怎么U盘重装系统的方法吧。 准备工作&#xff1a; 1、U盘一个&…

Java执行Linux命令死锁阻塞挂起,Runtime.getRuntime().exec阻塞卡死问题解决

1、前言&#xff1a; 最近在做一个需求需要调用linux下的ffmpeg来对处理视频&#xff0c;很简单的需求&#xff0c;我像往常一样写下如下的代码片段&#xff1a; Process process Runtime.getRuntime().exec(cmd); process.waitFor(); But当我运行代码时&#xff0c;发现代码执…

前端笔记 ---- document.execCommand 函数整理

1. 语法 使用语法 bool document.execCommand(aCommandName, aShowDefaultUI, aValueArgument)返回值 一个 Boolean &#xff0c;如果是 false 则表示操作不被支持或未被启用。 备注&#xff1a; 在调用一个命令前&#xff0c;不要尝试使用返回值去校验浏览器的兼容性 2. 参…

基于Vue和SpringBoot的宾馆管理系统的设计和实现

作者主页&#xff1a;Designer 小郑 作者简介&#xff1a;Java全栈软件工程师一枚&#xff0c;来自浙江宁波&#xff0c;负责开发管理公司OA项目&#xff0c;专注软件前后端开发&#xff08;Vue、SpringBoot和微信小程序&#xff09;、系统定制、远程技术指导。CSDN学院、蓝桥云…

树形结构——红黑树

前言 在 JDK1.8 之后&#xff0c;HashMap 的底层是由数组、链表、红黑树来实现的&#xff0c;当数组长度到 64 的时候&#xff0c;或者链表长度到 8 的时候&#xff0c;会调用 treeifyBin 转换为红黑树实现。因为红黑树是小伙伴们面试的时候经常被考到的知识点&#xff0c;因此…

OSPF-MGRE实验

1.首先配ip [r6]int g 0/0/1 [r6-GigabitEthernet0/0/1]ip add 192.168.1.2 24 [r6-GigabitEthernet0/0/1]int g 0/0/0 [r6-GigabitEthernet0/0/0]ip add 192.168.2.2 24 [r6-GigabitEthernet0/0/0]int g 0/0/2 [r6-GigabitEthernet0/0/2]ip add 192.168.3.2 24 [r6-GigabitEt…

git pull 和git fetch

1.git fetch 用户一&#xff1a;本地初始化项目&#xff0c;创建文件&#xff0c;保存本地仓库&#xff0c;提交远程仓库 $ git init $ touch file.txt $ git add . $ git commit -m "创建了file.txt文件" [master (root-commit) 4dcee36] 创建了file.txt文件1 file …

简单又好用的财务分析工具有哪些?

什么样的财务分析工具才能算是简单又好用&#xff1f;是能够快速完成组合多变的财务指标运算分析&#xff1b;能够充分发挥企业经营健康晴雨表作用&#xff0c;反映企业财务健康状态&#xff1b;还是能够支持多维度动态分析、自助分析&#xff1b;或者是轻松合并账套&#xff0…

跨域与JSONP

1、同源策略 1.1、什么是同源 如果两个页面的协议&#xff0c;域名和端口都相同&#xff0c;则两个页面具有相同的源。 例如&#xff0c;下表给出了相对于 http://www.test.com/index.html 页面的同源检测&#xff1a; URL 是否同源 原因 http://www.test.com/other.html…

智慧图书馆中的“智慧”体现在哪些方面?

在信息时代背景下&#xff0c;各个领域都发生了巨大变革&#xff0c;图书馆也不例外&#xff0c;开始逐步向着现代化方向发展。传统图书馆存在较多的缺陷&#xff0c;已经无法满足人们的借阅需求&#xff0c;引进信息化技术&#xff0c;打造智慧图书馆是目前图书馆的必然发展趋…

Linux学习记录——오 vim基本知识

** Linux开发工具 ** Linux开发工具——vim vim最小集 vim是一个多模式编辑器&#xff0c;vi也一样&#xff0c;但vim兼容了vi的所有指令&#xff0c;还有一些独有的特性&#xff0c;本篇只针对vim展开。vim有各种模式&#xff0c;每个模式的用法都有差别&#xff0c;模式…

【数据在内存中的存储】肝货满满

前言 我们知道在C语言中的基本内置类型&#xff1a; char //字符数据类型short //短整型int //整形long //长整形long long //更长的整形float //单精度浮点型double //双精度浮点型 那么这些类型是如何存储的呢&#xff1f; 回顾指针类型&#xff1a; *int pi*char pc*float…

String的讲解(Java系列9)

目录 前言&#xff1a; 1.String 1.1字符串的构造 1.2Sting对象的比较 1.3字符串的查找 1.4字符串的转化 1.4.1数值和字符转换 1.4.2大小写转换 1.4.3字符串转数组 1.4.4格式化 1.5字符串的替换 1.6字符串拆分 1.7字符串截取 1.8字符串去空格 1.9字符串的不可变…

Matplotlib笔记 · 绘图区域的结构和子图布局与划分(figure, axes, subplots)

文章目录1. 绘图区域的结构2. subplot系方法 ( subplot布局 )2.1 使用 add_subplot(nrows, ncols, index) 逐一创建子图2.2 控制子图大小和位置 ( add_subplot(nrows, ncols, index) 参数详解 )2.3 使用 subplots(nrows, ncols) 批量创建多张子图3. axes系方法 ( axes布局 )3.1…