赞
踩
承接前文,本文介绍如何根据已有的neo4j图谱来搭建一个简单的问答系统。
ps:因为是基于neo4j图谱的,所以这个问题必须是在图谱中有答案才能进行回答。
完整项目github地址:https://github.com/Chtholly1/KG-and-QA-demo
问答系统是NLP中最复杂的场景之一,根据查阅资料和个人的理解,一个简单的问答系统至少需要包含以下三个部分:
以下分别对这三部分进行介绍:
当一个问句过来的时候,我们首先要对其进行初步的分类,比如:
问题:伊利丹·怒风的称号是什么?
解析提问的类别:title
问题:伊利丹·怒风的种族是什么?
解析提问的类别:race
这是一个典型的分类问题,我们一般有两种方法:
1.模板匹配:
比如说对于第一个问题,他的模板就应该是
xx的称号是什么?
对于每个类别我们都可以枚举一些常见的模板,如:
#race xx是什么族的 xx是什么种族的 xx的种族是什么 xx是啥族的 xx是啥种族的 xx的种族是啥 xx是xx族的吗 xx族有哪些人 xx族有哪些角色 哪些人是xx族的 哪些角色是xx族的 哪些是xx族的 #group xx是什么势力的 xx的势力是什么 xx是啥势力的 xx的势力是啥 xx是xx势力的吗 xx势力有哪些人 xx势力有哪些角色 哪些人是xx势力的 哪些角色是xx势力的 哪些是xx势力的 #title xx的头衔是什么 xx的称号是什么 xx被誉为什么
匹配模板也有两种思路:
显然第一种方法准确率更高,但召回率更低。
2.模型分类
分类问题当然能由经典的NLP模型来解决,自不必多说。
关键就是样本的构造和收集。
一个比较常规的思路就是
判断问题的所属类别以后,我们还需要知道用来查询的关键词,
问题:伊利丹·怒风的称号是什么?
解析提问的类别:title
如上,虽然知道了在问称号,但我们需要知道在问谁(伊利丹怒风)的称号。
关键词抽取的方法其实和分类问题是差不多的,一是模板匹配,二是NER模型。
初级阶段来说,模板匹配就能做的比较好了,因为关键词的集合是图谱中存在的有限集,而且发生语义的歧义的可能性也很小。
由此我们便完成了第二步:关键词抽取。
理解问题后,我们最后还需要把理解的内容转换成neo4j支持的查询语言。
首先介绍一个概念,neo4j本质上是由"节点"和"关系"组成,而每个"节点"又可以具有多个"属性"。
细心的同学应该发现了,就算在"race"这个大类下,其中还是存在两种不同的提问方式:
1.xx是什么种族的
2.xx种族有哪些角色。
显然这两个提问的结果是不一样的,所以对应的查询语言也不一致。
本质上这里还需要再做一个分类。在这里可以用一个比较取巧的方法:
当xx是一个角色名的时候,触发第一种查询方式。
当xx是一个种族名的时候,触发第二种查询方式。
一般来说,基于图谱来查询的话,简单的提问的结构是比较固定的,一般也就分为三种:
所以对于确定好的大类的提问而言,大部分都可以分到这三种结构下面。
但在实际中问题可能要复杂很多,比如说复合问题:
1.种族为兽人且性别为男的角色有哪些?
2.麦迪文的徒弟的徒弟是谁?
对于复合问题,一个常规的想法就是问题拆解。
比如说第一个提问就可以拆解成两个简单提问并进行求交。
另外比较前沿的方法就是text2sql,顾名思义就是用模型把自然语言转换成查询语句的,因为是端到端的所以十分便利,但目前该技术准确率还不够高,感兴趣的读者可以自己去了解学习。
除了复合问题以外,还存在其他类型的复杂提问。总之问答系统是一个对技术和业务能力都有一定要求的复杂场景,而且落地和维护也较为繁琐。
最后还是直观的展示下几个步骤,首先是代码
import re import sys from py2neo import Graph from template_method import TempMethod #链接neo4j图谱 graph = Graph("http://localhost:7474/", auth=("neo4j", '123456')) #加载问题模板 c = TempMethod(graph, 'D:/NLP相关/知识图谱/wow/code/wow/question_template.txt') #本次的问题 question = '伊利丹·怒风的种族是什么?' print("提问:\n%s\n"%(question)) #判断问题的大类 question_type = c.match(question) print("类别:\n%s\n"%(question_type)) #根据问题及分类进行关键词提取,并生成答案 query_res_list = c.generate_answer(question_type, question) print() #打印答案 print("答案:") for query_res in query_res_list: for d in query_res.data(): for key, val in d.items(): sys.stdout.write(val+"、")
输出效果:
提问:
伊利丹·怒风的种族是什么?
类别:
race
关键词提取:
['伊利丹·怒风']
['伊利丹']
答案:
恶魔、暗夜精灵(前)、
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。