Neo4j+陶瓷多模态知识图谱构建

Neo4j+陶瓷多模态知识图谱构建

Cyria7 Lv2

1 总体概述以及 Neo4j 简介

本博客记录如何构建一个有关陶瓷的多模态知识图谱,所使用到的数据库平台是 neo4j。Neo4j 是使用 Java 编写的一个基于图的开源数据库,随着技术的发展,人们对数据的需求已经不仅限于数据本身,更多是数据与数据之间的联系。而如果用传统的数据库来存储连接的数据,会导致遍历大量数据时不能提供合适的性能。Neo4j 遵循图数据模型,使用 cypher 语言对数据库进行操作,且具有可视化界面来直观反应数据节点之间的联系。

1.1 Mac 版本安装(Apple Silicon/Intel 通用)

  1. 安装适配 Apple Silicon 的 jdk 版本(博主安装的是 Java17)。

  2. 从 neo4j 官网下载最新安装包,博主这里安装的是 neo4j-5.5.0,
    随附官网 community server 的下载页面 https://neo4j.com/download-center/#community。

  3. 下载后解压 tar.gz 文件(尽量不要解压在下载文件夹里,最好选择一个全英文路径且没有空格的路径下),终端进入/neo4j-community-5.5.0/bin 目录下,执行neo4j start命令。如果成功执行则可以在 http://localhost:7474/browser/ 本地网站访问,显示的页面如下图则表示正常安装。

    installsuc

  4. *(以下步骤为可选步骤)*将 neo4j 命令添加到系统的环境变量中,在任意目录下都可以执行neo4j start/stop等命令。

    • 在~/.bash_profile 中加入如下命令(尖括号内容替换为你自己的路径)

      1
      2
      export NEO4J_HOME=/Users/<username>/<your_path>/neo4j-community-5.5.0
      export PATH=$PATH:$NEO4J_HOME/bin
    • 如果你使用的是 mac 自带的“终端.app”软件,则需要在~/.zshrc 的开头加入如下两行

      1
      2
      source ~/.profile
      export PATH=/opt/homebrew/bin:$PATH
    • 保存后在终端中执行source ~/.zshrc即可生效,在~目录下执行neo4j start命令查看是否能正常启动

**恭喜你完成了 neo4j 的 mac 安装!!**🎉

2 陶瓷文物数据

2.1 数据来源——故宫博物馆网站

  • 藏品目录(部分):https://www.dpm.org.cn/collection/ceramics.html
    本目录下的陶瓷文物共有 1,388 条记录,对应每个文物都具有以下(或部分)栏目:文物名称、文物对应图片、时代、分类(一般来说是制作工艺,如釉下彩、青瓷等)、窑口、简介、关键词(和该文物相关的内容,如青花、吉祥图案)等。是博主目前首选的数据采集内容。
  • 数字文物库:https://digicol.dpm.org.cn/?category=6
    本目录下的陶瓷文物有 10,624 条记录,对应每个文物具有以下(或部分)栏目:文物名称、文物对应图片、时代、相关推荐词条(其中可能包含物件类型、图案纹样、形制等)。记录较多,后续大概率会加入陶瓷知识图谱中。需要注意的是,该文物库与上述藏品目录(部分)非包含关系
  • 数字多宝阁:https://www.dpm.org.cn/shuziwenwu.html?name=陶瓷
    本目录下的陶瓷文物有 60 条记录,需要注意的是,每个陶瓷文物都具有3D 效果!,但由于数据较少,暂未加入本次数据采集中。

©️ 版权注意(转自故宫博物馆官网):任何单位或个人在以转载、引用、摘编、下载等方式使用本网站内容时,均须注明作者,并标明图片、文章的出处为“故宫博物院网站”或http://www.dpm.org.cn 。 未经故宫博物院或相关权利人的书面许可,不得修改所使用的内容。

3 使用 Neo4j 构建知识图谱

3.1 常用 Neo4j 命令

1
2
# 删除所有HAS_PROPERTY关系
match (a1:Artifact)-[r:HAS_PROPERTY]-(a2:Keywords) delete r

3.2 构建知识图谱 python 脚本

将 2.1 中收集到的数据(藏品目录)进行整理,整理成如下栏目的 csv 格式:

1
2
3
文物名称,时代,分类,窑口,文物图片url,关键词
福清窑黑釉盏,宋,结晶釉,福清窑,https://img.dpm.org.cn/Uploads/Picture/dc/21861[1024].jpg,泪痕、王安石、建窑、兔毫纹
...

3.2.1 构建所有实体节点

  • 构建文物节点
    编写如下 python 脚本在 neo4j 中生成文物节点 Artifact,其中包括文物的名称、时代、分类、文物图片、关键词等属性
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
import csv

# 打开CSV文件
with open('转cypher脚本/csv文件/data2.csv', newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)

# 生成Cypher语句
cypher_statements = []
for row in reader:
# 构造属性字典
properties = {}
if row.get('时代'):
properties['era'] = row['时代']
if row.get('分类'):
properties['category'] = row['分类']
if row.get('窑口'):
properties['kiln'] = row['窑口']
if row.get('文物图片url'):
properties['imageUrl'] = row['文物图片url']
if row.get('关键词'):
keywords = row['关键词'].strip("[]").replace("'", "").split(", ")
# keywords = row['关键词'].split("、")
properties['keywords'] = keywords

# 构造Cypher语句
cypher = f"CREATE (:Artifact {{name: '{row['文物名称']}'"
if properties:
property_strings = [f"{k}: {v}" if isinstance(
v, list) else f"{k}: '{v}'" for k, v in properties.items()]
cypher += ', ' + ', '.join(property_strings)
cypher += '})'
cypher_statements.append(cypher)

# 将Cypher语句写入文件
with open('createchnew.cypher', 'w', encoding='utf-8') as cypher_file:
for statement in cypher_statements:
cypher_file.write(statement + '\n')
  • 构建时代、分类、窑口、关键词节点:
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
import csv

# 打开CSV文件
with open('转cypher脚本/csv文件/data2.csv', newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)

# 维护时代、分类、窑口、关键词的集合
eras = set()
categories = set()
kilns = set()
keywords = set()

# 遍历CSV文件中的每一行数据
for row in reader:
# 检查并添加时代、分类、窑口、关键词到集合中
if row.get('时代'):
eras.add(row['时代'])
if row.get('分类'):
categories.add(row['分类'])
if row.get('窑口'):
kilns.add(row['窑口'])
if row.get('关键词'):
kw = row['关键词'].strip("[]").replace("'", "").split(", ")
for k in kw:
keywords.add(k)
# 生成创建时代、分类、窑口节点的Cypher语句
keyword_statements = [
f"CREATE (:Keywords {{name: '{keyword}'}})" for keyword in keywords]
era_statements = [f"CREATE (:Era {{name: '{era}'}})" for era in eras]
category_statements = [
f"CREATE (:Category {{name: '{category}'}})" for category in categories]
kiln_statements = [f"CREATE (:Kiln {{name: '{kiln}'}})" for kiln in kilns]

# 将Cypher语句写入文件
with open('AllOtherNodes.cypher', 'w', encoding='utf-8') as cypher_file:
for statement in keyword_statements+era_statements+category_statements+kiln_statements:
cypher_file.write(statement + '\n')

注意:上述脚本文件生成的.cypher 文件内容可以直接复制到 neo4j 浏览器中的命令行执行

3.2.2 构建所有关系

在构建关系的过程中使用到了 py2neo 工具包,可以通过如下代码来接入 neo4j 数据库并直接执行命令:

1
2
3
4
5
6
7
8
9
10
11
12
from neo4j import GraphDatabase, basic_auth

# 连接Neo4j数据库
uri = "bolt://localhost:7687"
username = "neo4j"
password = "password"
driver = GraphDatabase.driver(uri, auth=basic_auth(username, password))

with driver.session() as session:
result = session.run("MATCH (n) RETURN count(n)")
count = result.single()[0]
print(f"成功连接到Neo4j数据库,当前有{count}个节点。") # 检查是否成功连接到neo4j
  • 构建“文物 - 制造时间是 - 时代”、“文物 - 采用工艺 - 分类”、“窑口 - 制造 - 文物”三个关系:
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
with open('data2.csv', 'r', encoding='utf-8') as f:
lines = f.readlines()
for line in lines[1:]:
values = line.strip().split(',')
relic_name = values[0] # 文物名称
dynasty = values[1] # 时代
category = values[2] # 分类
kiln = values[3] # 窑口
print(relic_name, dynasty, category, kiln)
# keywords = values[5][1:-1].split(', ') if values[5] != '' else [] # 关键词

# 创建"制造时间是"关系
if dynasty != '':
with driver.session() as session:
query = (
f"MATCH (a:Artifact {{name: '{relic_name}'}}), "
f"(e:Era {{name: '{dynasty}'}}) "
"MERGE (a)-[:MADE_IN]->(e)"
)
session.run(query)

# 创建"采用工艺"关系
if category != '':
with driver.session() as session:
query = (
f"MATCH (a:Artifact {{name: '{relic_name}'}}), "
f"(c:Category {{name: '{category}'}}) "
"MERGE (a)-[:CRAFTED_WITH]->(c)"
)
session.run(query)

# 创建"产出"关系
if kiln != '':
with driver.session() as session:
query = (
f"MATCH (a:Artifact {{name: '{relic_name}'}}), "
f"(k:Kiln {{name: '{kiln}'}}) "
"MERGE (k)-[:PRODUCED]->(a)"
)
session.run(query)
  • 构建“文物 - 具有特性 - 关键词”关系:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
with open('csv文件/data2.csv', newline='', encoding='utf-8') as csvfile:
reader = csv.DictReader(csvfile)
i = 1
for line in reader:
relic_name = line['文物名称'] # 文物名称
keywords = line['关键词'].strip("[]").replace("'", "").split(", ")
if keywords[0] != '':
# 创建"具有"关系
print(str(i) + ': ')
i += 1
print(keywords)
with driver.session() as session:
for keyword in keywords:
query = (
f"MATCH (a:Artifact {{name: '{relic_name}'}}), "
f"(k:Keywords {{name: '{keyword}'}}) "
"MERGE (a)-[:HAS_PROPERTY]->(k)"
)
session.run(query)

3.3 构建样例

下图为 neo4j 中呈现出的部分样例,后续还需要对节点和关系进行优化和删改

kgexample

  • Title: Neo4j+陶瓷多模态知识图谱构建
  • Author: Cyria7
  • Created at : 2023-03-14 21:00:21
  • Updated at : 2023-08-30 14:25:21
  • Link: https://cyria7.github.io/2023/03/14/neo4j/
  • License: This work is licensed under CC BY-NC-SA 4.0.
Comments