从零开始构建影视类知识图谱(四)

基于ElasticSearch的简单语义搜索

Posted by Pelhans on September 4, 2018

本次我们基于浙江大学在openKG上提供的基于elasticsearch的KBQA实现及示例,我们将其精简并将应用到自己的知识图谱上。目前的精力在知识图谱构建上,等有时间希望能完成一个自己的语义搜索和KBQA…

简介

基于ElasticSearch的简单语义搜索 项目地址

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。我们将通过提供的接口进行查询,例如查询朱一龙的相关信息,可以通过下列命令进行查询:

curl -XGET 'localhost:9200/demo/baidu_baike/_search?&pretty' -H 'Content-Type:application/json' -d'
{
    "query":{
        "bool":{
            "filter":{
                "term":{"subj":"周星驰"}
            }
        }
    }   
}
'

我们的目的就是在数据导入elasticsearch后,通过将输入的自然语言分解来构建这样的查询模板,从而实现搜索功能。

前置条件:需要在 SQL 数据库中有 百度百科数据,可以通过百度网盘下载,提取码 524j 。而后通过 mysql -uroot -pnlp < baidu_baike.sql; 命令导入 SQL 数据库,若报错提示 ERROR 1046 (3D000) at line 22: No database selected,是因为 sql 文件里没指定数据库,因此我们需要先创建数据库,而后指定使用它。因此首先在 21行添加 CREATE DATABASE movie_baidu_baike; 而后添加 USE movie_baidu_baike; (互动百科的就是 movie_baidu_baike)来指定使用该数据库。

elasticsearch 的安装与运行

本项目采用的是 es 5.0.1,通过如下命令进行安装:

wget https://artifacts.elastic.co/downloads/elasticsearch/elasticsearch-5.0.1.tar.gz;
tar -xzf elasticsearch-5.0.1.tar.gz
cd elasticsearch-5.0.1/

,而后运行 ./bin/elasticsearch.sh即可开启服务。

在开启服务后,您可以通过 curl 'http://localhost:9200'来访问 elasticsearch。

数据准备

数据库到JSON

elasticsearch 要求文档的输入格式为 JSON,因此我们需要把数据库中的数据转化为JSON形式。比如:

{
    "subj": "周星驰", 
    "po": [ {"pred": "actor_foreName", "obj": "Stephen Chow"},
           {"pred": "actor_nationality", "obj": "中国"}, 
           {"pred": "actor_constellation", "obj": "巨蟹座"}, 
           {"pred": "actor_birthPlace", "obj": "香港"}, 
           {"pred": "actor_birthDay", "obj": "1962年6月22日"} ]
           ...
}

对应代码为./utils/get_json.py,该程序的工作流程为对数据库进行查表,而后将对应信息保存到字典里。通过 json.dumps()将Python对象转化为JSON格式并写成文件。

这步会得到 baidu_baike.json。

属性同义词扩展

为了支持对同一类问题的不同询问方式,我们采用同意属性映射来扩展属性,当遇到同义属性时,我们将其映射到数据集中的属性上,对应于./data/attr_mapping.txt 文件:

actor_chname 中文名 名字 姓名
actor_forename 英文名 外文名
actor_bio 简介 简历 介绍
actor_nationality 国籍
actor_constellation 星座
actor_birthplace 出生地 老家
actor_birthday 出生日期 生日
actor_repworks 代表作 作品
actor_achiem 成就 获奖 奖项
actor_brokerage 经纪公司
movie_chname 片名
movie_forename 英文片名 外文片名
movie_prodtime 出品时间
movie_prodcompany 出品公司 制作方
movie_director 导演
movie_screenwriter 编剧
movie_genre 类型
movie_star 主演 演员 参演人员
movie_length 片长 时长
movie_releasetime 上映时间
movie_language 对白语言 语言 语种
movie_achiem 奖项 获奖 成就

建立属性间映射 get_ac_attr.py

我们通过cpikle 对属性间映射进行打包,其中属性间的映射通过ahocorasic.Automaton()进行处理。对应的输出为./data/attr_ac.pkl.

获取属性值和属性间的映射 get_total_val.py

通过对数据库进行查表得到各个实体的属性和属性值,而后将其存储为./data/total_val.txt 文件在搜索时使用。

获取所有实体 get_all_entity.py

我们直接通过Mysql的的操作得到所有实体的倒出并存储为一个文件,名为./data/all_entity.txt。

将数据导入到 elasticsearch

在 elasticsearch 中新建 index 和 type

这里我们遵循教程中的要求,采用下列命令建立 index 和 type:

curl -XPUT 'localhost:9200/demo?pretty' -H 'Content-Type: application/json' -d'
{
    "mappings": {
        "baidu_baike": {        
            "properties": {
                "subj": {"type": "keyword"},
                "height": {"type": "integer"},
                "weight": {"type": "integer"},
                "po":{
                    "type": "nested",
                    "properties":{
                        "pred":{"type":"keyword"},
                        "obj":{"type":"keyword"}
                    }
                }            
            }
        }
    }
}
'

对应脚本存储在 utils/query_create.sh; 中,若想删除索引,则用 utils/query_delete.sh 里的命令。

数据导入 insert.py

我们直接调用浙大的./utils/inset.py 程序,修改数据路径为我们的即可。

begin_insert_job("demo", "baidu_baike", "../data/baidu_baike.json")

此时已经可以通过curl方式检索知识库了。您可以直接运行 ./utils/query_cmd.sh 进行简单查询,也可以通过 query_size.sh 查看 ES 中当前索引的数据量。

程序核心 ./utils/views.py

改程序对输入的自然语言问题进行解析,识别出出现在其中的实体名、属性及属性值,并将其转换为对应的logical form。总体流程和浙大的类似,我只是将其从Django 中提取出来方便对于框架不懂的人直接使用。关于views.py的详细解释请看浙大的教程

最终效果展示


基于 ES 的语义检索