300行python代码从零开始构建基于知识图谱的电影问答系统5-答案获取

啦啦啦,终于快写完了,虽然我也知道并没有写什么实质性的东西,至少我坚持下来啦,后面再慢慢多拧拧,少一些水分。

在上一篇中,主要介绍了如何从接收到的用户问题中抽取关键信息,以及如何识别用户的意图,那么接下来就将介绍在得到了这些信息后,如何在知识图谱中查询答案。我在处理这个问题时,想得很直接,简单来说,每个问题模板就对应了一个用户意图,那么就按照每个意图来写查询语句,这是一种简单粗暴的方法,优点就是就只有简单了,缺点当然很多了,比如不利于维护以及扩展等。现在要有维护扩展的意识,但是具体实现是,如果想快速实现一个demo的话,可以使用这种简单粗暴方法。下面就对获取答案进行介绍。

首先,我定义了一个问题模板的方法字典,每一个key对应模板的编号,value就是根据该模板来查询答案的方法,结构如下:

self.q_template_dict={
            0:self.get_movie_rating,
            1:self.get_movie_releasedate,
            2:self.get_movie_type,
            3:self.get_movie_introduction,
            4:self.get_movie_actor_list,
            5:self.get_actor_info,
            6:self.get_actor_act_type_movie,
            7:self.get_actor_act_movie_list,
            8:self.get_movie_rating_bigger,
            9:self.get_movie_rating_smaller,
            10:self.get_actor_movie_type,
            11:self.get_cooperation_movie_list,
            12:self.get_actor_movie_num,
            13:self.get_actor_birthday
        }

当我们得到用户问题,以及该问题的模板后需要做那些工作呢?
首先时利用上一篇介绍的方法来获取问题的关键信息,然后就根据模板编号来调用相应的方法,整体框架的代码如下:

    def get_question_answer(self,question,template):
        # 如果问题模板的格式不正确则结束
        assert len(str(template).strip().split("t"))==2
        template_id,template_str=int(str(template).strip().split("t")[0]),str(template).strip().split("t")[1]
        self.template_id=template_id
        self.template_str2list=str(template_str).split()

        # 预处理问题
        question_word,question_flag=[],[]
        for one in question:
            word, flag = one.split("/")
            question_word.append(str(word).strip())
            question_flag.append(str(flag).strip())
        assert len(question_flag)==len(question_word)
        self.question_word=question_word
        self.question_flag=question_flag
        self.raw_question=question
        # 根据问题模板来做对应的处理,获取答案
        answer=self.q_template_dict[template_id]()
        return answer

进入到对应的方法中,利用Cypher语言来构建查询语句,其基本形式是:

match(n)-[r] -(b)

Cypher语言不太懂没关系,也可以直接使用python的库py2neo来操作图数据库neo4j。这里只涉及到查询操作,所以我直接构造了Cypher查询语句,然后使用py2neo库的run方法来查询,数据库的链接和查询我单独的写了一个类,在需要的时候调用即可:

from py2neo import Graph,Node,Relationship,NodeMatcher

class Query():
    def __init__(self):
        self.graph=Graph("http://localhost:7474", username="neo4j",password="123456")

    # 问题类型0,查询电影得分
    def run(self,cql):
        # find_rela  = test_graph.run("match (n:Person{name:'张学友'})-[actedin]-(m:Movie) return m.title")
        result=[]
        find_rela = self.graph.run(cql)
        for i in find_rela:
            result.append(i.items()[0][1])
        return result

比如这里以查询某部电影的演员列表为例,查询答案的代码为:

# 4:nm 演员列表
    def get_movie_actor_list(self):
        movie_name=self.get_movie_name()
        cql = f"match(n:Person)-[r:actedin]->(m:Movie) where m.title='{movie_name}' return n.name"
        print(cql)
        answer = self.graph.run(cql)
        answer_set = set(answer)
        answer_list = list(answer_set)
        answer = "、".join(answer_list)
        final_answer = movie_name + "由" + str(answer) + "等演员主演!"
        return final_answer

主要是构造Cypher语句,然后调用py2neo的run方法,对得到的答案进行处理这几步,得到答案返回即可。

这个系列这里也就差不多了吧,除了目录,也只有4篇,所以这并不是一个很详细的教程,主要是想帮助大家对代码的理解,理清思路或者扰乱思路。在做试验的时候,我就是先理清思路再写的,这或许是一个不错的方法,由于这个教程不是很详细,大家有被我搅晕的地方,可以给我发邮件([email protected] )或者直接评论,也可以去网上找找资料。最后,这也是一个python版本,很好上手,大家不妨试一试。