电影知识图谱问答(四)| 问句理解及答案推理

上篇文章《电影知识图谱问答(三)|Apache Jena知识存储及SPARQL知识检索》中讲到如何将处理后的RDF数据存储至Apache Jena数据库之中、如何利用SPARQL语句从Apache Jena之中进行知识检索和答案推理。本篇文章将主要介绍如何理解问句所表达的深层语义含义、如何将自然语言问句转换成SPARQL查询语句、如何进行答案推理


上篇文章讲到利用SPARQL语句能够从Apache Jena数据库之中检索得到问题答案,那么如果想要构建电影知识图谱问答系统,亟需解决的问题就是如何将自然语言问句转换成SPARQL查询语句。比如问句“流浪地球的主演有哪些?”,转换成如下SPARQL查询语句需要经过哪些步骤呢?

PREFIX : <http://www.douban_kgqa.com#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT ?x WHERE {
  ?s :movie_info_name '流浪地球'.
  ?s :has_actor ?a.
  ?a :movie_person_name ?x.
}
LIMIT 25

1. 问句理解

针对用户提问的自然语言问句,首先需要理解其中的深层次语义信息,即获取问句实体和目标属性信息。以问句“流浪地球的导演是谁?”为例,其问句实体是流浪地球、目标属性是导演,所采用的方法分别是实体识别和属性链接。

1.1 实体识别

从问句中提取出实体可以采用以下两种方法:1)构建诸如BiLSTM-CRF(https://arxiv.org/pdf/1508.01991.pdf)等深度学习模型,然后利用训练好的深度学习模型预测出问句实体。2)构建实体词表,从问句中提取词表中所包含的实体。

第一种深度学习方法,能够预测得到训练数据中未出现过的电影名称,预测准确率保持在90%以上。缺点是需要构建训练数据,从头开始训练深度学习模型,耗费时间长;第二种词表方法,构建快捷方便,缺点是只能够发现词表中包含的电影实体名称,无法发现新的电影实体。

比较推荐的方法是词表+BiLSTM-CRF深度学习模型,但此处为了构建方便,只采用词表方法。词表构建方法是从爬取的数据之中,选出其中的电影和书籍名称人物名称加入到词表之中。另外,有兴趣的朋友,可加上深度学习预测模型。BiLSTM-CRF模型在GitHub上有很多,可自主寻找。

1.2 属性链接

属性链接可以采用以下两种方法:1)构建诸如CNN等多分类深度学习模型,然后利用训练好的深度学习模型预测问句的目标属性。2)构建关键词集合,把问句中所包含的关键词当作问句的目标属性。

同样,此处为了方便,直接采用关键词方法。有兴趣的朋友,可自主加上CNN等多分类预测模型。CNN等多分类模型GitHub上有很多,此处不再介绍。

需要注意的是,同一目标属性可以表达成多种含义。比如流浪地球的评分是多少?、也可以表达成流浪地球在豆瓣有多少分数?,那么此时我们就需要同时考虑评分分数关键词。

rating = (W('评分') | W('分数'))  # 评分

2. 答案推理

2.1基于规则的答案推理

获取问句的实体和目标属性之后,便可根据规则模版将传统自然语言问句转换得到SPARQL查询语句,进而从Apache Jena数据库之中推理得到问题答案。构建规则模型可利用Python Refo库进行构建,比如构建某某电影的导演是谁?模糊匹配规则,方法如下所示。

movie_info_rules = [
    Rule(condition_num=1,condition=(book_or_movie_entity + Star(Any(), greedy=False) + director + Star(Any(), greedy=False)) | (writer + Star(Any(), greedy=False) + book_or_movie_entity) + Star(Any(), greedy=False), action=QuestionSet.has_director)
]

模糊匹配规则中has_director为SPARQL检索语句转换函数,函数定义方法如下所示。

SPARQL_PREFIX = u"""PREFIX : <http://www.douban_kgqa.com#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX owl: <http://www.w3.org/2002/07/owl#> #某电影有哪些导演
"""

SPARQL_SELECT_TEM = u"{prefix}\n" + \
                    u"SELECT DISTINCT {select} WHERE {{\n" + \
                    u"{expression}\n" + \
                    u"}}\n"

def has_director(word_objects):
        """
        某电影有哪些导演
        :param word_objects:
        :return:
        """
        select = u"?x"
        sparql = None
        for w in word_objects:
            if w.pos == pos_book_or_movie:
                e = u"?m :movie_info_name '{movie}'.\n" \
                    u"?m :has_director ?a.\n" \
                    u"?a :movie_person_name ?x".format(movie=w.token)

                sparql = SPARQL_SELECT_TEM.format(prefix=SPARQL_PREFIX,
                                                  select=select,
                                                  expression=e)
                break

        return sparql

通过上述规则模版,能够处理以下类型的简单问句。

# 某电影的图片/上映地区/语言/上映时间/时长/其他名称/介绍/评分/ 评价人数
# 某电影的类型
# 某电影有哪些演员
# 某电影有哪些编剧
# 某电影有哪些导演
# 某电影的详细信息

# 某人的图片/性别/星座/生日/出生地/职业/其他名称/介绍/
# 某人演了哪些电影
# 某人写了哪些电影
# 某人指导了哪些电影
# 某人的详细信息

当然,也可以处理以下类型的复杂问句,但规则模版构建比较复杂。

# 某电影的评分是否大于8
# 哪些喜剧电影的评分小于4
# ...

# 某人出演了多少部电影
# 某演员参演的评分大于X的电影有哪些
# 某演员出演过哪些类型的电影
# 演员A和演员B合作出演了哪些电影
# ...

将问句转换成SPARQL查询语句之后,便可从Apache Jena之中检索得到问句答案,查询代码如下所示。另外,为提高推理的准确率,还可以对《电影知识图谱问答(三)|Apache Jena知识存储及SPARQL知识检索》中所介绍的自定义推理规则进行补充。

# -*- coding:utf-8 -*-

"""
jena fuseki查询
"""

from collections import OrderedDict
from SPARQLWrapper import SPARQLWrapper, JSON


class SparqlQuery:
    """
    SPARQL 查询
    """

    def __init__(self, endpoint_url='http://localhost:3030/douban_kgqa/query'):
        """
        初始化链接
        :param endpoint_url:
        """
        self.sparql_conn = SPARQLWrapper(endpoint_url)

    def get_sparql_result(self, query):
        """
        根据查询条件,得到查询结果
        :param query:
        :return:
        """
        self.sparql_conn.setQuery(query)
        self.sparql_conn.setReturnFormat(JSON)
        return self.sparql_conn.query().convert()

    @staticmethod
    def parse_result(query_result):
        """
        解析返回的结果
        :param query_result:
        :return:
        """
        try:
            query_head = query_result['head']['vars']
            query_results = []
            for r in query_result['results']['bindings']:
                temp_dict = OrderedDict()
                for h in query_head:
                    temp_dict[h] = r[h]['value']
                query_results.append(temp_dict)
            return query_head, query_results
        except Exception as err:
            print('解析结果错误' + str(err))

    def get_sparql_result_value(self, query_result):
        """
        列表存储结果值
        :param query_result:
        :return:
        """
        query_head, query_result = self.parse_result(query_result)
        if query_head is None:
            return query_result
        else:
            values = []
            for qr in query_result:
                for _, value in qr.items():
                    values.append(value)
            return values

2.2 基于表示学习的答案推理

通过问句理解模块,能够得到问句的实体和目标属性信息。然后结合基于模版的答案推理方法,能够将问句转换成SPARQL查询语句,进而在Apache Jena数据库之中推理得到问题答案。但基于规则的答案推理仅能够处理已定义的规则,不能覆盖问句的所有情况。而我们又不能定义所有规则,这应该怎么处理呢?

这时,可以采用基于表示学习的答案推理方法,比如知识图谱嵌入中经典的Trans系列方法。这里我们以TransE(https://www.utc.fr/~bordesan/dokuwiki/_media/en/transe_nips13.pdf)为例进行解释,知识图谱中三元组向量化后可以表示为<h, r, t>,其中头实体为h、关系为r、尾实体为t。TransE假设实体和关系之间存在h+r ≈ t,即头实体h加上关系r的向量信息近似等于尾实体,那么我们便能够通过头实体和关系预测得到尾实体。也就是说,能够通过问句中实体和目标属性信息,预测得到问句答案。

此处对TransE原理内容不进行过多介绍,有兴趣的朋友可以去看论文。TransE训练代码可以从thunlp/OpenKE(https://github.com/thunlp/OpenKE)获取,训练数据可以从已爬取的豆瓣数据中抽取,训练完成后便可结合问句理解模块进行答案预测。

3. 总结

本篇文章介绍了如何理解问句深层次语义信息、如何将自然语言问句转换成SPARQL查询语句、如何利用TransE表示学习进行答案预测。至此,通过【、四(本文)】几篇文章的介绍,我们已经了解如何从豆瓣官网中爬取数据;如何将爬取的数据转换得到可用的三元组数据,并存储至Apache Jena之中;如何利用SPARQL查询语言进行知识检索和答案推理;如何理解问句所表达的深层语义信息,即获取问句实体和目标属性信息;如何利用问句的深层语义信息,结合规则和表示学习方法,推理得到问题答案。结合上面几篇文章,已经能够从零开始构建一个电影知识图谱问答系统,有兴趣的朋友可以尝试构建。

下篇文章,将介绍如何将电影知识图谱问答系统部署至微信公众平台,并利用微信公众号进行知识问答,构建一个完整的知识图谱问答系统Demo。

原文发布于微信公众号 - 谓之小一(weizhixiaoyi)

原文发表时间:2019-08-11

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

扫码关注云+社区

领取腾讯云代金券