python 知识图谱demo_古诗词知识图谱Demo
早前调研了知识图谱的基础概念和技术框架,最近这两个月倒腾了一个古诗词的图谱demo,仅以此文记录一下实验过程。从零开始做这个Demo,整个过程大致分为三大步骤:数据采集,数据存储以及图谱应用,全文将按这三步进行记录。
一、数据采集
既然是从零开始,那第一步就是要爬取数据。搜了几个诗词网站,对比网页排版结构和内容丰富程度,个人觉得古诗词网是个不错的选择,在这里感谢站长为经典文化传承作出的贡献。
1. 网页分析
F12打开诗词列表页的源码,查看头部信息如下图:
请求的url格式固定,只有页码改变;请求的类型为get。
多看几个页面,可以发现请求头中Cookie的hm_lvt和hm_lpvt为两个时间戳,不同页面只有hml_pvt发生改变;old_url取值为当前页码;Referer也是随页码改变的固定格式url。
请求列表页面的返回结果为json列表,可以非常方便地提取需要的信息,而不用去html中定位并解析目标元素,省去了爬虫中的一半工作量:
每一个json对应一首诗词,包含标题、正文、作者、朝代、标签、体裁、作者介绍、译注、赏析等信息,这种结构化的数据,也免去了数据抽取和整理的很多工作。
2. 爬虫代码
这一类网站广告很少,也没有收费业务,带有公益性质,网站服务器一般也扛不住爬虫的压力,常常会采取一些反爬措施,比如封禁IP。为了爬取这些网站,一方面要降低爬取速度;另一方面要维护代理池,在被封的时候更换IP。爬取过程中及时保存爬虫结果,并记录爬取失败的页面,方便以后再重爬。
def crawl_pages(page_list, save_path, ip_pool, retry_times=5):
fail_list = list()
lvt_code = int(time.time())
ip = random.choice(ip_pool)
for page in page_list:
time.sleep(3 * random.random())
lpvt_code = int(time.time())
page_url = 'https://www.gushici.com/poetry_list?page={0}'.format(page)
referer = 'https://www.gushici.com/p_{0}'.format(page)
headers = {'Host': 'www.gushici.com',
'Connection': 'keep-alive',
'Accept': '*/*',
'X-Requested-With': 'XMLHttpRequest',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.103 Safari/537.36',
'Referer': referer,
'Accept-Encoding': 'gzip, deflate, br',
'Accept-Language': 'zh-CN,zh;q=0.9',
'Cookie': 'JSESSIONID=48304F9E8D55A9F2F8ACC14B7EC5A02D; Hm_lvt_98209c07e81fcbdd5f79bd9e94c617eb={0}; Hm_lpvt_98209c07e81fcbdd5f79bd9e94c617eb={1};\old_url=/p_{2}'.format(lvt_code, lpvt_code, page)}
times = 0
flag = False
while times <= retry_times:
times += 1
try:
response = requests.get(page_url, headers=headers, proxies={'https': ip}, verify=False, timeout=10)
flag = True
with open(os.path.join(save_path, page), 'w', encoding='utf-8') as f:
json.dump(response.text, f, ensure_ascii=False)
break
except:
ip = random.choice(ip_pool)
if not flag:
fail_list.append(page)
with open(os.path.join(save_path, 'fail'), 'w', encoding='utf-8') as f:
json.dump(fail_list, f, ensure_ascii=False)
二、数据存储
知识图谱的数据层有多重存储方式,本文选择采用Neo4j搭建。Noe4j是一个高性能的轻量级图形数据库,应对小型知识图谱绰绰有余。虽然关系型数据库通过多重join也可以实现数据间的复杂关系查询,但是多表数据join然后过滤筛选导致性能会非常差,而图数据库很好地解决这样的问题,它只用遍历相关节点,不用操作全量数据,性能会大大提升。
1. Neo4j安装
从Neo4j官网可以下载开源的Noe4j社区版,解压到D盘,然后配置环境变量。注意:Neo4j依赖于Java运行环境,安装Neo4j前请检查本机是否安装Java并配置Java的环境变量。
打开cmd命令行窗口,进入安装目录下的bin文件夹,执行“neo4j install-service”命令,安装Neo4j服务。然后执行“neo4j start”命令,启动Neo4j的服务。
2. Neo4j操作
Neo4j是一种图数据库,其中并没有数据表的概念,只包含节点和边,节点表示实体,边表示实体间的关系(分为有向关系和无向关系),节点和边可以包含键值对表示的属性。
用惯了关系型数据库,初次接触图数据库感觉有点别扭。为了便于自己理解,我是这样来类比的:
节点和关系是图数据库中定义的最原始的两个基类,节点(关系)的标签表示由节点(关系)基类派生出来的一类节点(关系)。当导入数据之后,具有属性值的某一个节点(关系),就是该标签对应的节点(关系)派生类所生成的实例。
(1)导入数据
Neo4j提供import命令,可以批量导入csv格式的数据。针对json格式的数据,可以转为csv格式,然后用import导入,注意json中的双引号需要进行转义。为避免格式转换过程中的错误,可以调用apoc函数库中的json导入工具。
apoc的安装方式为:从github中下载apoc的jar包,将jar包复制到Neo4j安装目录的plugins路径下,在neo4j.conf中配置apoc.import.file.enabled=true,表示允许apoc导入文件。重启Neo4j服务,调用apoc.load.json即可导入json数据。
(2)查询数据
Neo4j的查询语言为Cypher(第一眼看成了Cython,然而这两个半点不沾边)。官网有完整版的Cypher手册,本文只挑选最基础的几个语句简要介绍。
A.增:
新建节点: CREATE (node: NodeType {AttributeKey : AttributeValue})
// 创建一个姓名为Jack的Person类的节点,并返回该节点
CREATE (a:Person {name:"Jack"})
RETURN a
新建关系:不能单独创建关系,必须指明关系的起始节点和终止节点。--表示无向关系,->和 EndNode
// 创建两个Person之间Knows的关系,并返回节点和关系
CREATE (a:Person)-[k:KNOWS]-(b:Person)
RETURN a, k, b
B.查:
查询节点:MATCH (node: NodeType {AttributeKey : AttributeValue}) WHERE node.AttributeKey = AttributeValue
// 查询1970年后出生的Person节点,并返回节点
MATCH (n)
WHERE n.born > 1970
RETURN n;
查询关系:MATCH StartNode - (relationship: RelationshipType {AttributeKey : AttributeValue}) -> EndNode WHERE relationship.AttributeKey = AttributeValue
// 查询自从2015年起居住(LIVES_IN)在NewYork城市(City)的名叫Mike的人(Person),并返回节点和关系
MATCH (p:Person {name:"Michel"})-[s:LIVES_IN]->(c:City {name:"NewYork"})
WHERE s.since = 2015
RETURN p,s,c
C.改:
修改属性:MATCH (variable : NodeType|RelationshipType) SET variable = {AttributeKey : AttributeValue}
// 查询名为Jack的Person类节点,并将名字改为Michel,年龄改为23
MATCH (p:Person)
WHERE p.name = "Jack"
SET p = {name: "Michel", age: 23}
D.删:
删除节点:与该节点相关的关系也需要删除。MATCH (node) - [relationship] - () DELETE node, relationship
// 删除名为Jack的Person节点及关联关系
MATCH (p:Person)-[relationship]-()
WHERE p.name = "Jack"
DELETE relationship, p
删除属性:MATCH (node) - [relationship] - () REMOVE node.AttributeKey, relationship.AttributeKey
// 删除名为Michel的Person节点的年龄属性
MATCH (p:Person)
WHERE p.name = "Michel"
REMOVE p.age
3. Neo4j实践
本文设计的知识图谱包含三类节点:诗词(Poem)、作者(Author)、标签(Tag)。作者与诗词是写作(WRITE)的关系,诗词、作者与标签是标识(LABEL)关系。
// 在三类节点上创建索引
create index on :Poem(uuid);
create index on :Author(name);
create index on :Tag(tag);
// 将数据导入Neo4j
call apoc.periodic.iterate('call apoc.load.json("web_file_poetry.json") yield value as poem',
'merge (p:Poem{uuid: poem.poem_id})
set p.title = poem.title, p.content=poem.poem, p.tag=poem.tag, p.appreciation=poem.appreciation, p.background=poem.background
// 作者节点
merge (a:Author{name: poem.poet, dynasty: poem.dynasty})
// 作者到诗词的关系
merge (a)-[r1:WRITE]->(p)',
{batchSize:100000, iterateList:true, parallel:true});
// 建立诗词、作者与标签之间的关系
match (a:Author)-[:WRITE]->(p:Poem)
where p.tag <> ''
unwind split(trim(p.tag), ",") as tag
// 标签节点
merge (t:Tag{tag: tag})
// 诗词到标签的关系
merge (p)-[r1:LABEL]->(t)
// 作者到标签的关系
merge (a)-[r2:LABEL]->(t);
图数据库创建成功之后,可以查询看看效果,Neo4j的可视化做的还是挺好看的。
三、图谱应用
知识问答是基于知识图谱的一项应用,前沿的问答系统多采用深度学习、自然语言处理等技术。本文采用最简单的正则匹配( ̄▽ ̄)~*
1.首先,定义可以回答的问题类型:
查找诗词的正则:
source_list = [
'[\"\'“‘《]?(?:是|出自|来[自|源])(?:哪[首|篇|个|里|儿|]?|什么)的?(?:[诗词][文句]?|文章|句子)?',
'[\"\'“‘《]?的(?:来源|出处|(?:整[首|篇]|完整|全)[诗词文])',
'(?:含有?|包[含括])[\"\'“‘《]?的(?:[诗词][文句]?|文章|句子)'
]
source_list = list(map(re.compile, source_list))
查找作者的正则:
author_list = [
'[\"\'“‘《]?的(?:作者|[诗词]人)',
'[\"\'“‘《]?是(?:谁|哪[位个])(?:作者|[诗词]人)?',
]
author_list = list(map(re.compile, author_list))
查找标签的正则:
tag_list = [
'(?:写|描[写绘述]|表达)(\S+?)的?[诗词]',
]
tag_list = list(map(re.compile, tag_list))
整合问题正则:
rules = {
'source': source_list,
'author': author_list,
'tag': tag_list,
}
2.其次,根据正则判断问题类型,并提取问题中的要素
def match(question):
match_result = None
for mode, temp_list in rules.items():
for temp in temp_list:
text = temp.findall(question)
if text:
match_result = (mode, text[0])
break
return match_result
3.最后,从Neo4j中根据问题要素查找并返回问题答案
def parse(question):
match_result = match(question)
if match_result is None:
return None
mode, text = match_result
res = None
cql = None
if mode == 'source':
cql = 'match (p:Poem) where p.content contains "{0}" return p.title, p.content'.format(text)
elif mode == 'author':
cql = 'match (a:Author)-[:WRITE]->(p:Poem) where p.content contains "{0}" return a.name'.format(text)
elif mode == 'tag':
tag_list = jieba.lcut(text)
cql = 'match (p:Poem)-[:LABEL]->(t:Tag) where t.tag in {0} return p.content, t.tag'.format(tag_list)
else:
pass
if cql:
res = neo4j_graph.run(cql).to_data_frame()
return res
后记:
本文只是搭建了一个非常小的图谱demo,后续还有很多地方需要完善,如有遗漏或错误,请大家不吝指出,欢迎交流。
python 知识图谱demo_古诗词知识图谱Demo相关推荐
- python知识图谱实战_知识图谱实战
原标题:知识图谱实战 知识图谱是近来非常红火的技术,融合网络爬虫,自然语言处理,机器学习,深度学习,图数据库,复杂网络分析等多种热门技术于一身,技术含量密集,在构造语义搜索,问答平台,高智能的人机界面 ...
- python+neo4j构建基于知识图谱的电影知识智能问答系统
目录 一.写在前面: 二.系统准备: 三.系统构建 四.总结反思: 五.完整代码: Author:qyan.li Date:2022.6.3 Topic:借助于python构建知识图谱的电影知识智能问 ...
- Ampligraph——基于tensorflow的python库,可用于知识图谱嵌入和链接预测
目录 一.AmpliGraph 1.介绍 2.特点 3.模块 4.安装AmpliGraph 二.API接口 1.数据 2.模型 3.评估 4.发现 5.其他实用函数 三.实例代码 1.训练和评估嵌入模 ...
- python 知识图谱数据库_知识图谱和 Neo4j 浅析-数据库
编辑推荐: 本文来自于51cto,介绍了什么是知识图谱,知识图谱的应用场景,知识图谱的构建,知识图谱的存储以及 neo4j 的性能测试,neo4j图数据库优化等知识. 在当前大数据行业中, 随着算法的 ...
- 技术动态 | 事理图谱,下一代知识图谱
本文转载自公众号:DataHorizon. 人工智能与认知智能 当前人工智能时代下,机器与人类之间的博弈一直在进行着.如图1所示,从1926年达特茅斯会议的召开标志人工智能诞生到深度学习模型在若干人工 ...
- 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part6基于图谱的问答实现
前序文章: [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视化及问答系统实践:part1项目介绍与环境准备 [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视 ...
- 从零构建知识图谱-第二章知识图谱技术体系
目录 一.知识表示与知识建模 1.知识表示的概念 (1)知识表示的五种角色 (2)综合描述 2.知识表示的方法和形式 (1)描述逻辑 (2)描述语言 3.知识建模 (1)知识建模的主要分析过程 (2) ...
- 知识图谱入门 (一) 知识图谱与语义技术概览
欢迎大家关注我的博客 http://pelhans.com/ ,所有文章都会第一时间发布在那里哦~ 知识图谱与语义技术概览.主要介绍知识表示.知识抽取.知识存储.知识融合.知识推理.知识众包.语义搜索 ...
- 我们的实践:事理图谱,下一代知识图谱
原文链接:https://mp.weixin.qq.com/s/iLfXeVeWE5CCs_sM_NAOSw 一.人工智能与认知智能 当前人工智能时代下,机器与人类之间的博弈一直在进行着.如图1所示, ...
最新文章
- py2exe——.py文件转换成exe
- SDUT1281Cup
- LeetCode 533. 孤独像素 II
- mysql 事务 隔离级别_MySQL的四种事务隔离级别
- python itertools模块_Python标准模块--itertools
- Node.js基础学习(第二幕)
- Python排序算法---快速排序
- 小学生python编程教程-极度舒适的全套 Python 入门教程,小学生看了也能学会
- 傅里叶变换性质证明卷积_傅里叶变换2.系统属性和卷积公式的推导
- 微信公众号迁移公证需要哪些材料?账号迁移流程来了
- 黑客如何用线程注射技术隐藏自己的病毒
- 学了python能找人吗_只学python能找工作吗
- 动态规划法(JavaScript)
- java 压缩pdf_java实现文件的压缩和解压
- 用友加密服务器修改密码,用户密码怎么修改?
- odrive搭建差速小车+轮毂电机+RC航模控制器
- 普林斯顿 计算机专业排名,普林斯顿大学计算机排名2020年全球超级有用干货
- 2019年12月PAT甲级 第一题 Good in C(1164)题解
- 【Flutter 异步编程 - 捌】 | 计算耗时? Isolate 来帮忙
- 转载Python正则表达式匹配反斜杠'\'问题(——字符串转义与正则转义)