文章目录
- 关于Neo4j
- 1. neo4j安装及配置:
- 2. 确定三元组
- 3. 代码实现
- 结束语
关于Neo4j
Neo4j
是一个高性能的,NOSQL
图形数据库。它是一个嵌入式的、基于磁盘的、具备完全的事务特性的Java
持久化引擎,但是它将结构化数据存储在网络(从数学角度叫做图)上而不是表中。是构建知识图谱最常用的图数据库之一。
知识图谱部署在
Linux
服务器上,具体版本信息为:
Ubuntu 22.04.2
Java 17.0.8
Neo4j 5.12.0
1. neo4j安装及配置:
Neo4j
依赖Java
引擎,因此需要安装Java
:
Java17
官方地址:https://www.oracle.com/java/technologies/downloads/#java17
Neo4j
官方地址:https://neo4j.com/deployment-center/#community
安装流程:
# 下载java17
wget https://download.oracle.com/java/17/latest/jdk-17_linux-x64_bin.tar.gz
# 下载neo4j
https://dist.neo4j.org/neo4j-community-5.12.0-unix.tar.gz
# 解压到/usr/local
sudo tar -zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/
sudo tar -zxvf neo4j-community-5.12.0-unix.tar.gz -C /usr/local/
配置流程:
# 配置neo4j
vim /usr/local/neo4j-community-5.12.0/conf/neo4j.conf
# line 65 设置远程访问
server.default_listen_address=0.0.0.0
# line 86, 91 设置端口
server.bolt.listen_address=:7687
server.http.listen_address=:7474
# 7687是bolt端口,Bolt协议是neo4j的应用层协议
# 7474和7473分别是http和https端口,可以通过浏览器来访问可视化界面
# 配置环境变量
vim ~/.bashrc
# >>> setting neo4j >>>
JAVA_HOME=/usr/local/jdk-17.0.8
NEO4J_HOME=/usr/local/neo4j-community-5.12.0
export PATH=$JAVA_HOME/bin:$NEO4J_HOME/bin:$PATH
# <<< setting neo4j <<<
# 使配置生效
source ~/.bashrc
# 查看版本
java --version
neo4j --version
版本信息如下:
以下是neo4j
常用的几个指令:
# 启动neo4j
neo4j start
# 查看neo4j的状态
neo4j status
# 停止neo4j
neo4j stop
# 重启neo4j
neo4j restart
ps:
如果因权限问题启动失败,则需要给予一定的权限:
bash sudo chmod 777 -R neo4j-community-5.12.0 jdk-17.0.8
浏览器访问可视化界面http://localhost:7474
(可以修改为数据库的ip
),初始账户及密码均为neo4j
:
登录后会自动跳转让修改初始密码,修改完毕后进入可视化界面:
2. 确定三元组
关于知识图谱中三元组的相关知识,这里也不再进行概述,感兴趣的可以查阅相关资料。
本来计划按照如下方式进行构造知识图谱,但后来实现的过程中发现,不太好构造(其实还不太熟练哈哈哈哈😅),所以就构造简单了些,比如坦克的火力/机动性/防护/侦察这些属性直接展开了。
展开后的关系如下:
# (实体, 关系, 实体)
Tank:
系别:
类型:
等级:
角色:
性质:
历史背景:
银币:
经验:
损伤:
装甲穿透力:
火炮装填时间:
最小弹震持续时间:
最大弹震持续时间:
射速:
平均每分钟损伤:
瞄准时间:
00米精度:
弹药容量:
重量/最大载重量:
发动机功率:
单位功率:
最大速度:
旋转速度:
炮塔旋转速度:
生命值:
车体装甲:
炮塔装甲:
悬挂装置维修时间:
观察范围:
通信距离:
3. 代码实现
根据上篇博客爬取到的坦克数据,构造知识图谱:
# -*- coding: utf-8 -*-
# Author : xiayouran
# Email : youran.xia@foxmail.com
# Datetime: 2023/10/1 20:29
# Filename: build_kg.py
import os
import json
from py2neo import Graph, Node, Relationship, NodeMatcher
class WOTKG(object):
def __init__(self, clean_kg=True):
self.clean_kg = clean_kg
self.entity_tank = []
self.entity_price = []
self.entity_firepower = []
self.entity_mobility = []
self.entity_survivability = []
self.entity_spotting = []
self.all_entity = []
self.data_path = '../data/tank_list_detail.json'
self.graph = Graph('neo4j://172.20.203.172:7687', auth=('neo4j', 'lyp123456')) # use your ip 172.20.197.99
self.matcher = NodeMatcher(self.graph)
if self.clean_kg:
self.graph.delete_all()
def build_KG(self):
self.collect_entity()
self.create_all_node()
self.create_relation()
def check_zero(self, v_str):
if not v_str:
return True
elif len(v_str) == 2 and v_str[0] == '0' and v_str[1] in ['秒', '米', '%', '度']:
return True
else:
return False
def add_entity(self, tank_name, entity_name, v_item: dict):
for k_, v_ in v_item.items():
if self.check_zero(v_):
continue
if entity_name == 'Price':
self.entity_price.append(('Price', k_, v_))
elif entity_name == 'Firepower':
self.entity_firepower.append(('Firepower', k_, v_))
elif entity_name == 'Mobility':
self.entity_mobility.append(('Mobility', k_, v_))
elif entity_name == 'Survivability':
self.entity_survivability.append(('Survivability', k_, v_))
elif entity_name == 'Spotting':
self.entity_spotting.append(('Spotting', k_, v_))
self.all_entity.append((tank_name, entity_name, k_, v_))
def collect_entity(self):
with open(self.data_path, 'r', encoding='utf-8') as f:
data_json = json.load(f)
for tank_item in data_json.values():
tank_name = tank_item['tank_name']
for k, v in tank_item.items():
if k[0] == 't' or not v:
continue
if k == '价格':
if isinstance(v, str):
self.entity_price.append(('Price', '金币', v))
self.all_entity.append((tank_name, 'Price', '金币', v))
else:
self.add_entity(tank_name, 'Price', v)
elif k == '火力':
self.add_entity(tank_name, 'Firepower', v)
elif k == '机动性':
self.add_entity(tank_name, 'Mobility', v)
elif k == '防护':
self.add_entity(tank_name, 'Survivability', v)
elif k == '侦察':
self.add_entity(tank_name, 'Spotting', v)
else:
self.entity_tank.append((tank_name, k, v))
self.all_entity.append((tank_name, 'Tank', k, v))
def create_node(self, entity_list, entity_name='Tank'):
head_nodes = []
tail_nodes = []
for (head, rela, tail) in entity_list:
if head not in head_nodes and head not in ['Price', 'Firepower', 'Mobility', 'Survivability', 'Spotting']:
head_nodes.append(head)
node = Node(entity_name, name=head)
self.graph.create(node)
if tail not in tail_nodes:
tail_nodes.append(tail)
node = Node("{}Value".format(entity_name), name=tail)
self.graph.create(node)
def create_all_node(self):
self.create_node(self.entity_tank, entity_name='Tank')
self.create_node(self.entity_price, entity_name='Price')
self.create_node(self.entity_firepower, entity_name='Firepower')
self.create_node(self.entity_mobility, entity_name='Mobility')
self.create_node(self.entity_survivability, entity_name='Survivability')
self.create_node(self.entity_spotting, entity_name='Spotting')
def create_relation(self):
for (head, flag_str, rela, tail) in self.all_entity:
node_head = self.matcher.match('Tank').where(name=head).first()
node_tail = self.matcher.match('{}Value'.format(flag_str)).where(name=tail).first()
rela_node = Relationship(node_head, rela, node_tail)
self.graph.create(rela_node)
if __name__ == '__main__':
wot_kg = WOTKG(clean_kg=True)
wot_kg.build_KG()
构造后的知识图谱可视化效果如下:
单辆坦克:
知识图谱局部:
结束语
本篇的代码已经同步到仓库中,感兴趣的话可以拉取一下,下一篇文章就基于这个知识图谱来构造一个关于坦克百科的智能问答机器人。
开源代码仓库
如果喜欢的话记得给我的GitHub
仓库WOT点个Star哦!ヾ(≧∇≦*)ヾ
公众号已开通:
夏小悠
,关注以获取更多关于Python
文章、AI
领域最新技术、LLM大模型相关论文及内部PPT
等资料^_^