前序文章:

  1. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part1项目介绍与环境准备
  2. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part2知识获取与图谱构建、服务搭建
  3. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part3前端搭建与可视化
  4. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part4检索人物关系实现
  5. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part5人物关系全貌与问答初入

任务说明

本部分则是整个项目的核心内容——基于图谱的问答。需要实现的是对于“简单问题”进行解析,然后从图谱数据库中查询与该人员及其相关人员信息,返回到前端并显示该人员的基本信息。除此之外,用户可以点击返回的结果人员节点,页面能够显示该用户的个人基本信息。那么现在就开始吧。

问答实现

根据源码实现问答形式,其实是比较简单的。原代码中使用ltp对问题进行分词,选取具有名次词性的关键词进行处理。
ltp配置稍许麻烦,我使用jieba分词工具对问题进行分词,然后再按照原文提取问句中人物及关系,然后构建cypher neo4j查询语句。最后将查询的数据进行格式化处理,返回给前端展示。

数据准备

其中源码中还提供了人物的相关信息,如中文名,英文名等等。我将该文件命令并放到:KGQAHLM/data/people_profile_file.json,其中的数据格式内容如下:

为了能够使得匹配的关系更具有泛化性,源码中也添加了一个关系的字典,内容样例如下:

为了对这些文件进行配置化管理,我进一步地完善了KGQAHLM/data/config.ini内容,如下:

[neo4j]
host=http://192.168.56.101
port=7474
user=neo4j
password=root[sys]
relation_path=data/relation.txt
# static dir
people_images_dir=people_images
people_profile_file_path=data/people_profile_file.json

对应的读取配置文件的类:KGQAHLP/utils/config.py的代码如下:

#!/usr/bin/python
# -*- coding: UTF-8 -*-
"""
@author: juzipi
@file: config.py
@time:2022/07/09
@description:
"""
import jsonfrom py2neo import Graph
from configparser import ConfigParserFAMILY_DICT = {"贾家荣国府": 0, "贾家宁国府": 1, "王家": 2, "史家": 3, "薛家": 4, "其他": 5, "林家": 6}SimilarWords = {"爸爸": "父亲","妈妈": "母亲","爸": "父亲","妈": "母亲","父亲": "父亲","母亲": "母亲","儿子": "儿子","女儿": "女儿","丫环": "丫环","兄弟": "兄弟","妻": "妻","老婆": "妻","哥哥": "哥哥","表妹": "表兄妹","弟弟": "弟弟","妾": "妾","养父": "养父","姐姐": "姐姐","娘": "母亲","爹": "父亲","father": "父亲","mother": "母亲","朋友": "朋友","爷爷": "爷爷","奶奶": "奶奶","孙子": "孙子","老公": "丈夫",'岳母': '岳母',"表兄妹": "表兄妹","孙女": "孙女","嫂子": "嫂子","暧昧": "暧昧"
}class SysConfig(object):__doc__ = """ system config """# 单例,全局唯一def __new__(cls, *args, **kwargs):if not hasattr(SysConfig, '_instance'):SysConfig._instance = object.__new__(cls)return SysConfig._instanceconfig_parser = ConfigParser()config_parser.read("./data/config.ini")NEO4J_HOST = config_parser.get("neo4j", 'host')NEO4J_PORT = int(config_parser.get("neo4j", 'port'))NEO4J_USER = config_parser.get("neo4j", 'user')NEO4J_PASSWORD = config_parser.get('neo4j', 'password')RELATION_PATH = config_parser.get('sys', 'relation_path')PEOPLE_IMAGES_DIR = config_parser.get('sys', 'people_images_dir')PEOPLE_PROFILE_FILE_PATH = config_parser.get('sys', 'people_profile_file_path')def load_profile_dict():with open(SysConfig.PEOPLE_PROFILE_FILE_PATH, 'r', encoding='utf8') as reader:person_profile_dict = json.load(reader)return person_profile_dictgraph = Graph(SysConfig.NEO4J_HOST + ":" + str(SysConfig.NEO4J_PORT),user=SysConfig.NEO4J_USER,password=SysConfig.NEO4J_PASSWORD)PersonProfile: dict = load_profile_dict()

前端准备

前端设计主要包含:问题输入框,结果图谱展示,节点人物信息展示。代码如下:
KGQAHLM/serve/templates/kgqa.html

{% extends 'layout_base.html' %}{% block title %} 问答系统 {% endblock %}{% block frame %}
<h4 class="text-main pad-btm bord-btm">问答系统</h4>
<div class="row"><div class="col-lg-6"><div class="input-group"><input type="text" id="search" class="form-control input-lg"placeholder="请输入你的问题(eg.贾宝玉的爸爸是谁?)"><span class="input-group-addon btn btn-primary" onclick="search()">搜索</span></div></div>
</div>
<div class="row" style="height: 40px;"></div>
<div class="row"><div class="col-lg-6" style="height: 400px;" id="guanxi"></div><div class="col-lg-1"></div><div class="col-lg-4"><div class="row" style="width:200px;height:200px;"><img id="picture" style="display:none;width:200px;height:200px;" src=""></div><div class="row"><div class="basic-info "><dl class="basicInfo-block basicInfo-left" id="profile"></dl></div></div></div>
</div>
{% endblock %}
{% block script %}
<script type="text/javascript">$(document).keypress(function (e) {if (e.which === 13) {  // 回车键事件search();}});window.onresize = function () {myChart.resize();}$.ajaxSetup({async: false});var myChart = echarts.init(document.getElementById("guanxi"));myChart.showLoading();myChart.hideLoading();option = {title: {textStyle: {// color: "white",fontWeight: "lighter",}},animationDurationUpdate: 1500,animationEasingUpdate: 'quinticInOut',legend: {x: "center",show: true,data: ["贾家荣国府", "贾家宁国府", "王家", "史家", "薛家", "其他", "林家"]},series: [{type: 'graph',layout: 'force',symbolSize: 50,edgeSymbol: ['circle', 'arrow'],edgeSymbolSize: [4, 4],edgeLabel: {normal: {show: true,textStyle: {fontSize: 10},formatter: "{c}"}},force: {repulsion: 2500,edgeLength: [10, 100]},focusNodeAdjacency: true,draggable: true,roam: true,categories: [{name: '贾家荣国府',}, {name: '贾家宁国府',}, {name: '王家',},{name: '史家',}, {name: '薛家',}, {name: '其他',},{name: '林家',}],label: {normal: {show: true,textStyle: {fontSize: 10},}},force: {repulsion: 1000},tooltip: {formatter: function (node) { // 区分连线和节点,节点上额外显示其他数字if (!node.value) {return node.data.name;} else {return node.data.name + ":" + node.data.showNum;}},},lineStyle: {normal: {opacity: 0.9,width: 1,curveness: 0.3}},// progressiveThreshold: 700,nodes: [],links: [],}]};myChart.on('click', function (params) {let url = '/get_profile/' + params.name;$.getJSON(url, {}, function (json) {$("#profile").html(json[0]);$("#picture").css("display", "block");let image_url = json[1];$("#picture").attr("src", "/static/"+ image_url);});});function search() {let url = '/KGQA_answer/' + $("#search").val();$.getJSON(url, {}, function (json) {if(JSON.stringify(json[0]) === '{}'){alert("系统智障中,还需进化,请重新提问");location.reload();}else{option.series[0].nodes = json[0].data.map(function (node, idx) {node.id = idx;return node;});option.series[0].links = json[0].links;myChart.setOption(option, true);let image_url = json[2];$("#profile").html(json[1]);$("#picture").css("display", "block");$("#picture").attr("src", "/static/" + image_url);}});}
</script>
{% endblock %}

接口实现

根据前端设计,后端主要实现两个接口。路由模块KGQAHLM/serve/search.py:

@bp.route("/KGQA_answer/<string:question>")
def KGQA_answer(question: str):json_data = search.answer_question(question)return jsonify(json_data)@bp.route("/get_profile/<string:name>")
def get_profile(name: str):return jsonify(search.get_answer_profile(name))

具体功能实现在KGQAHLM/KGQA/search.py中,如下:

import osfrom jieba import posseg
from utils.config import graph, FAMILY_DICT, SimilarWords, PersonProfile, SysConfigtarget_pos = ['nh', 'n', 'nr', 'r']def get_profile(name: str):s = ''for unit in PersonProfile.get(name, []):st = "<dt class = \"basicInfo-item name\" >" + str(unit) + " \<dd class = \"basicInfo-item value\" >" + str(PersonProfile[name][unit]) + "</dd >"s += streturn sdef convert2json(input_data: list):json_data = {"data": [], "links": []}d = []for record in input_data:d.append(record['p.name'] + "_" + record['p.family'])d.append(record['n.name'] + "_" + record['n.family'])d = list(set(d))name_dict, count = {}, 0for j in d:j_array = j.split("_")name_dict[j_array[0]] = countcount += 1json_data['data'].append({"name": j_array[0],"category": FAMILY_DICT.get(j_array[1], "")})for record in input_data:json_data['links'].append({"source": name_dict[record['p.name']],"target": name_dict[record['n.name']],"value": record['r.relation']})return json_datadef query_name(name: str):cypher = "match(p)-[r]->(n:Person{name:'%s'}) return  p.name, r.relation, n.name, p.family, n.family Union all\match(p:Person {name:'%s'}) -[r]->(n) return p.name, r.relation, n.name, p.family, n.family" % (name, name)data = list(graph.run(cypher))return convert2json(data)def answer_question(question: str):"""问答模块:param question::return:"""data_array, target_array = [], []for word_pos in posseg.lcut(question):if word_pos.flag in target_pos:target_array.append(word_pos.word)for i in range(len(target_array) - 2):if i == 0:name = target_array[0]else:name = data_array[-1]['p.name']cypher = "match(p)-[r:%s{relation: '%s'}]->(n:Person{name:'%s'}) return  p.name,n.name,r.relation,p.family,n.family" % (SimilarWords[target_array[i + 1]], SimilarWords[target_array[i + 1]], name)data = list(graph.run(cypher))data_array.extend(data)if data_array:result = [convert2json(data_array),get_profile(data_array[-1]['p.name']),os.path.join(SysConfig.PEOPLE_IMAGES_DIR, data_array[-1]['p.name']) + '.jpg']else:result = [{}, "", ""]return resultdef get_answer_profile(name: str):"""人员信息模块:param name::return:"""return [get_profile(name), os.path.join(SysConfig.PEOPLE_IMAGES_DIR, name + '.jpg')]

效果展示

效果展示如下。

总结

整个项目整体就是这么多了。后面的部分将会将代码进行优化,然后上传到github上,有兴趣的友友可以,查看。

对于知识图谱来说,内容还比较多。QA的内容也是比较多,上面的项目只能进行一些简单的回答,对于复杂的问题也需要做进一步处理。也会用到很多NLP等相关的知识。

除此之外,知识图谱构建的过程也是比较难的,涉及的知识、技术内容也比较多。后续将逐一深入剖析。

【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part6基于图谱的问答实现相关推荐

  1. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part7项目优化与打包

    前序文章: [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视化及问答系统实践:part1项目介绍与环境准备 [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视 ...

  2. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part4检索人物关系实现

    前序文章: [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视化及问答系统实践:part1项目介绍与环境准备 [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视 ...

  3. 【知识图谱】实践篇——基于知识图谱的《红楼梦》人物关系可视化及问答系统实践:part2知识获取与图谱构建、服务搭建

    前序文章: [知识图谱]实践篇--基于知识图谱的<红楼梦>人物关系可视化及问答系统实践:part1项目介绍与环境准备 知识获取与图谱构建 其中原项目提供了关系数据如下: 其中五列数据表示: ...

  4. 在图数据库Neo4j中创建红楼梦人物关系图谱

    在图数据库Neo4j中创建红楼梦人物关系图谱 1.加载csv数据文件 load csv from 'file:///triples.csv' as linecreate (:role {name:li ...

  5. neo4j的使用(以红楼梦人物关系为例)

    参考:知识图谱实战:构建红楼梦知识图谱_任萌新的小生活-CSDN博客_知识图谱构建实战https://blog.csdn.net/RHJlife/article/details/108586578 先 ...

  6. 华中科技大学--数据结构课程设计 ---红楼梦人物关系分析

    数据结构课程设计–<<基于社会网络分析技术的<红楼梦>人物关系分析>> 开发时间:2016-2017 第二学期华中科技大学 选题 – <题目二 基于社会网络分 ...

  7. python 红楼梦 人物关系_用Python来理一理红楼梦里的这些关系

    原标题:用Python来理一理红楼梦里的这些关系 最近把红楼梦又抽空看了一遍,古典中的经典,我真无法用言辞赞美她.今天,想跟大家一起用 Python 来理一理红楼梦中的的那些关系 不要问我为啥是红楼梦 ...

  8. HugeGraph图数据库构建红楼梦人物关系知识图谱实例

    HugeGraph是一款易用.高效.通用的开源图数据库系统(Graph Database,GitHub项目地址), 实现了Apache TinkerPop3框架及完全兼容Gremlin查询语言, 具备 ...

  9. 知识图谱实战1:构建红楼梦人物知识图谱

    一.安装Neo4j 在Windows环境中安装Neo4j 并创建两个节点和他们之间的关系 这个是先安装neo4j desktop 然后访问 brower 注意 : neo4j和jdk的版本要对应 ne ...

最新文章

  1. 第九期直播|《深度相机与应用》精彩回顾
  2. [杭电ACM]3336Count the string
  3. UVA10340子序列
  4. Spark 安装配置简单测试
  5. 搭建Nginx+Tomcat 负载均衡集群
  6. python小数乘法_Polymorph:支持几乎所有现有协议的实时网络数据包操作框架
  7. ffmpeg builds by zeranoe_FFmpeg
  8. Hive中Join的 MR 底层原理
  9. Linux 脚本编写基础(三)
  10. pandas如何去掉时间列的小时只保留日期
  11. 从CVPR2019看计算机视觉的最新趋势
  12. 采用Zigbee和Raspberry Pi的太阳能/燃气热水器自动控制系统
  13. Excel表格撤销工作表保护
  14. hadoop、hive搭建
  15. 伴着代码,那个女孩儿慢慢长大
  16. 熟练度=正确的知识 X 大量的刻意练习。
  17. node.js 实现简单爬虫批量下载喜马拉雅音频
  18. 计算机的硬盘类型及特点是,电脑硬盘中的蓝盘、黑盘、红盘、绿盘有什么区别?特点?...
  19. http系列---OpenSSL生成根证书CA及签发子证书
  20. AutoCAD 删除集合对象中的成员

热门文章

  1. 88E1111 100BASE-T百兆工程(part2--完)
  2. Google 黑板报: 哀悼与团结的曲线
  3. 关于QQ截图中马赛克处理的想法
  4. OpenJDK源码赏析之四(jli_util中的工具函数)
  5. ubuntu 轻量级图片编辑软件
  6. 【入门2】分支结构 P1422 小玉家的电费
  7. css3 简单的动画实现欢乐愉快的小鱼
  8. 【转】矩阵运算所满足的定律
  9. 〖Python 数据库开发实战 - Python与MySQL交互篇⑩〗- 创建新闻管理系统的具体python文件
  10. 负离子空气净化器哪个牌子好,空气净化器科普