这次想写一个知识图谱问答系列,从文本读取的知识图谱元素到智能处理的对话问答系统,涉及到实体识别、意图识别、槽位提取等技术。这里解释一下名词的含义。
实体识别:这个一般处理是正则表达式,或者是训练分类也就是BIO标签tag+softmax....有些人说是前者规则,后者学习。哈哈哈都行~~~
意图识别:就是判别这个问题是什么类型的问题,表示什么意思。比如,感冒可以吃什么药。我们可以知道这个问题是根据病来查吃什么药。。
槽位提取:就是对提的问题关键词进行提取,问题的关键词就是需要提取的槽位,上面一个例子,感冒就是槽位。
在介绍简单的概念后,正式开始今天的知识。主要步骤就是:构建图谱、分析问题类型(分类)、提取槽位、查询图谱。
初始化与neo4j的连接
读取数据文件
最后得到的就是,所有的实体,以及数据库关系而形成的实体间关系。这些字典数据将用于构建知识图谱。
建立节点、节点边的两个函数
其中涉及创建节点方法,通过py建立知识图谱。这里采用Node定义节点、create在neo4j中创建。——直接用Node创建
创建边的方法,通过query方法,首先"match(p:%s),(q:%s) where p.name='%s' and q.name='%s'匹配到两边节点,然后create (p)-[rel:%s{name:'%s'}]->(q)"创建边。——采用run query的方法创建。
就是对输入的文字判断其问题类型是什么。同时会提取对应实体的名称,也就是槽位。
步骤 1:输入文字,判断实体
步骤 2:判断意图,问题分类
步骤 3:组装json,送给search
步骤1:输入文字,判断实体
这里用到一个关键的问句过滤。本质上要做的是实体识别,这里直接采用知识的做法,而不是学习的方法。
知识的做法是,结合大量的实体知识文本、逐个去做匹配,得到对应实体,顺便完成了槽位提取。
学习的方法是,提前训练好一个CRF系列的实体识别网络,直接输出实体的句中位置,也就完成了槽位的提取。
关键点有3个:
1. region_tree提前把实体知识读取,构建加速树,形成(word,(index,word))
2. 提取槽位实体。在匹配到词后,需要进行长短同义词辨识去重(肝硬化、硬化就是长短同义词,会被重复识别,需要去重)
stop_wds取重复的短的词,如region_wds=['乙肝', '肝硬化', '硬化'],则stop_wds=['硬化'],这可以实现 '肝硬化', '硬化' 取一个
3. 对槽位实体进行归类,用于获取《槽位实体》词和词对应的实体类型
4. 上下文模式,记录上轮对话的槽位实体global disease_dict
最后就是得到了final_dict,就是需要的实体
步骤 2:判断意图,问题分类
提取的槽位就是medical_dict,根据该实体/实体类型,得到对应的问题予语义是什么意思,就是问题分类。以
# 推荐食品
if self.check_words(self.food_qwds, question) and 'disease' in types:
deny_status = self.check_words(self.deny_words, question)
if deny_status:
question_type = 'disease_not_food'
else:
question_type = 'disease_do_food'
if self.check_words(['能吃','能喝','可以吃','可以喝'], question):
question_types.append('disease_can_eat')
print(question_type)
question_types.append(question_type)
为例。分析问题类型,通过正则表达式匹配的思路,判断问句疑问词是否出现,对应到哪个问题类型。
步骤 3:组装json,送给search
data数据中包含args和question_types。如“乙肝怎么治疗”,得到的data如下:
{'args': {'乙肝': ['disease']}, 'question_types': ['disease_cureway']}
提取data中的args、question_type,创建cypher语句,用于查询图谱,得到的是一个sqls的JSON格式。包含questoin_type、sql,如下,
[{'question_type': 'disease_cureway', 'sql': ["MATCH (m:Disease) where m.name = '乙肝' return m.name, m.cure_way"]}]
查询语句执行后,对返回的结果进行拼装为答复结果。
其中根据question_type和查到的结果answer,调用回复模板,组装构成回复结果
至此就结束了,最后来看一下等待始终执行的主函数。