零基础搭建基于知识图谱的电影问答系统

news2025/1/21 11:32:47

零基础搭建基于知识图谱的电影问答系统

    • 一、项目准备
    • 二、项目数据
    • 三、训练问题分类器
    • 四、准备问答模板
    • 五、搭建webapp
    • 六、问题预处理

一、项目准备

  1. 首先需要一款python编译器,本人选用的是PyCharm,搭建好Python环境;
  2. 安装第三方依赖库,源码文件夹中的requirements.txt文件中说明了需要用到的第三方库和对应版本;
  3. 本项目采用图数据库进行存储,利用Neo4j图像数据库,可以参照本人博客:全网最详细的Neo4j安装教程进行安装。

那么至此,Python环境和知识图谱的存储环境已经搭建完成,接下来需要获取数据。

二、项目数据

数据采用的是IMDB互联网电影资料库中的数据,IMDB是一个关于电影演员、电影、电视节目、电视明星和电影制作的在线数据库,包括了影片的众多信息、演员、片长、内容介绍、分级、评论等。对于电影的评分使用最多的就是IMDb评分。
利用爬虫获取数据如下:
在这里插入图片描述
其中movie、person、genre为数据表,movie_to_genre、person_to_movie两张关系表建立起电影与类型、电影与角色之间的关系。表中相关字段如下:
1.movie.csv(mid:电影序号;title:电影标题;introduction:电影简介;rating:电影评分;releasedate:发布日期)
在这里插入图片描述
2.person.csv(pid:演员序号;birth:出生日期;death:离世日期;name:演员姓名;biography:生平简介;birthplace:出生地)
在这里插入图片描述
3.person_to_movie.csv(pid:演员序号;mid:电影序号)
在这里插入图片描述4.genre.csv(gid:类型序号;gname:类型名称)
在这里插入图片描述
5.movie_to_genre.csv(mid:电影序号;gid:角色序号)
在这里插入图片描述
数据获取完成后,将其导入Neo4j图形数据库中。
1.首先将五张数据表放入Neo4j安装目录中的import文件夹下
在这里插入图片描述
2.打开Neo4j,依次执行以下代码
建立连接,此时经常会连接不上,原因是7474端口被占用,查看被占用端口:netstat -ano |findstr 7474
在这里插入图片描述
关闭端口:taskkill /t /f /pid 9244
在这里插入图片描述
(1)导入电影类型genre.csv

//导入节点 电影类型  == 注意类型转换
LOAD CSV WITH HEADERS  FROM "file:///genre.csv" AS line
MERGE (p:Genre{gid:toInteger(line.gid),name:line.gname})

在这里插入图片描述
在这里插入图片描述
(2)导入演员数据person.csv

//导入节点 演员信息	
LOAD CSV WITH HEADERS FROM 'file:///person.csv' AS line
CREATE (p:Person { pid:toInteger(line.pid),birth:line.birth,
death:line.death,name:line.name,
biography:line.biography,
birthplace:line.birthplace})

在这里插入图片描述
在这里插入图片描述
(3)导入电影数据movie.csv

// 导入节点 电影信息
LOAD CSV WITH HEADERS  FROM "file:///movie.csv" AS line  
MERGE (p:Movie{mid:toInteger(line.mid),title:line.title,introduction:line.introduction,
rating:toFloat(line.rating),releasedate:line.releasedate})

在这里插入图片描述
在这里插入图片描述
(4)创建电影与演员之间的关系person_to_movie.csv

// 创建电影与演员之间的关系 actedin  电影是谁参演的 1对多
LOAD CSV WITH HEADERS FROM "file:///person_to_movie.csv" AS line 
match (from:Person{pid:toInteger(line.pid)}),(to:Movie{mid:toInteger(line.mid)})  
merge (from)-[r:actedin{pid:toInteger(line.pid),mid:toInteger(line.mid)}]->(to)

在这里插入图片描述
在这里插入图片描述

(5)创建电影与类型之间的关系movie_to_genre.csv

//导入关系  电影是什么类型 == 1对多
LOAD CSV WITH HEADERS FROM "file:///movie_to_genre.csv" AS line
match (from:Movie{mid:toInteger(line.mid)}),(to:Genre{gid:toInteger(line.gid)})  
merge (from)-[r:is{mid:toInteger(line.mid),gid:toInteger(line.gid)}]->(to)

在这里插入图片描述
在这里插入图片描述
至此,知识图谱的数据存储已经建立完毕!
在这里插入图片描述

三、训练问题分类器

针对用户提出的不同问题,需要给与对应的答案,因此需要对问题进行分类。如何识别用户的问题属于那一类,因此需要选择分类器,训练分类器的数据可以从github中下载:https://gitcode.net/mirrors/irvingbei/simple_movie_qa_with_kg?utm_source=csdn_github_accelerator
在这里插入图片描述

四、准备问答模板

在这里插入图片描述
在这里插入图片描述

五、搭建webapp

基于下图目录结构,将文件资源导入即可
在这里插入图片描述
在这里插入图片描述

六、问题预处理

输入框接收到用户提出的问题后,首先需要获取问题中的询问对象是什么,即主语,是人还是电影,这就涉及到自然语言处理中的命名实体识别;接着还需要从问题中了解到用户的意图,这就涉及到文本表示问题,最基本的文本表示方法是one-hot形式,在项目中使用的是sklearn中的TF-IDF工具。

1.关键信息抽取

通过命名实体识别来获取用户问题中的人名,电影名等信息,在本项目中,通过词性标注工具可以把人名标注出来,通过自定义字典,把所涉及到的所有电影,所有人名和所有电影类型名称都加到了这个字典中,jieba分词的时候就会参考字典里面的词来进行分词和词性标注了,自定义词典的格式如下:

# 电影名称 nm
Forrest Gump 15 nm
Kill Bill: Vol. 1 15 nm
英雄 15 nm
......
# 演员名称 nr
张学友 15 nr
刘德华 15 nr
林雪 15 nr
......
# 电影类型 ng
冒险 15 ng
奇幻 15 ng
动画 15 ng
......

分词与词性标注同步进行,代码实现如下:

        def question_posseg(self):
        # 加载自定义词库
        jieba.load_userdict("./data/userdict3.txt")
        # 去除问题中的特殊符号
        clean_question = re.sub("[\s+\.\!\/_,$%^*(+\"\')]+|[+——()?【】“”!,。?、~@#¥%……&*()]+","",self.raw_question)
        self.clean_question=clean_question
        # 调用jieba 进行分词
        # 例如 clean_question = '章子怡的生日'
        question_seged=jieba.posseg.cut(str(clean_question))
        result=[]
        question_word, question_flag = [], []
        for w in question_seged:
            # '章子怡/nr' 每一个word后拼接 / 词性
            temp_word=f"{w.word}/{w.flag}"
            result.append(temp_word)
            # 预处理问题
            word, flag = w.word,w.flag
            print('word:', word)
            print('flag:' ,flag)
            question_word.append(str(word).strip())
            print('question_word:', question_word)
            question_flag.append(str(flag).strip())
            print('question_flag:', question_flag)
        # 最终得到 question_word: ['章子怡', '的', '生日'] 对应 question_flag: ['nr', 'uj', 't']
        assert len(question_flag) == len(question_word) # 两个列表长度相等
        self.question_word = question_word
        self.question_flag = question_flag
        print(result) # ['章子怡/nr', '的/uj', '生日/t']
        return result

2.问题分类和模板填充

接下来需要对用户的问题进行分类,获取对应问题模板,从而明白用户的意图,首先要根据用户习惯构造的各种各样的问题来训练一个分类器,该项目使用的sklearn中的贝叶斯分类器。

(1)获取训练数据:

# 获取训练数据
    def read_train_data(self):
        # 存放抽象问题
        train_x=[]
        # 存放抽象问题 对应的类别序号 0-13
        train_y=[]
        # 读入所有的问题分类数据 0-13
        file_list=getfilelist("./data/question/")
        # 遍历所有文件
        for one_file in file_list:
            # 获取文件名中的数字
            num = re.sub(r'\D', "", one_file)
            # 如果该文件名有数字,则读取该文件
            if str(num).strip()!="":
                # 设置当前文件下的数据标签
                label_num=int(num)
                # 读取文件内容
                with(open(one_file,"r",encoding="utf-8")) as fr:
                    data_list=fr.readlines()
                    for one_line in data_list:
                        word_list=list(jieba.cut(str(one_line).strip()))
                        # 将这一行加入结果集
                        train_x.append(" ".join(word_list))
                        train_y.append(label_num)
                    print(train_x) # 问题列表
                    print(train_y) # 问题序号列表
        return train_x,train_y
['nm 的 评分 是 多少', 'nm 得 了 多少 分', 'nm 的 评分 有 多少', 'nm 的 评分', 'nm 的 分数 是', 'nm 电影 分数 是 多少', 'nm 评分', 'nm 的 分数 是 多少', 'nm 这部 电影 的 评分 是 多少', 'nnt 演过 哪些 风格 的 电影', 'nnt 演过 的 电影 都 有 哪些 风格', 'nnt 演过 的 电影 有 哪些 类型', 'nnt 演过 风格 的 电影', 'nnt 演过 类型 的 电影', 'nnt 演过 题材 的 电影', '\ufeff nnt 和 nnr 合作 的 电影 有 哪些', 'nnt 和 nnr 一起 拍 了 哪些 电影', 'nnt 和 nnr 一起 演 过 哪些 电影', 'nnt 与 nnr 合拍 了 哪些 电影', 'nnt 和 nnr 合作 了 哪些 电影', '\ufeff nnt 一共 参演 过 多少 电影', 'nnt 演过 多少 部 电影', 'nnt 演过 多少 电影', 'nnt 参演 的 电影 有 多少', 'nnt 的 出生日期', 'nnt 的 生日', 'nnt 生日 多少', 'nnt 的 出生 是 什么 时候', 'nnt 的 出生 是 多少', 'nnt 生日 是 什么 时候', 'nnt 生日 什么 时候', 'nnt 出生日期 是 什么 时候', 'nnt 什么 时候 出生 的', 'nnt 出 生于 哪一天', 'nnt 的 出生日期 是 哪一天', 'nnt 哪一天 出生 的', 'nm 的 上映 时间 是 什么 时候', 'nm 的 首映 时间 是 什么 时候', 'nm 什么 时候 上映', 'nm 什么 时候 首映', 'nm 什么 时候 在 影院 上线', '什么 时候 可以 在 影院 看到 nm', 'nm 什么 时候 在 影院 放映', 'nm 什么 时候 首播', 'nm 的 风格 是 什么', 'nm 是 什么 风格 的 电影', 'nm 的 格调 是 什么', 'nm 是 什么 格调 的 电影', 'nm 是 什么 类型 的 电影', 'nm 的 类型 是 什么', 'nm 是 什么 类型 的', 'nm 的 剧情 是 什么', 'nm 主要 讲 什么 内容', 'nm 的 主要 剧情 是 什么', 'nm 主要 讲 什么 故事', 'nm 的 故事 线索 是 什么', 'nm 讲 了 什么', 'nm 的 剧情简介', 'nm 的 故事 内容', 'nm 的 主要 情节', 'nm 的 情节 梗概', 'nm 的 故事梗概', 'nm 有 哪些 演员 出演', 'nm 是 由 哪些 人演 的', 'nm 中 参演 的 演员 都 有 哪些', 'nm 中 哪些 人演 过', 'nm 这部 电影 的 演员 都 有 哪些', 'nm 这部 电影 中 哪些 人演 过', 'nnt', 'nnt', 'nnt', 'nnt', 'nnt', 'nnt 是', 'nnt 是 谁', 'nnt 的 介绍', 'nnt 的 简介', '谁 是 nnt', 'nnt 的 详细信息', 'nnt 的 信息', 'nnt 演过 哪些 ng 电影', 'nnt 演 哪些 ng 电影', 'nnt 演过 ng 电影', 'nnt 演过 什么 ng 电影', 'nnt 演过 ng 电影', 'nnt 演过 的 ng 电影 有 哪些', 'nnt 出演 的 ng 电影 有 哪些', 'nnt 演了 什么 电影', 'nnt 出演 了 什么 电影', 'nnt 演过 什么 电影', 'nnt 演过 哪些 电影', 'nnt 过去 演 过 哪些 电影', 'nnt 以前 演 过 哪些 电影', 'nnt 演过 的 电影 有 什么', 'nnt 有 哪些 电影', '\ufeff nnt 参演 的 评分 大于 x 的 电影 有 哪些', 'nnt 参演 的 电影 评分 大于 x 的 有 哪些', 'nnt 参演 的 电影 评分 超过 x 的 有 哪些', 'nnt 演 的 电影 评分 超过 x 的 有 哪些', 'nnt 演 的 电影 评分 大于 x 的 都 有 哪些', 'nnt 演 的 电影 评分 在 x 以上 的 都 有 哪些', '\ufeff nnt 参演 的 评分 小于 x 的 电影 有 哪些', 'nnt 参演 的 电影 评分 小于 x 的 有 哪些', 'nnt 参演 的 电影 评分 低于 x 的 有 哪些', 'nnt 演 的 电影 评分 低于 x 的 有 哪些', 'nnt 演 的 电影 评分 小于 x 的 都 有 哪些', 'nnt 演 的 电影 评分 在 x 以下 的 都 有 哪些']
[0, 0, 0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9]

(2)训练多分类贝叶斯分类器模型

# 训练并测试模型-NB
    def train_model_NB(self):
        X_train, y_train = self.train_x, self.train_y
        # 调用sklearn中的TF-IDF
        self.tv = TfidfVectorizer()
        # fit_transform(trainData)对部分数据先拟合fit,找到该part的整体指标,
        # 如均值、方差、最大值最小值等等(根据具体转换的目的),
        # 然后对该trainData进行转换transform,从而实现数据的标准化、归一化等等。
        train_data = self.tv.fit_transform(X_train).toarray()
        # alpha:浮点型,可选项,默认1.0,添加拉普拉斯/Lidstone平滑参数。
        # 当α=1时,称作Laplace平滑,当0<α<1时,称作Lidstone平滑,α=0时不做平滑。
        # MultinomialNB多项式朴素贝叶斯
        clf = MultinomialNB(alpha=0.01)
        clf.fit(train_data, y_train)
        return clf

(3)利用训练好的模型来对新问题进行分类预测

# 预测
    def predict(self,question):
        # 对问题进行分词
        question=[" ".join(list(jieba.cut(question)))]
        # 将问题输入转换为词向量矩阵
        test_data=self.tv.transform(question).toarray()
        # 调用模型完成预测 返回问题编号 0 - 13
        y_predict = self.model.predict(test_data)[0]
        print("question type:",y_predict)
        return y_predict

在这里插入图片描述
返回用户问题所属的类别编号,这个编号也就对应一个问题模板:

0:nm 评分
1:nm 上映时间
2:nm 类型
3:nm 简介
4:nm 演员列表
5:nnt 介绍
6:nnt ng 电影作品
7:nnt 电影作品
8:nnt 参演评分 大于 x
9:nnt 参演评分 小于 x
10:nnt 电影类型
11:nnt nnr 合作 电影列表
12:nnt 电影数量
13:nnt 出生日期

(4)替换模板中的抽象内容

数字和模板的对应关系可以提前存到一个字典中,当预测出编号后,直接通过这个编号作为字典的key值,value就是根据该模板来查询答案的方法,这样就查询出问题模板了。比如预测的结果是2,则对应的问题模板 nm 类型,表示询问某部电影的类型,再结合前一阶段获取的电影名字,则可以组成一个新的问题,比如:

    def __init__(self):
        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,# 演员的参演评分大于x
            9:self.get_movie_rating_smaller,# 演员的参演评分小于x
            10:self.get_actor_movie_type,# 电影类型
            11:self.get_cooperation_movie_list,# 合作的电影列表
            12:self.get_actor_movie_num, # 电影数量
            13:self.get_actor_birthday# 演员出生日期
        }
肖申克的救赎 类型

3.答案获取
在已知问题和答案模板之后,可以通过调用对应的方法得到结果。在对应的方法中,利用Cypher语言来构建查询语句,其基本形式是:

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

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

#-*- coding: UTF-8 -*-
# @Time    : 2022/11/14
# @Author  : zgf
# @Site    : 
# @File    : query.py
# @Software: PyCharm
from py2neo import Graph,Node,Relationship,NodeMatcher
class Query():
    def __init__(self):
        # self.graph=Graph("http://localhost:7474", username="neo4j",password="090711zgf")
        # 连接图形数据库用户名和密码
        self.graph=Graph("http://localhost:7474", auth=("neo4j", "090711zgf"))
    # 问题类型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
# if __name__ == '__main__':
#     SQL=Query()
#     result=SQL.run("match (m:Movie)-[]->() where m.title='卧虎藏龙' return m.rating")
#     print(result)

那么接下来就是13个问题对应的实现方法,主要是构造Cypher查询语句

(1)获取电影评分

# 0:nm 电影评分
    def get_movie_rating(self):
        # 获取电影名称,这个是在原问题中抽取的
        movie_name=self.get_movie_name()
        # cql语句
        # match 从数据库获取有关节点、关系和属性的数据 相当于查询
        # match (节点的名称:节点标签名称)
        # -[<relationship-label-name>:<relationship-name>]关系的名称:关系的标签名称
        # where : Neo4j CQL在CQL match命令中提供了where子句来过滤MATCH查询的结果
        # WHERE <condition> 其中condition语法为:<property-name> <comparison-operator> <value> cql比较运算符
        # return m的电影评分
        cql = f"match (m:Movie)-[]->() where m.title='{movie_name}' return m.rating"
        print(cql)
        # 执行sql语句
        answer = self.graph.run(cql)[0]
        print(answer)
        answer = round(answer, 2) # 用于数字的四舍五入,保留两位小数
        final_answer=movie_name+"电影评分为"+str(answer)+"分!"
        return final_answer

(2)上映时间

# 1:nm 上映时间
    def get_movie_releasedate(self):
        movie_name = self.get_movie_name()
        cql = f"match(m:Movie)-[]->() where m.title='{movie_name}' return m.releasedate"
        print(cql)
        answer = self.graph.run(cql)[0]
        final_answer = movie_name + "的上映时间是" + str(answer) + "!"
        return final_answer

(3)电影类型

# 2:nm 类型
    def get_movie_type(self):
        movie_name = self.get_movie_name()
        cql = f"match(m:Movie)-[r:is]->(b) where m.title='{movie_name}' return b.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

(4)电影简介

# 3:nm 简介
    def get_movie_introduction(self):
        movie_name = self.get_movie_name()
        cql = f"match(m:Movie)-[]->() where m.title='{movie_name}' return m.introduction"
        print(cql)
        answer = self.graph.run(cql)[0]
        final_answer = movie_name + "主要讲述了" + str(answer) + "!"
        return final_answer

(5)演员列表

# 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

(6)演员介绍

# 5:nnt 介绍
    def get_actor_info(self):
        actor_name = self.get_name('nr')
        cql = f"match(n:Person)-[]->() where n.name='{actor_name}' return n.biography"
        print(cql)
        answer = self.graph.run(cql)[0]
        final_answer = answer
        return final_answer

(7)演员出演作品类型

# 6:nnt ng 电影作品
    def get_actor_act_type_movie(self):
        actor_name = self.get_name("nr")
        type=self.get_name("ng")
        # 查询电影名称
        cql = f"match(n:Person)-[]->(m:Movie) where n.name='{actor_name}' return m.title"
        print(cql)
        movie_name_list = list(set(self.graph.run(cql)))
        # 查询类型
        result=[]
        for movie_name in movie_name_list:
            movie_name=str(movie_name).strip()
            try:
                cql=f"match(m:Movie)-[r:is]->(t) where m.title='{movie_name}' return t.name"
                # print(cql)
                temp_type=self.graph.run(cql)
                if len(temp_type)==0:
                    continue
                if type in temp_type:

                    result.append(movie_name)
            except:
                continue
        answer="、".join(result)
        print(answer)
        final_answer = actor_name+"演过的"+type+"电影有:\n"+answer+"。"
        return final_answer

(8)演员出演作品

# 7:nnt 电影作品
    def get_actor_act_movie_list(self):
        actor_name = self.get_name("nr")
        answer_list=self.get_actorname_movie_list(actor_name)
        answer = "、".join(answer_list)
        final_answer = actor_name + "演过" + str(answer) + "等电影!"
        return final_answer
    def get_actorname_movie_list(self,actorname):
        # 查询电影名称
        cql = f"match(n:Person)-[]->(m:Movie) where n.name='{actorname}' return m.title"
        print(cql)
        answer = self.graph.run(cql)
        answer_set = set(answer)
        answer_list = list(answer_set)
        return answer_list

(9)作品评分

    def get_movie_rating_bigger(self):
        actor_name=self.get_name('nr')
        x=self.get_num_x()
        cql = f"match(n:Person)-[r:actedin]->(m:Movie) where n.name='{actor_name}' and m.rating>={x} return m.title"
        print(cql)
        answer = self.graph.run(cql)
        answer = "、".join(answer)
        answer = str(answer).strip()
        final_answer=actor_name+"演的电影评分大于"+x+"分的有"+answer+"等!"
        return final_answer
    def get_movie_rating_smaller(self):
        actor_name = self.get_name('nr')
        x = self.get_num_x()
        cql = f"match(n:Person)-[r:actedin]->(m:Movie) where n.name='{actor_name}' and m.rating<{x} return m.title"
        print(cql)
        answer = self.graph.run(cql)
        answer = "、".join(answer)
        answer = str(answer).strip()
        final_answer = actor_name + "演的电影评分小于" + x + "分的有" + answer + "等!"
        return final_answer

(10)其他问题

    def get_actor_movie_type(self):
        actor_name = self.get_name("nr")
        # 查询电影名称
        cql = f"match(n:Person)-[]->(m:Movie) where n.name='{actor_name}' return m.title"
        print(cql)
        movie_name_list = list(set(self.graph.run(cql)))
        # 查询类型
        result = []
        for movie_name in movie_name_list:
            movie_name = str(movie_name).strip()
            try:
                cql = f"match(m:Movie)-[r:is]->(t) where m.title='{movie_name}' return t.name"
                # print(cql)
                temp_type = self.graph.run(cql)
                if len(temp_type) == 0:
                    continue
                result+=temp_type
            except:
                continue
        answer = "、".join(list(set(result)))
        print(answer)
        final_answer = actor_name + "演过的电影有" + answer + "等类型。"
        return final_answer
    def get_cooperation_movie_list(self):
        # 获取演员名字
        actor_name_list=self.get_name('nr')
        movie_list={}
        for i,actor_name in enumerate(actor_name_list):
            answer_list=self.get_actorname_movie_list(actor_name)
            movie_list[i]=answer_list
        result_list=list(set(movie_list[0]).intersection(set(movie_list[1])))
        print(result_list)
        answer="、".join(result_list)
        final_answer=actor_name_list[0]+"和"+actor_name_list[1]+"一起演过的电影主要是"+answer+"!"
        return final_answer

    def get_actor_movie_num(self):
        actor_name=self.get_name("nr")
        answer_list=self.get_actorname_movie_list(actor_name)
        movie_num=len(set(answer_list))
        answer=movie_num
        final_answer=actor_name+"演过"+str(answer)+"部电影!"
        return final_answer

(11)演员生日

    def get_actor_birthday(self):
        actor_name = self.get_name('nr')
        cql = f"match(n:Person)-[]->() where n.name='{actor_name}' return n.birth"
        print(cql)
        answer = self.graph.run(cql)[0]
        final_answer = actor_name+"的生日是"+answer+"。"
        return final_answer

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/40713.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Hack The Box】linux练习-- Delivery

HTB 学习笔记 【Hack The Box】linux练习-- Delivery &#x1f525;系列专栏&#xff1a;Hack The Box &#x1f389;欢迎关注&#x1f50e;点赞&#x1f44d;收藏⭐️留言&#x1f4dd; &#x1f4c6;首发时间&#xff1a;&#x1f334;2022年11月17日&#x1f334; &#x1…

黄佳《零基础学机器学习》chap1笔记

黄佳 《零基础学机器学习》 chap1笔记 这本书实在是让我眼前一亮&#xff01;&#xff01;&#xff01; 感觉写的真的太棒了&#xff01; 文章目录黄佳 《零基础学机器学习》 chap1笔记第1课 机器学习快速上手路径—— 唯有实战1.1 机器学习族谱1.2 云环境入门实践&#xff1a;…

ERD Online 4.0.4 元数据在线建模(免费、私有部署)

❝ fix(erd): 修改表名、模块名自定义提示fix(erd): 支持自定义表名显示格式fix(erd): 升级ant到5.0.1版本fix(erd): 修复PDMan导入类型列为空fix(erd): 增加类型列宽度&#xff0c;避免类型显示不全fix(erd): 修复表设计报undefine异常fix(erd): 修复版本比对&#xff0c;出现…

二分搜索算法框架解析

文章目录 一、寻找一个数&#xff08;基本的二分搜索&#xff09;二、寻找左侧边界的二分搜索三、寻找右侧边界的二分查找总结 一、寻找一个数&#xff08;基本的二分搜索&#xff09; 这个场景是最简单的&#xff0c;可能也是大家最熟悉的&#xff0c;即搜索一个数&#xf…

2023年天津财经大学珠江学院专升本经济学专业课考试大纲

天津财经大学珠江学院2023年高职升本科专业课考试《经济学》考试大纲一、本大纲系天津财经大学珠江学院2023年高职升本科《经济学》课程考试大纲。所列考试范围出自郑健壮、王培才主编的教材《经济学基础&#xff08;第二版&#xff09;》&#xff0c;清华大学出版社&#xff0…

win10通过Docker搭建LNMP环境全流程

win10通过Docker搭建LNMP环境全流程 下载安装docker desktop 由于博主环境已经安装好了&#xff0c;一些异常设置&#xff0c;暂且略过 根据官方教程下载docker desktop执行文件.exe 注意尽量不要把docker安装到C盘&#xff0c;除非你的C盘很大&#xff0c;具体可以参考文章 …

初识 Spring 框架

文章目录一、Spring 介绍二、Spring 下载安装三、编写入门程序1.项目文件构架2.引入相关依赖3.创建实体类4.Spring 配置文件5.编写测试类四、控制反转与依赖注入1.控制反转概念2.依赖注入概念3.依赖注入的类型4.依赖注入的应用一、Spring 介绍 Spring 是由 Rod Johnson 组织和…

计算机毕设题目设计与实现(论文+源码)_kaic

毕业设计(论文)题目 高校图书馆座位预约选座微信小程序设计与实现 基于防火墙的访问控制系统的设计与实现 基于区块链的农产品追溯系统设计与实现 学生公寓楼改造布线系统规划与设计 智能家居网络设计与实现“互联网”农村精准扶贫共享平台的设计与实现“智慧健康少儿成长平台”…

Linux内核——门相关入门知识

为什么20位的寻址可以达到1MB&#xff1f; &#x1f512; 点击查看答案 &#x1f512; 拆分如下的段描述符&#xff1a; 0000000000000000 00cf9b000000ffff 00cf93000000ffff 00cffb000000ffff 00cff3000000ffff 80008b04200020ab ffc093dff0000001 0040f30000000fff 0000f20…

TypeScript开启

TypeScript是什么&#xff1f; typescript是以JavaScript为基础构建的语言&#xff0c;是一个Javascript的超集&#xff0c;可以在任何支持JavaScript的平台中执行&#xff0c;typescript扩展了JavaScript&#xff0c;并添加了类型。 注意&#xff1a;ts不能被js直接解析执行&…

MySQL的join你真的了解吗!!!

1.测试用例数据库信息 本文章采用的数据库结构&#xff0c;以及MySQL版本&#xff1a;5.7 t1 表&#xff0c;有一个主键id&#xff0c;字段a&#xff0c;字段b。 &#xff08;此表建立了一个索引a&#xff09; 数据大约1000条 t2 表&#xff0c;有一个主键id&#xff0c;字段…

C++标准库分析总结(十一)——<适配器>

目录 1 适配器简介 2 适配器使用分类 2.1 容器适配器 2.2 函数适配器 2.2.1 常见的函数适配器 2.2.2 bind2nd 2.2.3 not1 2.2.4 新型适配器bind 2.3 迭代器适配器 2.3.1 reverse_iterator 2.3.2 insert_iterator 2.4 X适配器 2.4.1 ostream_iterator 2.4.2 istre…

BUUCTF-babyheap_0ctf_2017

checksec 标准堆菜单 IDA Allocate void __fastcall sub_D48(__int64 a1) {int i; // [rsp10h] [rbp-10h]int v2; // [rsp14h] [rbp-Ch]void *v3; // [rsp18h] [rbp-8h]for ( i 0; i < 15; i ){if ( !*(_DWORD *)(24LL * i a1) ){printf("Size: ");v2 sub_1…

【云原生】无VIP稳定性和可扩展性更强的k8s高可用方案讲解与实战操作

文章目录一、概述二、架构三、开始部署1&#xff09;节点信息2&#xff09;前期准备&#xff08;所有节点&#xff09;1、配置hosts2、配置互信3、时间同步4、关闭防火墙5、禁用SELinux6、关闭swap7、设置bridge-nf-call-iptables3&#xff09;安装容器docker&#xff08;所有节…

C++标准库分析总结(十)——<仿函数/函数对象>

目录 1.functor仿函数简介 2 仿函数的分类 3 仿函数使用 4 仿函数可适配的条件 1.functor仿函数简介 仿函数是STL中最简单的部分&#xff0c;存在的本质就是为STL算法部分服务的&#xff0c;一般不单独使用。仿函数&#xff08;functors&#xff09;又称为函数对象&…

Windows 命令行cmd.exe简单介绍

介绍&#xff1a; 在windows系统中&#xff0c;Windows命令shell&#xff08;cmd.exe&#xff09;,在 SystemRoot/System32目录下。 启动命令行&#xff0c;在"开始"——>"搜索"中输入cmd&#xff0c;此时命令行展示当前工作目录&#xff0c;默认为/u…

JS(第二十四课)JS高级Es6语法

ECMAScript 6_百度百科 (baidu.com) 第一部分:百度简介 ECMAScript 6&#xff08;简称ES6&#xff09;是于2015年6月正式发布的JavaScript语言的标准&#xff0c;正式名为ECMAScript 2015&#xff08;ES2015&#xff09;。它的目标是使得JavaScript语言可以用来编写复杂的大型…

mybatis 01: 静态代理 + jdk动态代理 + cglib动态代理

背景 有时目标对象不可直接访问&#xff0c;只能通过代理对象访问 图示&#xff1a; 示例1&#xff1a; 房东 > 目标对象房屋中介 > 代理对象你&#xff0c;我 > 客户端对象示例2&#xff1a; 运营商(电信&#xff0c;移动&#xff0c;联通) > 目标对象第三方公司…

(Java)P1223 排队接水

排队接水 一、 题目描述 有 nnn 个人在一个水龙头前排队接水&#xff0c;假如每个人接水的时间为 TiT_iTi​&#xff0c;请编程找出这 nnn 个人排队的一种顺序&#xff0c;使得 nnn 个人的平均等待时间最小。 二、输入格式 第一行为一个整数 nnn。 第二行 nnn 个整数&…

Linux下加密库Libsodium 使用实践(ip监听、封装的加密消息、运行系统命令)

Libsodium 是一个用C语言编写的库&#xff0c;是一种新的易于使用的高速软件库&#xff0c;用于网络通信、加密、解密、签名等实现和简化密码学。 完成 Libsodium 安装 Libsodium 是一个用于加密&#xff0c;解密&#xff0c;数字签名&#xff0c;密码哈希&#xff0c;等的&a…