多读书多实践,勤思考善领悟

从零开始构建知识图谱-Windows下开发环境搭建

本文于1757天之前发表,文中内容可能已经过时。

一. 半结构化数据的获取

简介

本文章针对半结构化数据的获取,介绍基于scrapy构建的百度百科爬虫和互动百科爬虫。同时为了练手还根据教程制作了基于BeautifulSoup和urllib2的百度百科爬虫、微信公众号爬虫和虎嗅网爬虫。

目前百度百科爬虫,爬取电影类数据,包含电影22219部,演员13967人。互动百科爬虫, 爬取电影类数据,包含电影13866部,演员5931 人。

1. mysql

MySQL是一个关系型数据库管理系统,由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。MySQL 是最流行的关系型数据库管理系统之一,在 WEB 应用方面,MySQL是最好的 RDBMS (Relational Database Management System,关系数据库管理系统) 应用软件之一。

MySQL官网安装包,该安装包有安装指引,按步骤完成即可。

如果想安装MySQL绿色版(不建议),需要手工配置,请参考文章MySQL 8.0.16安装教程(windows 64位)

1
2
3
4
5
6
7
8
9
ALTER TABLE actor_to_movie DROP actor_movie_id;
ALTER TABLE actor_to_movie ADD PRIMARY KEY (actor_id,movie_id);
ALTER TABLE actor_to_movie ADD FOREIGN KEY actor_to_movie_fk_1 (movie_id) REFERENCES movie (movie_id) ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE actor_to_movie ADD FOREIGN KEY actor_to_movie_fk_2 (actor_id) REFERENCES actor (actor_id) ON DELETE NO ACTION ON UPDATE NO ACTION;

ALTER TABLE movie_to_genre DROP movie_genre_id;
ALTER TABLE movie_to_genre ADD PRIMARY KEY (movie_id,genre_id);
ALTER TABLE movie_to_genre ADD FOREIGN KEY movie_to_genre_fk_1 (movie_id) REFERENCES movie (movie_id) ON DELETE NO ACTION ON UPDATE NO ACTION;
ALTER TABLE movie_to_genre ADD FOREIGN KEY movie_to_genre_fk_2 (genre_id) REFERENCES genre (genre_id) ON DELETE NO ACTION ON UPDATE NO ACTION;

2. Python

Python是一种跨平台的计算机程序设计语言。是一种面向对象的动态类型语言,最初被设计用于编写自动化脚本(shell),随着版本的不断更新和语言新功能的添加,越来越多被用于独立的、大型项目的开发。

对于初学者和完成普通任务,Python语言是非常简单易用的。连Google都在大规模使用Python,你就不用担心学了会没用。

项目是Python2开发的,建议安装Python3。

Python官网下载地址:https://www.python.org/downloads/ ,该安装包有安装指引,按步骤完成即可。

详细步骤请参考文章新手必看!如何在windows下安装Python(Python入门教程)

python安装好之后,我们要检测一下是否安装成功,用系统管理员打开命令行工具cmd,输入“python -V”,然后敲回车,如果出现如下信息,则表示我们安装成功了。

1
2
C:\Users\mmm>python -V
Python 3.7.4

3. IDE(PyCharm)

PyCharm是一种Python IDE,带有一整套可以帮助用户在使用Python语言开发时提高其效率的工具,比如调试、语法高亮、Project管理、代码跳转、智能提示、自动完成、单元测试、版本控制。此外,该IDE提供了一些高级功能,以用于支持Django框架下的专业Web开发。

a. 官网Professional(专业版)下载地址:https://www.jetbrains.com/pycharm/download/#section=windows

b. 下载Jetbrains系列产品2019.2.2激活破解补丁jetbrains-agent.jar文件

网盘链接:https://pan.baidu.com/s/1FGZ9d5J5amnvf0vMFqSOsQ 提取码:mmk6

c. 参考pycharm永久激活教程,永久激活。

4. Scrapy

Scrapy是一个为了爬取网站数据,提取结构性数据而编写的应用框架。 可以应用在包括数据挖掘,信息处理或存储历史数据等一系列的程序中。

Scrapy依赖的库比较多,在安装之前,你需要确保以下库已经安装:wheel、lxml、pyOpenSSL、Twisted、pywin32,先装完,再装Scrapy。使用可阅读文章Scrapy入门简介及Demo
库地址:https://www.lfd.uci.edu/~gohlke/pythonlibs/

安装wheel

用途:

pip安装固然方便,但有时候会遇到安装失败的问题。wheel和egg都是打包的格式,支持不需要编译或制作的安装过程。wheel现在被认为是Python标准的二进制打包格式。

安装命令:

pip install wheel

注意:如果你是刚刚安装过python并且从没有安装过wheel,你可以直接运行上述命令。但如果你的pip版本不够新,你需要在执行install命令之前更新一下pip,在命令行中输入:python -m pip install –upgrade pip更新pip,再输入安装命令即可。

安装lxml

用途:

python的一个解析库,支持HTML和XML的解析,支持XPath解析方式,而且解析效率非常高。

安装命令:

安装方式一(在线):

pip install lxml

安装方式二(离线):

你可以进入地址
[https://www.lfd.uci.edu/~gohlke/pythonlibs/#lxml]:

去下载lxml,然后用安装.whl文件的方式安装。
pip install lxml‑4.4.1‑cp37‑cp37m‑win_amd64.whl

下面安装都省略离线安装方式。

安装zope.interface

用途:

python本身不提供interface的实现,需要通过第三方扩展库来使用类似interface的功能,一般都是zope.interface。

注意:不安装zope.interface可能会出现pyOpenSSL安装失败。

安装命令:

pip install zope.interface

安装pyOpenSSL

用途:

让python支持SSL通信协议,简单来说就是加密解密等这系列操作。

安装命令:

pip install pyOpenSSL

安装Twisted

用途:

Twisted是用Python实现的基于事件驱动的网络引擎框架,Twisted支持许多常见的传输及应用层协议,包括TCP、UDP、SSL/TLS、HTTP、IMAP、SSH、IRC以及FTP。就像Python一样,Twisted也具有“内置电池”(batteries-included)的特点。Twisted对于其支持的所有协议都带有客户端和服务器实现,同时附带有基于命令行的工具,使得配置和部署产品级的Twisted应用变得非常方便。

详情参见[https://www.cnblogs.com/misswangxing/p/7712318.html]

安装命令:

pip install Twisted

安装pywin32

用途:

python不自带访问Windows API的库,需要下载这个库做支持。

安装命令:

pip install pywin32

#在python安装根路径的Scripts目录下执行
python pywin32_postinstall.py -install

安装Scrapy

安装命令:

命令:pip install scrapy

可能出现的问题

问题:You are using pip version 19.0.3, however version 19.X is available.
解决方法:输入命令python -m pip install -U pip 或 python -m pip install –upgrade pip

模块安装完毕,输入’scrapy -h’, 输出信息如下则表示Scrapy安装成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
C:\Users\mmm>scrapy -h
Scrapy 1.7.3 - no active project

Usage:
scrapy <command> [options] [args]

Available commands:
bench Run quick benchmark test
fetch Fetch a URL using the Scrapy downloader
genspider Generate new spider using pre-defined templates
runspider Run a self-contained spider (without creating a project)
settings Get settings values
shell Interactive scraping console
startproject Create new project
version Print Scrapy version
view Open URL in browser, as seen by Scrapy

[ more ] More commands available when run from project directory

使用工具,快速解决系列:Anaconda

其实,你还可以登录Scrapy中文网,使用Anaconda进行安装,这个方式可能更适合初学编程的童鞋。地址如下:

[ http://www.scrapyd.cn/doc/124.html ]

验证安装是否成功

方法一:

命令行:pip list

列表中出现了Scrapy,安装成功。

方法二:

命令行:scrapy

正确执行命令,安装成功。

文件的功能

scrapy.cfg:配置文件

spiders:存放你Spider文件,也就是你爬取的py文件

items.py:相当于一个容器,和字典较像

middlewares.py:定义Downloader Middlewares(下载器中间件)和Spider Middlewares(蜘蛛中间件)的实现

pipelines.py:定义Item Pipeline的实现,实现数据的清洗,储存,验证。

settings.py:全局配置

基本使用

a. 创建工程结构

cmd中执行命令:scrapy startproject 工程名

快速打开当前文件夹的dos命令窗口:找到指定文件的文件夹,按住“shift+右键”,选择“在此处打开命令窗口”或“在此处打开Powershell窗口”即可。

1
2
3
4
5
6
7
PS C:\d\mmm\pycharm> scrapy startproject baidu_baike
New Scrapy project 'baidu_baike', using template directory 'c:\my\python\lib\site-packages\scrapy\templates\project', created in:
C:\d\mmm\pycharm\baidu_baike

You can start your first spider with:
cd baidu_baike
scrapy genspider example example.com

b. 创建一个spider(爬虫文件)

cmd中执行命令:scrapy genspider 文件名 要爬取的网址。

在spiders文件夹下创建

1
2
3
PS C:\d\mmm\pycharm\baidu_baike\baidu_baike\spiders> scrapy genspider -t basic baidubaike baike.baidu.com
Created spider 'baidubaike' using template 'basic' in module:
baidu_baike.spiders.baidubaike

生成baidubaike.py的代码

1
2
3
4
5
6
7
8
9
10
11
# -*- coding: utf-8 -*-
import scrapy


class BaidubaikeSpider(scrapy.Spider):
name = 'baidu'
allowed_domains = ['baike.baidu.com']
start_urls = ['http://baike.baidu.com/']

def parse(self, response):
pass

name:是项目的名字

allowed_domains:是允许爬取的域名,比如一些网站有相关链接,域名就和本网站不同,这些就会忽略。

atart_urls:是Spider爬取的网站,定义初始的请求url,可以多个。

parse方法:是Spider的一个方法,在请求start_url后,之后的方法,这个方法是对网页的解析,与提取自己想要的东西。

response参数:是请求网页后返回的内容,也就是你需要解析的网页。

c. 运行

项目从零开始构建知识图谱项目链接是python2编写的,在python3环境下运行需要修改代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#settings.py文件
#修改前 mysql的配置,PORT的值为数字,不可加单引号
HOST_IP = 'localhost'
PORT = 3306
USER = 'root'
PASSWD = 'root'
DB_NAME = 'baidu_baike'

#baidu_baike.py文件
#修改前 urlparse.urljoin
urllib.parse.urljoin
#修改前 urlparse
urllib

#pipelines.py文件
#修改前 .decode('utf-8')
.encode('utf-8')
#删除#port=settings.PORT的注释
port=settings.PORT
#删除代码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

cmd中执行命令:scrapy crawl 项目名

在项目根路径下执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
PS C:\d\mmm\pycharm\baidu_baike> scrapy crawl baidu
2019-09-26 09:45:40 [scrapy.utils.log] INFO: Scrapy 1.7.3 started (bot: baidu_baike)
2019-09-26 09:45:40 [scrapy.utils.log] INFO: Versions: lxml 4.4.1.0, libxml2 2.9.5, cssselect 1.1.0, parsel 1.5.2, w3lib 1.21.0, Twisted 19.7.0, Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)], pyOpenSSL 19.0.0 (OpenSSL 1.1.1c 28 May 2019), cryptography 2.7, Platform Windows-10-10.0.18362-SP0
2019-09-26 09:45:40 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'baidu_baike', 'NEWSPIDER_MODULE': 'baidu_baike.spiders', 'SPIDER_MODULES': ['baidu_baike.spiders'], 'USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}
2019-09-26 09:45:40 [scrapy.extensions.telnet] INFO: Telnet Password: 4e0e039c01ca23b2
2019-09-26 09:45:40 [scrapy.middleware] INFO: Enabled extensions:
['scrapy.extensions.corestats.CoreStats',
'scrapy.extensions.telnet.TelnetConsole',
'scrapy.extensions.logstats.LogStats']
2019-09-26 09:45:41 [scrapy.middleware] INFO: Enabled downloader middlewares:
['baidu_baike.middlewares.RandomUserAgent',
'baidu_baike.middlewares.ProxyMiddleWare',
'scrapy.downloadermiddlewares.httpauth.HttpAuthMiddleware',
'scrapy.downloadermiddlewares.downloadtimeout.DownloadTimeoutMiddleware',
'scrapy.downloadermiddlewares.defaultheaders.DefaultHeadersMiddleware',
'scrapy.downloadermiddlewares.useragent.UserAgentMiddleware',
'scrapy.downloadermiddlewares.retry.RetryMiddleware',
'scrapy.downloadermiddlewares.redirect.MetaRefreshMiddleware',
'scrapy.downloadermiddlewares.httpcompression.HttpCompressionMiddleware',
'scrapy.downloadermiddlewares.redirect.RedirectMiddleware',
'scrapy.downloadermiddlewares.cookies.CookiesMiddleware',
'scrapy.downloadermiddlewares.httpproxy.HttpProxyMiddleware',
'scrapy.downloadermiddlewares.stats.DownloaderStats']
2019-09-26 09:45:41 [scrapy.middleware] INFO: Enabled spider middlewares:
['scrapy.spidermiddlewares.httperror.HttpErrorMiddleware',
'scrapy.spidermiddlewares.offsite.OffsiteMiddleware',
'scrapy.spidermiddlewares.referer.RefererMiddleware',
'scrapy.spidermiddlewares.urllength.UrlLengthMiddleware',
'scrapy.spidermiddlewares.depth.DepthMiddleware']
2019-09-26 09:45:41 [scrapy.middleware] INFO: Enabled item pipelines:
['baidu_baike.pipelines.BaiduBaikePipeline']
2019-09-26 09:45:41 [scrapy.core.engine] INFO: Spider opened
2019-09-26 09:45:41 [scrapy.extensions.logstats] INFO: Crawled 0 pages (at 0 pages/min), scraped 0 items (at 0 items/min)
2019-09-26 09:45:41 [scrapy.extensions.telnet] INFO: Telnet console listening on 127.0.0.1:6023
2019-09-26 09:45:41 [scrapy.core.engine] DEBUG: Crawled (200) <GET https://baike.baidu.com/item/%E5%88%98%E5%BE%B7%E5%8D%8E/114923> (referer: None)
Get a actor page
2019-09-26 09:45:42 [scrapy.core.scraper] DEBUG: Scraped from <200 https://baike.baidu.com/item/%E5%88%98%E5%BE%B7%E5%8D%8E/114923>
......

二. 数据库到 NTriples 以及通过Apache jena 访问NT

1. Protege

斯坦福大学开发的本体编辑和知识获取软件。开发语言采用Java,属于开放源码软件。由于其优秀的设计和众多的插件,Protege已成为目前使用最广泛的本体论编辑器之一。软件不需要安装,需要配置相应的Java环境。详细使用可阅读官方教程

打开protege,看到和下图类似的界面。在Ontology IRI中填写我们新建本体资源的IRI。读者可以填写自己的符合标准的IRI。如下:

1
http://www.kgdemo.com

2. d2rq

D2RQ平台用于访问关系数据库系统是虚拟的,只读RDF图。它提供了基于RDF的访问关系数据库的内容,而无需复制成RDF存储。使用D2RQ可参考文章使用d2rq的第一步官方文档

官方网站:http://d2rq.org/

a. 下载后得到了d2rq-0.8.1.zip的压缩文件,d2rq不需要安装,直接将其解压到运行目录,再配置运行环境即可。

b. 项目需要将d2rq与java、mysql进行联合应用,因此需要JDBC driver,将mysql-connector-java-5.1.48-bin.jar文件放入d2rq的/lib文件夹中。

c. 用generate-mapping工具为数据库创建mapping file(映射文件)。cmd中运行 cd C:\my\d2rq命令,转到d2rq目录。
运行以下命令,创建mappling映射文件。?useSSL=false语句设置SSL为false以避免提示警告,数据库没设置主键会提示警告。

1
2
3
PS C:\my\d2rq> .\generate-mapping -u root -p root -o kg_demo_mapping_baidu_baike.ttl jdbc:mysql:///baidu_baike?useSSL=false
## -u 后root是数据库用户,-p 后root是用户密码,jdbc:mysql: 后baidu_baike是数据库名称;
## 注意笔者是Windows PowerShell命令窗口运行命令,若在cmd中去掉前面的.\,即:generate-mapping开始。下面的命令也如此。

下面是根据我们定义的本体修改的mapping文件。

1) 为了表达简练,我们给本体做一些修改。

这样http://www.kgdemo.com#Actor就可以表达为:Actor`,其他的词汇同理。

vocab前缀,它表示输出本体的命名空间,也就是说,所有来自D2RQRDF都必须使用具有vocab前缀的命名空间的类和属性描述。这样做的目的是为了使它们是唯一的,在需要读取某个类或属性时可以直接操作,而不必先动态获得命名空间了。

2) 把默认的映射词汇改为我们本体中的词汇即可。在处理外键的时候要注意当前编辑的属性的domain和range,belongsToClassMap是domain,refersToClassMap是range。

为了实现生成及修改全自自动,需编写dos下的bat实现,auto.bat代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@echo off&setlocal enabledelayedexpansion

set db=baidu_baike
set file=kg_demo_mapping_%db%.ttl

call generate-mapping -u root -p root -o %file% jdbc:mysql:///%db%?useSSL=false

:: call findstr /i /v /C:"@prefix vocab" "%file%">>%file%.bk
:: move /y %file%.bk %file%

for /f "tokens=1,* delims=:" %%b in ('findstr /n ".*" "%file%"')do (
set "var=%%c"
if "!var!" neq "@prefix vocab: <vocab/> ." (
if "!var!" equ "" (
>>%file%.bk echo,!var!) ^
else if "!var!" equ "@prefix jdbc: <http://d2rq.org/terms/jdbc/> ." (
>>%file%.bk echo,!var!
>>%file%.bk echo,@prefix : ^<http://www.kgdemo.com#^> .) ^
else (
echo;"!var!"|find "jdbcDSN"&&(
>>%file%.bk echo, d2rq:jdbcDSN ^"jdbc:mysql:///%db%?useUnicode=true^&characterEncoding=utf8^&useSSL=false^";)||(
set "var=!var:vocab= !"
set "var=!var:actor_actor=actor!"
>>%file%.bk echo,!var!))
)
)
move /y %file%.bk %file%

d. 运行dump-rdf工具,创建rdf的转存,命令将数据转换为Ntriples。
按照官方的介绍,运行以下命令生成rdf,在d2rq文件夹中查看生成的nt文件可以看到RDF结构。

1
PS C:\my\d2rq> ./dump-rdf -o baidu_baike.nt kg_demo_mapping_baidu_baike.ttl

e. 使用下面的命令启动D2R Server

1
2
PS C:\my\d2rq> ./d2r-server kg_demo_mapping_baidu_baike.ttl
17:10:16 INFO JettyLauncher :: [[[ Server started at http://localhost:2020/ ]]]

f.SPARQL查询

例如:“周星驰出演了哪些电影?”

1
2
3
4
5
6
SELECT ?n WHERE {
?s rdf:type :Actor.
?s :actor_chName '周星驰'.
?o :movie_chName ?n
}
LIMIT 10

结果为:

1
2
3
4
5
6
7
8
9
10
11
12
SPARQL results:
n
"七小福"
"大众电影百花奖"
"台湾电影金马奖"
"香港电影金像奖"
"香港电影导演会"
"长江7号"
"第28届香港电影金像奖"
"跳出去"
"少林少女"
"西游:降魔篇"

就我们这个例子而言,可以不要“?s rdf:type :Actor”,这里只是让查询图更具体(在拥有复杂关系的RDF图中,可能会存在不同的类拥有相同的属性名。比如,猫和狗名字的属性名都是”name”,我们想查询一只叫汤姆的猫;如果不指定类型,返回结果可能也包含一只叫汤姆的狗)。图模式中,每个RDF用英文句号进行分割。

例如:“少林足球这部电影有哪些演员参演”:

1
2
3
4
5
6
SELECT ?n WHERE {
?s rdf:type :Movie.
?s :movie_chName '少林足球'.
?a :hasActedIn ?s.
?a :actor_chName ?n
}

结果为:

1
2
3
n
"周星驰"
"吴孟达"

3. Apache jena

Apache Jena是一个开源的Java语义网框架(open source Semantic Web Framework for Java),用于构建语义网和链接数据应用。安装可阅读文章Jena 和 Fuseki安装与SPARQL查询

下载地址:http://jena.apache.org/download/

TDB:用于存储RDF的组件。
Jena:提供了RDFS、OWL和通用规则推理机。下载Jena
Fuseki:Jena提供的SPARQL服务器,也就是SPARQL endpoint。下载Fuseki

安装

java开发的软件免安装。

基本使用

a. 将RDF数据转换以TDB的方式存储
运行命令:tdbloader –loc=”..\tdb” “....\d2rq\baidu_baike.nt”

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
PS C:\my\apache-jena\bat> ./tdbloader --loc="..\tdb" "..\..\d2rq\baidu_baike.nt"
16:03:28 INFO loader :: -- Start triples data phase
16:03:28 INFO loader :: ** Load empty triples table
16:03:28 INFO loader :: -- Start quads data phase
16:03:28 INFO loader :: ** Load empty quads table
16:03:28 INFO loader :: Load: ..\..\d2rq\baidu_baike.nt -- 2019/09/27 16:03:28 CST
16:03:30 INFO loader :: Add: 50,000 triples (Batch: 31,867 / Avg: 31,867)
16:03:30 INFO loader :: Add: 100,000 triples (Batch: 124,688 / Avg: 50,761)
16:03:31 INFO loader :: Add: 150,000 triples (Batch: 147,928 / Avg: 64,991)
16:03:31 INFO loader :: Add: 200,000 triples (Batch: 124,378 / Avg: 73,800)
16:03:31 INFO loader :: Add: 250,000 triples (Batch: 128,534 / Avg: 80,671)
16:03:32 INFO loader :: Add: 300,000 triples (Batch: 152,905 / Avg: 87,565)
16:03:32 INFO loader :: Add: 350,000 triples (Batch: 131,926 / Avg: 91,984)
16:03:32 INFO loader :: Add: 400,000 triples (Batch: 135,501 / Avg: 95,831)
16:03:33 INFO loader :: Add: 450,000 triples (Batch: 154,798 / Avg: 100,066)
16:03:33 INFO loader :: Add: 500,000 triples (Batch: 145,348 / Avg: 103,284)
16:03:33 INFO loader :: Elapsed: 4.84 seconds [2019/09/27 16:03:33 CST]
16:03:33 INFO loader :: Add: 550,000 triples (Batch: 160,256 / Avg: 106,733)
16:03:34 INFO loader :: Add: 600,000 triples (Batch: 145,348 / Avg: 109,150)
16:03:34 INFO loader :: Add: 650,000 triples (Batch: 125,628 / Avg: 110,262)
16:03:34 INFO loader :: -- Finish triples data phase
16:03:34 INFO loader :: ** Data: 663,080 triples loaded in 6.08 seconds [Rate: 109,059.21 per second]
16:03:34 INFO loader :: -- Finish quads data phase
16:03:34 INFO loader :: -- Start triples index phase
16:03:35 INFO loader :: Index SPO->POS: 100,000 slots (Batch: 418,410 slots/s / Avg: 418,410 slots/s)
16:03:35 INFO loader :: Index SPO->POS: 200,000 slots (Batch: 662,251 slots/s / Avg: 512,820 slots/s)
16:03:35 INFO loader :: Index SPO->POS: 300,000 slots (Batch: 598,802 slots/s / Avg: 538,599 slots/s)
16:03:35 INFO loader :: Index SPO->POS: 400,000 slots (Batch: 588,235 slots/s / Avg: 550,206 slots/s)
16:03:35 INFO loader :: Index SPO->POS: 500,000 slots (Batch: 581,395 slots/s / Avg: 556,173 slots/s)
16:03:35 INFO loader :: Index SPO->POS: 600,000 slots (Batch: 598,802 slots/s / Avg: 562,851 slots/s)
16:03:36 INFO loader :: ** Index SPO->POS: 663,080 slots indexed in 1.19 seconds [Rate: 558,618.38 per second]
16:03:36 INFO loader :: Index SPO->OSP: 100,000 slots (Batch: 657,894 slots/s / Avg: 657,894 slots/s)
16:03:36 INFO loader :: Index SPO->OSP: 200,000 slots (Batch: 694,444 slots/s / Avg: 675,675 slots/s)
16:03:36 INFO loader :: Index SPO->OSP: 300,000 slots (Batch: 584,795 slots/s / Avg: 642,398 slots/s)
16:03:36 INFO loader :: Index SPO->OSP: 400,000 slots (Batch: 561,797 slots/s / Avg: 620,155 slots/s)
16:03:36 INFO loader :: Index SPO->OSP: 500,000 slots (Batch: 595,238 slots/s / Avg: 615,006 slots/s)
16:03:37 INFO loader :: Index SPO->OSP: 600,000 slots (Batch: 546,448 slots/s / Avg: 602,409 slots/s)
16:03:37 INFO loader :: ** Index SPO->OSP: 663,080 slots indexed in 1.11 seconds [Rate: 595,224.44 per second]
16:03:37 INFO loader :: -- Finish triples index phase
16:03:37 INFO loader :: ** 663,080 triples indexed in 2.31 seconds [Rate: 287,171.94 per second]
16:03:37 INFO loader :: -- Finish triples load
16:03:37 INFO loader :: ** Completed: 663,080 triples loaded in 8.41 seconds [Rate: 78,844.23 per second]
16:03:37 INFO loader :: -- Finish quads load

注意:“–loc”指定tdb存储的位置;第二个参数是由Mysql数据转换得到的RDF数据。

b. 通过Fuseki进行开启服务
进入fuseki目录下,运行命令:fuseki-server –loc=..\apache-jena\tdb /kg_movie

注意:–loc的参数是上一步TDB数据库的路径,kg_movie是显示的数据库名。

1
2
3
4
5
6
7
8
9
10
PS C:\my\apache-jena-fuseki> ./fuseki-server --loc=..\apache-jena\tdb /kg_movie
[2019-09-25 16:35:32] Server INFO Running in read-only mode for /kg_movie
[2019-09-25 16:35:32] Server INFO Apache Jena Fuseki 3.12.0
[2019-09-25 16:35:32] Config INFO FUSEKI_HOME=C:\my\apache-jena-fuseki\.
[2019-09-25 16:35:32] Config INFO FUSEKI_BASE=C:\my\apache-jena-fuseki\run
[2019-09-25 16:35:32] Config INFO Shiro file: file://C:\my\apache-jena-fuseki\run\shiro.ini
[2019-09-25 16:35:32] Config INFO Template file: templates/config-tdb-dir
[2019-09-25 16:35:32] Config INFO TDB dataset: directory=..\apache-jena\tdb
[2019-09-25 16:35:33] Config INFO Register: /kg_movie
[2019-09-25 16:35:33] Server INFO Started 2019/09/25 16:35:33 CST on port 3030

测试查询,可以通过网页端和命令行方式进行SPQRQL查询

如:过滤出变量包含“长江7号”的实体

1
2
3
4
5
6
SELECT ?subject ?predicate ?object
WHERE {
?subject ?predicate ?object
FILTER regex(?object, "长江7号")
}
LIMIT 25

返回结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
	subject	predicate	object
1
<file:///C:/my/d2rq/baidu_baike.nt#movie/6>
<http://www.kgdemo.com#movie_chName>
"长江7号"
2
<file:///C:/my/d2rq/baidu_baike.nt#movie/6>
<http://www.kgdemo.com#movie_bio>
" 《长江7号》是由周星驰执导,周星驰、徐娇、张雨绮、林子聪主演的科幻喜剧电影。该片于2008年1月30日在中国上映。影片讲述一名父亲将意外拾获的外星玩具狗当做礼物送给儿子,从而让父子两人的生活发生变化的故事。 [1] "
3
<file:///C:/my/d2rq/baidu_baike.nt#movie/10221>
<http://www.kgdemo.com#movie_chName>
"长江7号爱地球"
4
<file:///C:/my/d2rq/baidu_baike.nt#movie/10221>
<http://www.kgdemo.com#movie_bio>
" 《长江7号爱地球》是由袁建滔执导的动画电影,石班瑜、徐娇、董洁等联合配音。该片于2010年7月9日在中国内地上映。该片讲述了狄爸以在建筑工地打散工养家,在垃圾堆意外捡到神秘外星生物7仔的故事。 [1] "
5
<file:///C:/my/d2rq/baidu_baike.nt#actor/1>
<http://www.kgdemo.com#actor_bio>
" 周星驰,1962年6月22日生于香港,祖籍浙江宁波,中国香港演员、导演、编剧、制作人、商人,毕业于无线电视艺员训练班。1980年成为丽的电视台的特约演员,从而进入演艺圈。1981年出演个人首部电视剧《IQ成熟时》。1988年将演艺事业的重心转向大银幕,并于同年出演电影处女作《捕风汉子》。1990年凭借喜剧片《一本漫画闯天涯》确立其无厘头的表演风格 [1] ;同年,因其主演的喜剧动作片《赌圣》打破香港地区票房纪录而获得关注 [2] 。1991年主演喜剧片《逃学威龙》,并再次打破香港地区票房纪录 [3] 。1995年凭借喜剧爱情片《大话西游》奠定其在华语影坛的地位。1999年自导自演的喜剧片《喜剧之王》获得香港电影年度票房冠军 [4] 。2002年凭借喜剧片《少林足球》获得第21届香港电影金像奖最佳男主角奖以及最佳导演奖 [5] 。2003年成为美国《时代周刊》封面人物 [6] 。2005年凭借喜剧动作片《功夫》获得第42届台湾电影金马奖最佳导演奖 [7] 。2008年自导自演的科幻喜剧片《长江7号》获得香港电影年度票房冠军 [8] 。2013年执导古装喜剧片《西游·降魔篇》,该片以2.18亿美元的票房成绩打破华语电影在全球的票房纪录 [9-10] 。2016年担任科幻喜剧片《美人鱼》的导演、编剧、制作人,该片以超过33亿元的票房创下中国内地电影票房纪录 [11-14] 。2017年1月28日,担任监制、编剧的古装喜剧片《西游伏妖篇》上映 [15] 。2018年执导《美人鱼2》 [16] 。演艺事业外,周星驰还涉足商界。1989年成立星炜有限公司 [17] 。1996年成立星辉公司 [18] 。2010年出任比高集团有限公司执行董事 [19] 。 "
6
<file:///C:/my/d2rq/baidu_baike.nt#movie/10218>
<http://www.kgdemo.com#movie_bio>
" 曾谨昌是香港资深编剧家。他于1981年加入电视广播有限公司(TVB),编写过多部脍炙人口的电视剧,作品有《白蛇传说》、《长江7号爱地球》等。 "

c. 实现OWL推理

上一步运行完退出。程序会为我们在当前目录自动创建“run”文件夹实现。将我们的本体文件“kg_movie_tultle.owl”移动到“run”文件夹下的“databases”文件夹中,并将“owl”后缀名改为“ttl”。在“run”文件夹下的“configuration”中,我们创建名为“fuseki_conf.ttl”的文本文件(取名没有要求),加入如下内容:

1) TDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
@prefix :       <#> .
@prefix fuseki: <http://jena.apache.org/fuseki#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .

[] rdf:type fuseki:Server ;
fuseki:services (
<#service1>
) .

## ---------------------------------------------------------------
## Service with only SPARQL query on an inference model.
## Inference model base data in TDB.

<#service1> rdf:type fuseki:Service ;
fuseki:name "kg_movie" ;
fuseki:endpoint [ fuseki:operation fuseki:query; fuseki:name "sparql" ] ;
fuseki:endpoint [ fuseki:operation fuseki:query; fuseki:name "query" ] ;
fuseki:endpoint [ fuseki:operation fuseki:update; fuseki:name "update" ] ;
fuseki:endpoint [ fuseki:operation fuseki:upload; fuseki:name "upload" ] ;
fuseki:endpoint [ fuseki:operation fuseki:gsp_r; fuseki:name "get" ] ;
fuseki:endpoint [ fuseki:operation fuseki:gsp_rw; fuseki:name "data" ] ;
fuseki:dataset <#dataset> .

<#dataset> rdf:type tdb:DatasetTDB ;
ja:context [ ja:cxtName "arq:queryTimeout" ; ja:cxtValue "10000,30000" ] ;
tdb:location "../apache-jena/tdb" .

2) 在内存,同步加载本体和三元组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@prefix :       <#> .
@prefix fuseki: <http://jena.apache.org/fuseki#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix tdb: <http://jena.hpl.hp.com/2008/tdb#> .
@prefix ja: <http://jena.hpl.hp.com/2005/11/Assembler#> .

[] rdf:type fuseki:Server ;
fuseki:services (
<#service1>
) .

## ---------------------------------------------------------------
## Service with only SPARQL query on an inference model.
## Inference model base data in TDB.

<#service1> rdf:type fuseki:Service ;
fuseki:name "kg_movie" ;
fuseki:endpoint [ fuseki:operation fuseki:query; fuseki:name "sparql" ] ;
fuseki:endpoint [ fuseki:operation fuseki:query; fuseki:name "query" ] ;
fuseki:endpoint [ fuseki:operation fuseki:update; fuseki:name "update" ] ;
fuseki:endpoint [ fuseki:operation fuseki:upload; fuseki:name "upload" ] ;
fuseki:endpoint [ fuseki:operation fuseki:gsp_r; fuseki:name "get" ] ;
fuseki:endpoint [ fuseki:operation fuseki:gsp_rw; fuseki:name "data" ] ;
fuseki:dataset <#dataset> .

<#dataset> rdf:type ja:RDFDataset ;
ja:defaultGraph
[ a ja:MemoryModel ;
ja:content [ja:externalContent <file:../databases/kg_movie_tultle.ttl> ] ;
ja:content [ja:externalContent <file:../../../d2rq/baidu_baike.nt> ] ;
] ;
.

再次运行“fuseki-server.bat”,如果出现如下界面表示运行成功:

1
2
3
4
5
6
7
8
9
10
PS C:\my\apache-jena-fuseki> ./fuseki-server
[2019-09-26 10:48:42] Server INFO Apache Jena Fuseki 3.12.0
[2019-09-26 10:48:42] Config INFO FUSEKI_HOME=C:\my\apache-jena-fuseki\.
[2019-09-26 10:48:42] Config INFO FUSEKI_BASE=C:\my\apache-jena-fuseki\run
[2019-09-26 10:48:42] Config INFO Shiro file: file://C:\my\apache-jena-fuseki\run\shiro.ini
[2019-09-26 10:48:42] Config INFO Configuration file: C:\my\apache-jena-fuseki\run\config.ttl
[2019-09-26 10:48:42] riot WARN [line: 5, col: 9 ] Bad IRI: <C:\my\apache-jena-fuseki\run\config.ttl#> Code: 4/UNWISE_CHARACTER in PATH: The character matches no grammar rules of URIs/IRIs. These characters are permitted in RDF URI References, XML system identifiers, and XML Schema anyURIs.
[2019-09-26 10:48:43] Config INFO Load configuration: file:///C:/my/apache-jena-fuseki/run/configuration/fuseki_conf.ttl
[2019-09-26 10:48:43] Config INFO Register: /kg_movie
[2019-09-26 10:48:43] Server INFO Started 2019/09/26 10:48:43 CST on port 3030

需要注意的是,每次运行fuseki服务器后,会在TDB文件夹内生成一些以prefix*开头的文件,重新运行fuseki服务的话不删除它们可能会报错。

测试查询,可以通过网页端和命令行方式进行SPQRQL查询,经过实践,发现丧失推理能力。

如:查询电影鹿鼎记的所有属性

1
2
3
4
5
6
7
8
PREFIX : <http://www.kgdemo.com#>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>

SELECT * WHERE {
?x :movie_chName '鹿鼎记'.
?x ?p ?o.
}

返回的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66

x p o
1
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
rdfs:label
"movie #35"
2
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
rdf:type
:Movie
3
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_language
"粤语"
4
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_screenwriter
"王晶"
5
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_rekeaseTime
"1992年07月30日"
6
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_prodTime
"None"
7
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_id
"35"^^xsd:integer
8
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_foreName
"Royal Tramp"
9
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_genre
"动作"
10
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_star
"周星驰,温兆伦,邱淑贞,张敏,吴孟达,徐锦江"
11
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_achiem
"None"
12
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_chName
"鹿鼎记"
13
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_director
"王晶"
14
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_prodCompany
"香港永盛电影公司"
15
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_bio
" 《鹿鼎记》是改编自金庸小说的一部武侠喜剧。影片由王晶执导,周星驰、吴孟达、温兆伦、林青霞 、 李嘉欣、袁洁莹、邱淑贞、陈德容等联合出演。影片讲述清朝初期,康熙皇帝年少,奸臣鳌拜从中控制政权。韦小宝有幸加入推翻清朝的民间组织“天地会”,被派到王宫当卧底,偷取藏有清朝秘密的四十二章经。韦小宝很快成为皇上的心腹,做了大官。他既要执行任务却又跟皇帝成为了好朋友,陷入了两难的状态。 [1] 该片于1992年7月30日上映。 "
16
<file:///C:/my/d2rq/baidu_baike.nt#movie/35>
:movie_length
"106 分钟"

三. 基于REfO的简单知识问答

项目从零开始构建知识图谱项目链接是python2编写的,在python3环境下运行需要修改代码

1
2
3
4
5
6
7
8
9
10
11
#word_tagging.py文件
#修改前 word.encode('utf-8')
bytes.decode(word.encode('utf-8'))

#rules.py文件
#原代码 w.token.encode("utf-8")
w.token

#query.py文件
#原代码 raw_input()
input()

运行,提问示例结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
C:\my\Python\python.exe C:/d/mmm/pycharm/patternREfO/query.py
Building prefix dict from the default dictionary ...
init...........
Loading model from cache C:\Users\mmm\AppData\Local\Temp\jieba.cache
Loading model cost 0.816 seconds.
Prefix dict has been built succesfully.
done

Please input your question:
刘德华是哪个
Result: 刘德华(Andy Lau),1961年9月27日出生于中国香港,中国香港男演员、歌手、作词人、制片人。1981年出演电影处女作《彩云曲》 [1]  。1983年主演的武侠剧《神雕侠侣》在香港获得62点的收视纪录 [2-3]  。1991年创办天幕电影公司 [4]  。1992年,凭借传记片《五亿探长雷洛传》获得第11届香港电影金像奖最佳男主角提名 [5]  。1994年担任剧情片《天与地》的制片人 [6]  。2000年凭借警匪片《暗战》获得第19届香港电影金像奖最佳男主角奖 [7]  。2004年凭借警匪片《无间道3:终极无间》获得第41届台湾金马奖最佳男主角奖 [8]  。2005年获得香港UA院线颁发的全港最高累积票房香港男演员”奖 [9]  。2006年获得釜山国际电影节亚洲最有贡献电影人奖 [10]  。2011年主演剧情片《桃姐》,并凭借该片先后获得台湾金马奖最佳男主角奖、香港电影金像奖最佳男主角奖 [11]  ;同年担任第49届台湾电影金马奖评审团主席 [12]  。2017年主演警匪动作片《拆弹专家》 [13]  。1985年发行首张个人专辑《只知道此刻爱你》 [14]  。1990年凭借专辑《可不可以》在歌坛获得关注 [15]  。1994年获得十大劲歌金曲最受欢迎男歌星奖 [16]  。1995年在央视春晚上演唱歌曲《忘情水》 [17]  。2000年被《吉尼斯世界纪录大全》评为“获奖最多的香港男歌手” [18]  。2004年第六次获得十大劲歌金曲最受欢迎男歌星奖。2016年参与填词的歌曲《原谅我》正式发行 [19]  。1994年创立刘德华慈善基金会 [20]  。2000年被评为世界十大杰出青年 [21]  。2005年发起亚洲新星导计划 [22]  。2008年被委任为香港非官守太平绅士 [23]  。2016年连任中国残疾人福利基金会副理事长。 [21] 
Please input your question:
刘德华出生地
Result: 香港新界大埔镇泰亨村
Please input your question:
七小福简介
Result: 《七小福》(Painted Faces)是由罗启锐导演,洪金宝、郑佩佩、林正英、岑建勋、午马等领衔主演的喜剧电影。影片讲述京剧大师于占元当年创办的“中国戏剧研究学院”,名字虽然取得唬人,但要论规模在香港众多戏校中也只算得中等,而且校舍破败,条件简陋,所幸师傅并未误人子弟,教得认真。“七小福“戏班最终名扬天下的故事。

四. 基于ElasticSearch的简单语义搜索

ElasticSearch是一个基于Lucene的搜索服务器。它提供了一个分布式多用户能力的全文搜索引擎,基于RESTful web接口。Elasticsearch是用Java语言开发的,并作为Apache许可条款下的开放源码发布,是一种流行的企业级搜索引擎。ElasticSearch用于云计算中,能够达到实时搜索,稳定,可靠,快速,安装使用方便。根据DB-Engines的排名显示,Elasticsearch是最受欢迎的企业搜索引擎,其次是Apache Solr,也是基于Lucene。

1. 安装

elasticsearch 官网下载安装包,软件不需要安装,需要配置相应的Java环境。详细使用可阅读官方教程

运行 ./bin/elasticsearch.bat即可开启服务。

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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
{
"name" : "DESKTOP-3AFDEBF",
"cluster_name" : "elasticsearch",
"cluster_uuid" : "0HpHJxLAREq6SntFdfVSPQ",
"version" : {
"number" : "7.4.0",
"build_flavor" : "default",
"build_type" : "zip",
"build_hash" : "22e1767283e61a198cb4db791ea66e3f11ab9910",
"build_date" : "2019-09-27T08:36:48.569419Z",
"build_snapshot" : false,
"lucene_version" : "8.2.0",
"minimum_wire_compatibility_version" : "6.8.0",
"minimum_index_compatibility_version" : "6.0.0-beta1"
},
"tagline" : "You Know, for Search"
}

2. 修改代码

项目从零开始构建知识图谱项目链接是python2编写的,在python3环境下运行需要修改代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#query.py文件
#原代码 raw_input()
input()

#get_json.py文件
#删除代码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

#get_ac_attr.py文件
#ahocorasick要安装pyahocorasick(pip install pyahocorasick)
#原代码 cPickle
pickle
#原代码 open(attr_mapping_file)
open(attr_mapping_file,'r',encoding='UTF-8')

#get_total_val.py文件
#删除代码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
#原代码 open(__package__ + "/../data/{}.txt".format(cate), "w+")
open("../data/{}.txt".format(cate), "w+",encoding='utf-8')

#build_dict.py文件
#删除代码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
#ahocorasick要安装pyahocorasick(pip install pyahocorasick)
#原代码 cPickle
pickle

#views.py文件
#原代码 cPickle
pickle
#原代码 from Queue import Queue
from queue import Queue

可能出现的问题:
python pyahocorasick包安装失败解决方法

3. 运行

1)数据库到JSON

运行get_json.py,生成actor.json和movie.json

1
2
3
4
5
6
C:\my\Python\python.exe C:/d/mmm/pycharm/elasticsearch/utils/get_json.py
max_id: 13967
max_id: 22219
tuple index out of range

Process finished with exit code 0

2)建立属性间映射

运行get_ac_attr.py,生成./data/attr_ac.pkl

1
2
3
C:\my\Python\python.exe C:/d/mmm/pycharm/elasticsearch/utils/get_ac_attr.py

Process finished with exit code 0

3)获取属性值和属性间的映射

运行get_total_val.py,生成actor.txt和movie.txt

1
2
3
4
5
6
C:\my\Python\python.exe C:/d/mmm/pycharm/elasticsearch/utils/get_total_val.py
max_id: 13967
max_id: 22219
tuple index out of range

Process finished with exit code 0

4)在 elasticsearch 中新建 index 和 type

可以用elasticsearch-head或CURL。

ealsticsearch只是后端提供各种api,那么怎么直观的使用它呢?elasticsearch-head将是一款专门针对于elasticsearch的客户端工具。elasticsearch-head配置包,下载地址:https://github.com/mobz/elasticsearch-head 。安装可以参考文章windows下安装ElasticSearch的Head插件

我们这里选择用CURL,去curl官网下载对应版本的包,解压后打开CMD切换到对应目录下运行CURL.exe文件,

如果把该CURL.exe文件复制到C:\Windows\System32目录下,则不需要切换目录,可以直接运行curl命令。

a. 用下列命令建立 index 和 type:

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

运行结果

1
2
3
4
5
6
C:\Users\mmm>curl -XPUT "localhost:9200/demo?pretty" -H "Content-Type: application/json" -d" { \"mappings\": { \"properties\": { \"subj\": {\"type\": \"keyword\"}, \"po\":{ \"type\": \"nested\", \"properties\":{ \"pred\":{\"type\":\"keyword\"}, \"obj\":{\"type\":\"keyword\"} } } } } } "
{
"acknowledged" : true,
"shards_acknowledged" : true,
"index" : "demo"
}

注意:笔者使用的Elasticsearch>7.0,Elasticsearch 7.0及以后版本移除映射类型

b. 可用下列命令查询是否添加成功

1
curl -XGET localhost:9200/_search?pretty

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
C:\Users\mmm>curl -XGET localhost:9200/_search?pretty
{
"took" : 3,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 0,
"relation" : "eq"
},
"max_score" : null,
"hits" : [ ]
}
}

c. 如果创建错了,可用下列命令删除索引

1
curl -XDELETE localhost:9200/demo

5)数据导入

Elastic search 7.0及以后版本移除映射类型,修改insert.py

1
2
#原代码 begin_insert_job("demo", "baidu_baike", "../data/baidu_baike.json")
begin_insert_job("demo", "_doc", "../data/baidu_baike.json")

为了测试简单,把actor.json文件改名为../data/baidu_baike.json。

运行 insert.py

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
C:\my\Python\python.exe C:/d/mmm/pycharm/elasticsearch/utils/insert.py
1000
2000
3000
4000
5000
6000
7000
8000
9000
10000
11000
12000
13000

Process finished with exit code 0

6)检索知识库

DOS默认的是(GB2312),让cmd dos 支持utf-8方法CHCP 65001,关闭cmd,CHCP又还原成936。

1
2
C:\Users\mmm>CHCP 65001 
Active code page: 65001

curl方式检索知识库,可用下列命令,如检索:周星驰

1
curl -XGET "localhost:9200/demo/_doc/_search?&pretty" -H "Content-Type:application/json" -d" { \"query\":{ \"bool\":{ \"filter\":{ \"term\":{\"subj\":\"\u5468\u661f\u9a70\"} } } } }

运行结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
curl -XGET "localhost:9200/demo/_doc/_search?&pretty" -H "Content-Type:application/json" -d" { \"query\":{ \"bool\":{ \"filter\":{ \"term\":{\"subj\":\"\u5468\u661f\u9a70\"} } } } }"
{
"took" : 2,
"timed_out" : false,
"_shards" : {
"total" : 1,
"successful" : 1,
"skipped" : 0,
"failed" : 0
},
"hits" : {
"total" : {
"value" : 1,
"relation" : "eq"
},
"max_score" : 0.0,
"hits" : [
{
"_index" : "demo",
"_type" : "_doc",
"_id" : "1",
"_score" : 0.0,
"_source" : {
"subj" : "周星驰",
"po" : [
{
"pred" : "actor_bio",
"obj" : " 周星驰,1962622日生于香港,祖籍浙江宁波,中国香港演员、导演、编剧、制作人、商人,毕业于无线电视艺员训练班。1980年成为丽的电视台的特约演员,从而进入演艺圈。1981年出演个人首部电视剧《IQ成熟时》。1988年将演艺事业的重心转向大银幕,并于同年出演电 影处女作《捕风汉子》。1990年凭借喜剧片《一本漫画闯天涯》确立其无厘头的表演风格 [1]  ;同年,因其主演的喜剧动作片《赌圣》打破香港地区票 房纪录而获得关注 [2]  。1991年主演喜剧片《逃学威龙》,并再次打破香港地区票房纪录 [3]  。1995年凭借喜剧爱情片《大话西游》奠定其在华语影 坛的地位。1999年自导自演的喜剧片《喜剧之王》获得香港电影年度票房冠军 [4]  。2002年凭借喜剧片《少林足球》获得第21届香港电影金像奖最佳男 主角奖以及最佳导演奖 [5]  。2003年成为美国《时代周刊》封面人物 [6]  。2005年凭借喜剧动作片《功夫》获得第42届台湾电影金马奖最佳导演奖 [7]  。2008年自导自演的科幻喜剧片《长江7号》获得香港电影年度票房冠军 [8]  。2013年执导古装喜剧片《西游·降魔篇》,该片以2.18亿美元的票房 成绩打破华语电影在全球的票房纪录 [9-10]  。2016年担任科幻喜剧片《美人鱼》的导演、编剧、制作人,该片以超过33亿元的票房创下中国内地电影票房纪录 [11-14]  。2017128日,担任监制、编剧的古装喜剧片《西游伏妖篇》上映 [15]  。2018年执导《美人鱼2》 [16]  。演艺事业外,周星驰 还涉足商界。1989年成立星炜有限公司 [17]  。1996年成立星辉公司 [18]  。2010年出任比高集团有限公司执行董事 [19]  。 "
},
{
"pred" : "actor_foreName",
"obj" : "Stephen Chow"
},
{
"pred" : "actor_nationality",
"obj" : "中国"
},
{
"pred" : "actor_constellation",
"obj" : "巨蟹座"
},
{
"pred" : "actor_birthPlace",
"obj" : "香港"
},
{
"pred" : "actor_birthDay",
"obj" : "1962622"
},
{
"pred" : "actor_repWorks",
"obj" : "赌圣、逃学威龙系列、唐伯虎点秋香、大话西游系列、喜剧之王、少林足球、功夫、长江七号"
},
{
"pred" : "actor_achiem",
"obj" : "获得两届香港电影金像奖最佳影片\n第21届香港电影金像奖最佳导演\n第21届香港电影金像奖最佳男主角\n第42届台湾电影金马奖最佳导演\n第42届台湾电影金马奖最佳剧情片\n\n第25届台湾电影金马奖最佳男配角\n第28届大众电影百花奖优秀故事片\n第23届香港电影评论学会大 奖最佳导演\n第8届香港电影评论学会大奖最佳电影\n第2届香港电影评论学会大奖最佳男主角\n第37届亚太电影节最佳男主角\n第13届亚洲电影博览会最 佳导演\n获得两届香港电影金紫荆奖最佳影片\n第01届香港电影金紫荆奖最佳男主角\n国际杰人会港澳杰人之星等\n收起"
},
{
"pred" : "actor_brokerage",
"obj" : "星辉公司、比高集团"
}
]
}
}
]
}
}

五. Deepdive抽取演员-电影间关系

deepdive是由斯坦福大学InfoLab实验室开发的一个开源知识抽取系统。它通过弱监督学习,从非结构化的文本中抽取结构化的关系数据 。本项目CNDeepdive修改了自然语言处理的model包,使它支持中文,并提供中文tutorial。 DeepDive项目处于维护模式,并且不再处于主动开发状态。用户社区保持活跃,但是原始项目成员不能再承诺令人兴奋的新功能/改进或响应请求。有关最新研究,请参阅Snorkel项目Ce Zhang的项目

DeepDive可在macOS,Linux和Docker容器中运行,install.sh脚本文件可以检测当前的安装系统环境,并可以一键式完成安装,安装可以参考文档Deepdive 实战-从下载到跑路

deepdive在 Ubuntu 17.04下的支持并不好,虽然作者修改安装代码最终也装上了,但是不建议新手来处理。所以推荐Ubuntu 16.04的版本。 Ubuntu 16.04下载地址,安装Ubuntu主机可参考文章VirtualBox虚拟机安装Ubuntu

1. 安装JDK

1) 设置下载目录

1
2
3
[root@ubuntu-mmm CNdeepdive]# cd /usr/local/
[root@ubuntu-mmm local]# mkdir jdk/
[root@ubuntu-mmm local]# cd jdk/

2) 下载JDK

1
2
3
4
5
6
7
8
9
[root@ubuntu-mmm jdk]# wget https://download.oracle.com/otn/java/jdk/8u221-b11/230deb18db3e4014bb8e3e8324f81b43/jdk-8u221-linux-x64.tar.gz?AuthParam=1570778301_521350e291b71079469aa571d925a2ec
--2019-10-11 14:04:37-- https://download.oracle.com/otn/java/jdk/8u221-b11/230deb18db3e4014bb8e3e8324f81b43/jdk-8u221-linux-x64.tar.gz?AuthParam=1570778301_521350e291b71079469aa571d925a2ec
正在解析主机 download.oracle.com (download.oracle.com)... 23.195.255.150
正在连接 download.oracle.com (download.oracle.com)|23.195.255.150|:443... 已连接。
已发出 HTTP 请求,正在等待回应... 200 OK
长度:195094741 (186M) [application/x-gzip]
正在保存至: “jdk-8u221-linux-x64.tar.gz?AuthParam=1570778301_521350e291b71079469aa571d925a2ec”

r.gz?AuthParam=1570778301_521350e291b7107 5%[===>

3) 解压

使用tar -zxvf 文件名进行解压。

1
[root@ubuntu-mmm jdk]# tar -zxvf jdk-8u221-linux-x64.tar.gz

4) 配置环境变量

1
[root@ubuntu-mmm jdk]# vi /etc/profile

将如下配置添加至文件中,然后保存退出。

1
2
3
4
#java
export JAVA_HOME=/usr/local/jdk/jdk1.8.0_221
export PATH=$JAVA_HOME/bin:$PATH
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib

执行命令,使文件修改后立即生效

1
[root@ubuntu-mmm jdk]# source /etc/profile

5) 验证

1
2
3
4
5
[root@ubuntu-mmm jdk]# java -version

java version "1.8.0_221"
Java(TM) SE Runtime Environment (build 1.8.0_221-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.221-b11, mixed mode)

2. 安装Deepdive

修改install.sh,否则出现报错,无法安装

1
2
# 修改前 tar xzvf "$tarball" -C "$PREFIX"
tar zvf "$tarball" -C "$PREFIX"

运行install.sh 选择【1 】安装deepdive,选择【6】 安装postgresql。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
[root@ubuntu-mmm CNdeepdive]# cd /usr/local/CNdeepdive
[root@ubuntu-mmm CNdeepdive]# bash install.sh
#运行install.sh 分别选择【1 】安装deepdive,选择【6】 安装postgresql。
正在处理用于 dbus (1.10.6-1ubuntu3.3) 的触发器 ...
正在处理用于 ca-certificates (20170717~16.04.1) 的触发器 ...
Updating certificates in /etc/ssl/certs...
0 added, 0 removed; done.
Running hooks in /etc/ca-certificates/update.d...

done.
done.
+ sudo localedef -i en_US -f UTF-8 en_US.UTF-8
## Finished installation for _deepdive_runtime_deps
## Finished installation for deepdive
......
+ trap 'rm -f /tmp/pg_hba.conf.ixUUNdF' EXIT
+ echo 'host all all 127.0.0.1/32 trust'
+ echo 'host all all ::1/128 trust'
+ sudo cat /etc/postgresql/9.5/main/pg_hba.conf
+ sudo tee /etc/postgresql/9.5/main/pg_hba.conf
+ sudo service postgresql restart
++ rm -f /tmp/pg_hba.conf.ixUUNdF
## Finished installation for postgres
......

配置环境变量,deepdive的可执⾏⽂件⼀般安装在~/local/bin⽂件夹下。 在~/.bashrc 文件的末尾添加下面的内容:

1
2
3
4
5
6
7
[root@ubuntu-mmm CNdeepdive]# vi ~/.bashrc
#添加如下内容
#除了root,其他在/home/(username)/local/bin其中的(username)要替换成你当前登录的用户名
export PATH="/root/local/bin:$PATH"

#来使我们的修改生效。
[root@ubuntu-mmm CNdeepdive]# source ~/.bashrc

然后执行下面的命令,安装自然语言处理的部分 。

1
2
3
4
root@ubuntu-mmm:/usr/local/CNdeepdive# bash nlp_setup.sh

Install Dependency.
Denpendency Already Installed.

好的,到这里Deepdive就已经安装完成了 。

打开终端执行deepdive我们可以看到Deepdive的版本信息和命令参数的Help。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
root@ubuntu-mmm:/usr/local/CNdeepdive# deepdive
# DeepDive (v0.8.0-79-g28a58de)
# Usage: deepdive COMMAND [ARG]...

# To enable bash completion for deepdive commands, run:
source $(deepdive whereis installed etc/deepdive_bash_completion.sh)

No COMMAND given

# Available COMMANDs are:
deepdive check # Checks errors in compiled DeepDive app
deepdive compile # Compiles DeepDive source code into executables under run/
deepdive compute # Runs a UDF using a computer against the database
deepdive create # Creates a table/view in the database
deepdive db # Exposes lower level database operations provided by the driver
deepdive do # Runs necessary processes to get something done
deepdive done # Checks whether given targets are all done
deepdive env # Runs commands inside DeepDive's environment
deepdive help # Shows help
deepdive initdb # (DEPRECATED) Initializes the underlying database for the DeepDive application
deepdive load # Loads a given relation's data
deepdive mark # Marks state of something to do
deepdive model # Supports working with the statistical inference model
deepdive plan # Shows execution plan for given targets
deepdive query # Runs a DDlog query against the database for the DeepDive application
deepdive redo # Runs processes after marking them as 'todo'
deepdive run # Runs the current DeepDive app end-to-end
deepdive sql # Runs a SQL query against the database for the DeepDive application
deepdive unload # Unloads a given relation's data
deepdive version # show deepdive's version and build information
deepdive whereis # Finds absolute paths to files in the app or DeepDive installation

3. 建立postgresql的数据库movie

Navicat Premium,是一套数据库开发工具,让你从单一应用程序中同时连接 MySQL、MariaDB、MongoDB、SQL Server、Oracle、PostgreSQL 和 SQLite 数据库。Navicat系列破解工具链接:https://pan.baidu.com/s/1KmH2aaESpjozQaxr2C7D2A

可以使用它来管理PostgreSQL数据库,Navicat连接PostgreSQL,PostgreSQL需要进行如下配置:

1
2
3
4
5
6
7
8
9
10
11
12
1. 通过find / -name  postgresql.conf 和 find / -name pg_hba.conf 找到这两个文件

2. 设置外网访问:

     1)修改配置文件 postgresql.conf
           listen_addresses = '*'
     2)修改pg_hba.conf       在原来的host下面新加一行
           # IPv4 local connections:
           host    all             all             127.0.0.1/32            trust
           host    all             all             0.0.0.0/0               password

3. 重新启动服务:service postgresql restart

在这里我们不使用navicat,可以不安装。

运行 sudo -u postgres createdb 建立数据库movie

1
root@ubuntu-mmm:CNdeepdive# sudo -u postgres createdb movie

如果要删除数据,可以使用下面命令

1
root@ubuntu-mmm:CNdeepdive# sudo -u postgres dropdb movie

验证数据库是否创建成功,首先运行sudo -i -u postgres 进入到postgresql账户

1
root@ubuntu-mmm:/usr/local/CNdeepdive# sudo -i -u postgres

输入psql进入到postgresql命令界面

1
2
3
4
5
postgres@ubuntu-mmm:~$ psql
psql (9.5.19)
Type "help" for help.

postgres=#

修改PostgreSQL登录密码:

1
2
3
postgres=# ALTER USER postgres WITH PASSWORD 'postgres';

ALTER ROLE

查看数据库列表

1
2
3
4
5
6
7
8
9
10
11
postgres=# \l
List of databases
Name | Owner | Encoding | Collate | Ctype | Access privileges
-----------+----------+----------+-------------+-------------+-----------------------
movie | postgres | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 |
postgres | postgres | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 |
template0 | postgres | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
template1 | postgres | UTF8 | zh_CN.UTF-8 | zh_CN.UTF-8 | =c/postgres +
| | | | | postgres=CTc/postgres
(4 rows)

输入\q退出psql。

1
postgres-# \q

运行’’’su yourusername’’’ 回到自己的程序目录。

1
postgres@ubuntu-mmm:~$ su root

4. 项目框架搭建

这部分的数据和代码以及程序都在前面我们解压后的CNdeepdive/transaction中,你可以把这个目录复制到你喜欢的地方(比如~/Projects/transaction 这个位置),然后再新建一个目录,可以叫做transaction2 我们后面的所有工作都是在这个transaction2目录中进行的,后面简称它为项目目录。

建⽴⾃⼰的项⽬⽂件夹transaction2,之前已在postgresql中为项⽬建⽴数据库movie,现要在项⽬⽂件夹下建⽴数据库配置⽂件:

命令说明

1
2
3
echo "postgresql://$USER@$HOSTNAME:5432/db_name" >db.url
#$符号是shell中用来表示变量的,所以这个蓝色部分大概就是 用户名@主机名:。。。。
#db_name 我们这个项目的数据库名,也可以自定义。

创建命令

1
2
3
4
root@ubuntu-mmm:/var/lib/postgresql# cd /usr/local/CNdeepdive
root@ubuntu-mmm:/usr/local/CNdeepdive# mkdir transaction2/
root@ubuntu-mmm:/usr/local/CNdeepdive# cd transaction2
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# echo "postgresql://localhost:5432/movie" >db.url

在deepdive内建立输入数据文件夹 input,用户定义函数文件夹udf,用户配置文件app.ddlog,模型配置文件deepdive.conf。

为了调用 stanford_nlp 进行文本处理,将下载的CNdeepdive 文件夹中的transaction/udf/bazzar复制到自己的 udf 文件夹下,并在udf/bazzar/parser/ 目录下运行 sbt/sbt stage 进行编译。编译完成后会在 target 中生成可执行文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2/udf/bazaar/parser# chmod 777 sbt/sbt
#获得执行权限
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2/udf/bazaar/parser# sbt/sbt stage

Getting org.scala-sbt sbt 0.13.8 ...
:: retrieving :: org.scala-sbt#boot-app
confs: [default]
52 artifacts copied, 0 already retrieved (17674kB/165ms)
Getting Scala 2.10.4 (for sbt)...
:: retrieving :: org.scala-sbt#boot-scala
confs: [default]
5 artifacts copied, 0 already retrieved (24459kB/108ms)
[info] Loading project definition from /usr/local/CNdeepdive/transaction2/udf/bazaar/parser/project/project
[info] Updating {file:/usr/local/CNdeepdive/transaction2/udf/bazaar/parser/project/project/}parser-build-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Loading project definition from /usr/local/CNdeepdive/transaction2/udf/bazaar/parser/project
[info] Updating {file:/usr/local/CNdeepdive/transaction2/udf/bazaar/parser/project/}parser-build...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[info] Set current project to deepdive-nlp-parser (in build file:/usr/local/CNdeepdive/transaction2/udf/bazaar/parser/)
[info] Updating {file:/usr/local/CNdeepdive/transaction2/udf/bazaar/parser/}parser...
[info] Resolving org.fusesource.jansi#jansi;1.4 ...
[info] Done updating.
[warn] Scala version was updated by one of library dependencies:
[warn] * org.scala-lang:scala-library:(2.10.3, 2.10.4, 2.10.2, 2.10.0) -> 2.10.5
[warn] To force scalaVersion, add the following:
[warn] ivyScala := ivyScala.value map { _.copy(overrideScalaVersion = true) }
[warn] Run 'evicted' to see detailed eviction warnings
[info] Compiling 6 Scala sources to /usr/local/CNdeepdive/transaction2/udf/bazaar/parser/target/scala-2.10/classes...
[info] Wrote start script for mainClass := Some(com.clearcut.nlp.Main) to /usr/local/CNdeepdive/transaction2/udf/bazaar/parser/target/start
[success] Total time: 18 s, completed 2019-10-15 16:10:54

5. 修改代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#udf/get_actor_movie.py文件
#删除代码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')
#原代码 open(out_name,'w')
open(out_name,'w',encoding='UTF-8')

#baidu_baike.py文件
#修改前 urlparse.urljoin
urllib.parse.urljoin
#修改前 urlparse
urllib

#pipelines.py文件
#修改前 open("articles.txt", "a+")
open("articles.txt", "a+",encoding='utf-8')
#修改# process info for actor后3行代码为下面
articles = bytes.decode(str(item['articles']).encode('utf-8')).replace("\n", " ")
article_id = bytes.decode(str(item['article_id']).encode('utf-8'))
self.article_file.write(article_id + "," + articles + "\n")
#修改前 .decode('utf-8')
.encode('utf-8')
#删除代码
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

#trans.py文件
#修改前 open("./articles.txt")
open("baidu_baike/articles.txt",encoding='utf-8')
#修改前 open("./articles_new.csv", "w+")
open("./articles_new.csv", "w+",encoding='utf-8')

6. 先验数据导入

用mysql导出工具把actor_to_movie表的数据导出到actor_movie.txt文件,数据格式如下:

1
2
3
4
5
#actor_id movie_id
900 1
10426 9
9412 11
8792 25

运行udf/get_actor_movie.py 获取 input/actor_movie_dbdata.csv 文件

1
2
3
C:\my\Python\python.exe C:/d/mmm/pycharm/deepdive/udf/get_actor_movie.py

Process finished with exit code 0

app.ddlog 中定义相应的数据表,文件内容如下:

1
2
3
4
5
6
7
@source
actor_movie_dbdata(
@key
actor_name text,
@key
movie_name text
).

而后通过命令行生成 postgresql 数据表

a. 行编译操作,也就是在项目目录执行下面的命令:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile

2019-10-16 15:25:51.779111 ‘run/LATEST.COMPILE’ -> ‘20191016/152551.724661396’
2019-10-16 15:25:51.784188 ‘run/RUNNING.COMPILE’ -> ‘20191016/152551.724661396’
2019-10-16 15:25:51.784488 Parsing DeepDive application (/usr/local/CNdeepdive/transaction2) to generate:
2019-10-16 15:25:51.784700 run/compiled/schema.json
2019-10-16 15:25:51.784902 from app.ddlog
2019-10-16 15:25:52.230712 run/compiled/deepdive.conf
2019-10-16 15:25:52.230760 from app.ddlog
2019-10-16 15:25:52.739134 from deepdive.conf
2019-10-16 15:25:52.740832 run/compiled/deepdive.conf.json
2019-10-16 15:25:53.062665 Performing sanity checks on run/compiled/deepdive.conf.json:
2019-10-16 15:25:53.090525 checking if input_extractors_well_defined
2019-10-16 15:25:53.090609 checking if input_schema_wellformed
2019-10-16 15:25:53.090621 Normalizing and adding built-in processes to the data flow to compile:
2019-10-16 15:25:53.090631 run/compiled/config-0.00-init_objects.json
2019-10-16 15:25:53.101117 run/compiled/config-0.01-parse_calibration.json
2019-10-16 15:25:53.108870 run/compiled/config-0.01-parse_schema.json
2019-10-16 15:25:53.126399 run/compiled/config-0.51-add_init_app.json
2019-10-16 15:25:53.132111 run/compiled/config-0.52-input_loader.json
2019-10-16 15:25:53.144006 run/compiled/config-1.00-qualified_names.json
2019-10-16 15:25:53.158387 run/compiled/config-1.01-parse_inference_rules.json
2019-10-16 15:25:53.185708 run/compiled/config-2.01-grounding.json
2019-10-16 15:25:53.287285 run/compiled/config-2.02-learning_inference.json
2019-10-16 15:25:53.303617 run/compiled/config-2.03-calibration_plots.json
2019-10-16 15:25:53.314917 run/compiled/config-9.98-ensure_init_app.json
2019-10-16 15:25:53.324952 run/compiled/config-9.99-dependencies.json
2019-10-16 15:25:53.336073 run/compiled/config.json
2019-10-16 15:25:53.337028 Validating run/compiled/config.json:
2019-10-16 15:25:53.382982 checking if compiled_base_relations_have_input_data
2019-10-16 15:25:53.383035 checking if compiled_dependencies_correct
2019-10-16 15:25:53.383047 checking if compiled_input_output_well_defined
2019-10-16 15:25:53.383056 checking if compiled_output_uniquely_defined
2019-10-16 15:25:53.383064 Compiling executable code into:
2019-10-16 15:25:53.383073 run/compiled/code-cmd_extractor.json
2019-10-16 15:25:53.401750 run/compiled/code-dataflow_dot.json
2019-10-16 15:25:53.417009 run/compiled/code-Makefile.json
2019-10-16 15:25:53.435906 run/compiled/code-sql_extractor.json
2019-10-16 15:25:53.447180 run/compiled/code-tsv_extractor.json
2019-10-16 15:25:53.461059 Generating files:
2019-10-16 15:25:53.471287 run/process/init/app/run.sh
2019-10-16 15:25:53.478829 run/process/init/relation/actor_movie_dbdata/run.sh
2019-10-16 15:25:53.482429 run/dataflow.dot
2019-10-16 15:25:53.484349 run/Makefile
2019-10-16 15:25:53.541030 run/dataflow.svg
2019-10-16 15:25:53.543347 (file:///usr/local/CNdeepdive/transaction2/run/dataflow.svg)
2019-10-16 15:25:53.544398 ‘run/compiled’ -> ‘20191016/152551.724661396’

编译完成后,我们要执行

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive do actor_movie_dbdata

# on ubuntu-mmm: deepdive do actor_movie_dbdata
# run/20191016/152600.104675031/plan.sh
# execution plan for data/actor_movie_dbdata

## process/init/app ##########################################################
# Done: N/A
process/init/app/run.sh
mark_done process/init/app
##############################################################################


## process/init/relation/actor_movie_dbdata ##################################
# Done: N/A
process/init/relation/actor_movie_dbdata/run.sh
mark_done process/init/relation/actor_movie_dbdata
##############################################################################


## data/actor_movie_dbdata ###################################################
# Done: N/A
# no-op
mark_done data/actor_movie_dbdata
##############################################################################

这里do 后面应该和我们app.ddlog 中的名字相同,和input 文件夹中的文件名也相同,他们三个应该都是一致的。他会把input文件中的对应的文件导入postgresql数据库中。注意这个语句执行后,他会进入一个类似vi的界面让你审查他自动生成的处理代码是不是正确,这时候输入:wq 就可以保存并退出,继续执行后面的步骤。运行结果 如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
2019-10-16 15:36:50.793180 
2019-10-16 15:36:50.793341 : ## process/init/app ##########################################################
2019-10-16 15:36:50.793549 : # Done: 2019-10-16T15:31:00+0800 (5m 42s ago)
2019-10-16 15:36:50.793734 : process/init/app/run.sh
2019-10-16 15:36:50.793938 : mark_done process/init/app
2019-10-16 15:36:50.795712 : ##############################################################################
2019-10-16 15:36:50.795906
2019-10-16 15:36:50.796165
2019-10-16 15:36:50.796308 ## process/init/relation/actor_movie_dbdata ##################################
2019-10-16 15:36:50.796550 # Done: N/A
2019-10-16 15:36:50.796758 process/init/relation/actor_movie_dbdata/run.sh
2019-10-16 15:36:50.797006 ++ dirname process/init/relation/actor_movie_dbdata/run.sh
2019-10-16 15:36:50.797202 + cd process/init/relation/actor_movie_dbdata
2019-10-16 15:36:50.797407 + export DEEPDIVE_CURRENT_PROCESS_NAME=process/init/relation/actor_movie_dbdata
2019-10-16 15:36:50.797677 + DEEPDIVE_CURRENT_PROCESS_NAME=process/init/relation/actor_movie_dbdata
2019-10-16 15:36:50.797987 + deepdive create table actor_movie_dbdata
2019-10-16 15:36:50.885518 CREATE TABLE
2019-10-16 15:36:50.886898 + deepdive load actor_movie_dbdata
loading actor_movie_dbdata: 0:00:00 179KiB [ 816MiB/s] ([ 816MiB/s])r_movie_dbdata.csv (csv format)
loading actor_movie_dbdata: 0:00:00 5.94k [ 123k/s] ([ 123k/s])
2019-10-16 15:36:50.996248 COPY 5943
2019-10-16 15:36:50.998965 mark_done process/init/relation/actor_movie_dbdata
2019-10-16 15:36:51.003297 ##############################################################################
2019-10-16 15:36:51.003373
2019-10-16 15:36:51.003386
2019-10-16 15:36:51.003397 ## data/actor_movie_dbdata ###################################################
2019-10-16 15:36:51.003408 # Done: N/A
2019-10-16 15:36:51.003436 # no-op
2019-10-16 15:36:51.003467 mark_done data/actor_movie_dbdata
2019-10-16 15:36:51.006529 ##############################################################################
2019-10-16 15:36:51.006568
2019-10-16 15:36:51.006580
‘run/FINISHED’ -> ‘20191016/153642.492053809

执行完成后,可以执行下面代码在数据库中查询,看看是不是成功导入了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive query '?- actor_movie_dbdata(actor_name, _).'

actor_name
--------------------------------------------------------------------------
周星驰
周星驰
Stephen Chow
Stephen Chow
周星驰
周星驰
Stephen Chow
Stephen Chow
周星驰
周星驰
Stephen Chow
Stephen Chow
周星驰
周星驰
Stephen Chow
Stephen Chow
车保罗
车保罗
Paul Che
Paul Che
张学友
张学友
Jacky Cheung
Jacky Cheung
章子怡
Zhang Ziyi
章子怡
Zhang Ziyi
章子怡

7. 待抽取文章的导入

为了获取到大量的电影和演员相关文章,我们直接套用之前的半结构化数据爬虫来获取非结构文本。

cmd中执行命令:scrapy crawl 项目名

1
2
3
4
PS C:\d\mmm\pycharm\deepdive\udf\baidu_baike\baidu_baike> scrapy crawl baidu
2019-10-16 16:06:06 [scrapy.utils.log] INFO: Scrapy 1.7.3 started (bot: baidu_baike)
2019-10-16 16:06:06 [scrapy.utils.log] INFO: Versions: lxml 4.4.1.0, libxml2 2.9.5, cssselect 1.1.0, parsel 1.5.2, w3lib 1.21.0, Twisted 19.7.0, Python 3.7.4 (tags/v3.7.4:e09359112e, Jul 8 2019, 20:34:20) [MSC v.1916 64 bit (AMD64)], pyOpenSSL 19.0.0 (OpenSSL 1.1.1c 28 May 2019), cryptography 2.7, Platform Windows-10-10.0.18362-SP0
2019-10-16 16:06:06 [scrapy.crawler] INFO: Overridden settings: {'BOT_NAME': 'baidu_baike', 'NEWSPIDER_MODULE': 'baidu_baike.spiders', 'SPIDER_MODULES': ['baidu_baike.spiders'], 'USER_AGENT': 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/61.0.3163.100 Safari/537.36'}

接下来为了将其导入到数据库中,需要将其转换为csv格式,这里可以使用程序 udf/trans.py 进行转换。再更改名字即可。

1
2
3
C:\my\Python\python.exe C:/d/mmm/pycharm/deepdive/udf/trans.py

Process finished with exit code 0

在 app.ddlog 中建立相应的 articles 表:

1
2
3
4
5
@source
articles(
id text,
content text
).

因为下面的 stanford_nlp 进行句法分析时速度特别的慢,因此我抽取出 articles.csv 的头10 行进行实验。
执行 ‘’’ deepdive do articles ‘’’ 将文章导入到 postgresql中

1
2
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive do articles

验证是否成功

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive query '?- articles(id, _).'
id
----
0
1
2
3
4
5
6
7
8
9
10
(11 rows)

8. 用 stanford_nlp 模块进行文本处理

deepdive 默认采⽤standfor nlp进⾏⽂本处理。输⼊⽂本数据,nlp模块将以句子为单位,返回每句的分词、lemma、pos、NER和句法分析的结果,为后续特征抽取做准备。我们将这些结果存入sentences表中。

首先在 app.ddlog 中建立 sentences 表:

1
2
3
4
5
6
7
8
9
10
11
12
13
@source
sentences(
doc_id text,
sentence_index int,
sentences_text text,
tokens text[],
lemmas text[],
pos_tags text[],
ner_tags text[],
doc_offsets int[],
dep_types text[],
dep_tokens int[]
).

而后定义NLP 处理的函数 nlp_markup 来调用自定义的脚本 udf/nlp_markup.sh 进行文本处理。 我们需要对数据处理的方法,deepdive只是个框架,具体要怎么处理需要我们告诉他。所以我们要定义函数来处理articles让他变成sentences。

1
2
3
4
5
function nlp_markup over (
doc_id text,
content text,
) returns rows like sentences
implementation "udf/nlp_markup.sh" handles tsv lines.

说明:

​ function用来定义函数,后面nlp_markup 是函数名 over后面接的是参数表。

​ returns 说明了函数返回的形式,返回就像我们前面定义的sentences那样的一行。

​ 最后一句说明了我们这个程序文件是udf/nlp_markup.sh ,输入是tsv的一行。

使用如下语法调用 nlp_markup 函数,将函数的输出存储到sentences 表中:

1
2
sentences += nlp_markup(doc_id, content) :-
articles(doc_id, content).

说明:上面的+= 其实和其他语言差不多,就是对于来源是articles中的每一行的doc_idcontent 我们都调用nlp_markup 然后结果添加到sentences表中。

编写 udf/nlp_markup.sh,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#!/usr/bin/env bash
# A shell script that runs Bazaar/Parser over documents passed as input TSV lines
#
# $ deepdive env udf/nlp_markup.sh doc_id _ _ content _
##
set -euo pipefail
cd "$(dirname "$0")"

: ${BAZAAR_HOME:=$PWD/bazaar}
[[ -x "$BAZAAR_HOME"/parser/target/start ]] || {
echo "No Bazaar/Parser set up at: $BAZAAR_HOME/parser"
exit 2
} >&2

[[ $# -gt 0 ]] ||
# default column order of input TSV
set -- doc_id content

# convert input tsv lines into JSON lines for Bazaar/Parser


# start Bazaar/Parser to emit sentences TSV
tsv2json "$@" |
"$BAZAAR_HOME"/parser/run.sh -i json -k doc_id -v content

说明:

所有#开头的(除了#!)都是普通注释

参数的用法(

  • $0:调用文件使用的文件名,带有前面的路径,
  • $1-∞:传给脚本的各个参数,
  • $@,$*:这两个都表示传入的所有参数,
  • $#:表示传入参数的个数)

第一行指定了脚本的执行程序

第六行指定了一些程序的错误处理方式等(详见Shell相关文档)

第七行改变当前目录到nlp_markup.py 所在目录,也就是udf 目录

第九行设置了一个变量BAZZER_HOME 他的值是bazaar 的路径

第10-13行执行/parser/target/start 文件,如果有错会不正常退出,并提示

第15-17行检查输入参数的正确性,看参数个数是不是大于0个,如果没有参数,自己设定参数名

第23-24行把全部输入的参数用tsv2json 工具转换成json 格式,然后在执行parser/run.sh 并以刚才的json 作为参数输入。

编译并执行deepdive compile && deepdive do sentences 生成 sentences 表。

预告:运行很慢,耐心等待……

1
2
3
4
5
6
7
8
9
10
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# chmod 777 udf/bazaar/parser/run.sh
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# chmod 777 udf/nlp_markup.sh

root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do sentences

loading dd_tmp_sentences: 0:00:31 0 B [ 0 B/s] ([ 0 B/s])2019-10-17 10:01:41.117623 Reading POS tagger model from edu/stanford/nlp/models/pos-tagger/chinese-distsim/chinese-distsim.tagger ... done [2.1 sec].
2019-10-17 10:01:41.118162 Adding annotator lemma
loading dd_tmp_sentences: 0:00:42 0 B [ 0 B/s] ([ 0 B/s])2019-10-17 10:01:52.480759 Loading classifier from edu/stanford/nlp/models/ner/chinese.misc.distsim.crf.ser.gz ... done [11.3 sec].
loading dd_tmp_sentences: 0:00:43 0 B [ 0 B/s] ([ 0 B/s])2019-10-17 10:01:53.716363 Loading parser from serialized file edu/stanford/nlp/models/lexparser/chineseloading dd_tmp_sentences: 0:00:44 0 B [ 0 B/s] ([ 0 B/s])2019-10-17 10:01:53.943866 Parsing document 0...
......

您可以通过以下命令来查询生成的结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive query '
doc_id, index, tokens, ner_tags | 5
?- sentences(doc_id, index, text, tokens, lemmas, pos_tags, ner_tags, _, _, _).
'

doc_id | index | tokens | ner_tags
--------+-------+---------------------------------------------------------------------------------------------------------------------------------------------------------------------------+-----------------------------------------------------------------------------------------------------------
0 | 1 | {周星驰,,,1962年,6月,22日,生,于,香港,,,祖籍,浙江,宁波,,,中国,香港,演员,、,导演,、,编剧,、,制作人,、,商人,,,毕业于,无线,电视,艺员,训练班,。} | {PERSON,O,MISC,MISC,MISC,O,O,GPE,O,O,GPE,GPE,O,GPE,GPE,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O}
0 | 2 | {1980年,成为,丽的,电视台,的,特约,演员,,,从而,进入,演艺圈,。} | {O,O,O,O,O,O,O,O,O,O,O,O}
0 | 3 | {1981年,出演,个人,首部,电视剧,《,IQ,成熟,时,》,。} | {O,O,O,O,O,O,MISC,MISC,MISC,O,O}
0 | 4 | {1988年,将,演艺,事业,的,重心,转向,大,银幕,,,并,于,同,年,出演,电影,处女,作,《,捕,风,汉子,》,。} | {O,O,O,O,O,O,O,O,O,O,O,O,MISC,MISC,O,O,O,O,O,MISC,MISC,MISC,O,O}
0 | 5 | {1990年,凭借,喜剧片,《,一,本,漫画,闯,天涯,》,确立,其,无厘头,的,表演,风格,(,1,),;,同年,,,因其,主演,的,喜剧,动作片,《,赌圣,》,打破,香港,地区,票房,纪录,而,获得,关注,(,2,),。} | {O,O,O,O,MISC,MISC,MISC,MISC,MISC,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,O,MISC,O,O,GPE,O,O,O,O,O,O,O,O,O,O}
(5 rows)

9.候选实体的生成

首先介绍演员候选实体的生成。首先我们在app.ddlog 中定义实体数据表:

1
2
3
4
5
6
7
8
9
@extraction
actor_mention(
mention_id text,
mention_text text,
doc_id text,
sentences_index int,
begin_index int,
end_index int
).

该表包含了实体的id、内容、所在文本的id、所在句子的索引、起始和终止位置索引。

而后继续定义实体抽取函数:

1
2
3
4
5
6
7
8
function map_actor_mention over(
doc_id text,
sentence_index int,
tokens text[],
pos_tags text[],
ner_tags text[]
) returns rows like actor_mention
implementation "udf/map_actor_mention.py" handles tsv lines.

其中 udf/map_actor_mention.py 脚本遍历数据库中的句子,找到连续的NER标记为PERSON 且 POS 标记为NR的序列,再对其做过滤整合处理,返回候选实体。

最后我们在 app.ddlog 中调用函数,将 函数的输出存储到 actor_mention 表中。

1
2
3
4
actor_mention += map_actor_mention(
doc_id, sentence_index, tokens, pos_tags, ner_tags
) :-
sentences(doc_id, sentence_index, _, tokens, _, pos_tags, ner_tags, _, _, _).

现在我们可以编译并执行得到 actor_mention 表了。

1
2
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# chmod 777 udf/map_actor_mention.py
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do actor_mention

同理可以得到 电影类的实体表 movie_mention :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@extraction
movie_mention(
mention_id text,
mention_text text,
doc_id text,
sentences_index int,
begin_index int,
end_index int
).

function map_movie_mention over(
doc_id text,
sentence_index int,
tokens text[],
pos_tags text[],
ner_tags text[]
) returns rows like movie_mention
implementation "udf/map_movie_mention.py" handles tsv lines.

movie_mention += map_movie_mention(
doc_id, sentence_index, tokens, pos_tags, ner_tags
) :-
sentences(doc_id, sentence_index, _, tokens, _, pos_tags, ner_tags, _, _, _).

编译并执行

1
2
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# chmod 777 udf/map_movie_mention.py
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do movie_mention

查询看一下得到的实体:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive query '
mention_id, mention_text, doc_id | 5
?- movie_mention(mention_id, mention_text, doc_id, _, _, _).
'

mention_id | mention_text | doc_id
------------+--------------+--------
0_5_28_28 | 赌圣 | 0
0_7_6_6 | 大话西游 | 0
0_7_11_11 | 华语 | 0
0_8_6_6 | 喜剧 | 0
0_9_4_4 | 少林足球 | 0
(5 rows)

10. 生成候选实体对

这一步我们要生成候选实体对,首先定义数据表如下:

1
2
3
4
5
6
7
@extraction
play_candidate(
p1_id text,
p1_name text,
p2_id text,
p2_name text
).

包含实体1/2 的id 和内容。接下来统计每个句子的实体数量以限制同一句内出现过多实体:

1
2
3
num_entity(doc_id, sentence_index, COUNT(p) + COUNT(q)) :-
actor_mention(p, _, doc_id, sentence_index, _, _),
movie_mention(q, _, doc_id, sentence_index, _, _).

而后定义过滤函数:

1
2
3
4
5
6
7
function map_play_candidate over (
p1_id text,
p1_name text,
p2_id text,
p2_name text
) returns rows like play_candidate
implementation "udf/map_play_candidate.py" handles tsv lines.

该函数内您可以定义一些规则对候选实体对进行筛选。

接下来调用上述函数并结合一些规则对实体对进行进一步的筛选,将筛选结果存储到 play_candidate 数据表中:

1
2
3
4
5
6
7
play_candidate += map_play_candidate(p1, p1_name, p2, p2_name) :-
num_entity(same_doc, same_sentence, num_e),
actor_mention(p1, p1_name, same_doc, same_sentence, p1_begin, _),
movie_mention(p2, p2_name, same_doc, same_sentence, p2_begin, _),
num_e < 5,
p1_name != p2_name,
p1_begin != p2_begin.

编译并执行得到候选实体对表:

1
2
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# chmod 777 udf/map_play_candidate.py
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do play_candidate

查询一下看看结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive query '
p1_text, p2_text | 5
?- play_candidate(_, p1_text, _, p2_text).
'

p1_text | p2_text
--------------+----------
周星驰 | 滕王阁序
周星驰 | 北斗
龙炳基 | 北斗
赵子龙 | 生命
郑佩佩 | 审死官
(5 rows)

11. 特征抽取

现在我们要用deeodive自带的 ddlib 库抽选实体对的文本特征。

首先定义特征表:

1
2
3
4
5
6
@extraction
play_feature(
p1_id text,
p2_id text,
feature text
).

该特征是实体对间一系列文本特征的集合。

而后我们定义特征提取函数得到各种 POS/NER/次序列的窗口特征等。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function extract_play_features over (
p1_id text,
p2_id text,
p1_begin_index int,
p1_end_index int,
p2_begin_index int,
p2_end_index int,
doc_id text,
sent_index int,
tokens text[],
lemmas text[],
pos_tags text[],
ner_tags text[],
dep_types text[],
dep_tokens int[]
) returns rows like play_feature
implementation "udf/extract_play_features.py" handles tsv lines.

而后调用该函数:

1
2
3
4
5
6
7
play_feature += extract_play_features(
p1_id, p2_id, p1_begin_index, p1_end_index, p2_begin_index, p2_end_index,
doc_id, sent_index, tokens, lemmas, pos_tags, ner_tags, dep_types, dep_tokens
) :-
actor_mention(p1_id, _, doc_id, sent_index, p1_begin_index, p1_end_index),
movie_mention(p2_id, _, doc_id, sent_index, p2_begin_index, p2_end_index),
sentences(doc_id, sent_index, _, tokens, lemmas, pos_tags, ner_tags, _, dep_types, dep_tokens).

编译并执行:

预告:运行很慢,耐心等待……

1
2
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# chmod 777 udf/extract_play_features.py
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do play_feature

查询看一下特征:

1
2
3
4
5
6
7
8
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive query '| 5 ?- play_feature(_, _, feature).'

IS_INVERTED
INV_WORD_SEQ_[》 是 2006年 上映 的 一 部 宫廷 悲剧 电影 , 该 片 根据 莎士比亚 名剧 《 哈姆雷特 》 改编 , 由 冯小刚 导演 , 主要 演员 有 章子怡 、 葛优 、 吴彦祖 、]
INV_LEMMA_SEQ_[》 是 2006年 上映 的 一 部 宫廷 悲剧 电影 , 该 片 根据 莎士比亚 名剧 《 哈姆雷特 》 改编 , 由 冯小刚 导演 , 主要 演员 有 章子怡 、 葛优 、 吴彦祖 、]
INV_NER_SEQ_[O O MISC O O O O O O O O O O O O O O MISC O O O O PERSON O O O O O PERSON O PERSON O PERSON O]
INV_POS_SEQ_[PU VC NT VV DEC CD M NN NN NN PU DT NN P NR NN PU NR PU VV PU P NR NN PU JJ NN VE NR PU NR PU NR PU]
(5 rows)

12. 有监督数据处理

首先在 app.ddlog 中定义 play_label 表存放有监督数据:

1
2
3
4
5
6
7
8
9
10
11
12
13
@extraction             
play_label(
@key
@references(relation="has_play", column="p1_id", alias="has_play")
p1_id text,
@key
@references(relation="has_play", column="p2_id", alias="has_play")
p2_id text,
@navigable
label int,
@navigable
rule_id text
).

rule_id 表示相关性的规则名称,label 为正值表示正相关,负值表示负相关。绝对值越大,相关性越大。

初始化定义,复制 play_candidate 表,label 初始化为0,rule_id 为 NULL:

1
paly_label(p1, p2, 0, NULL) :- play_candidate(p1, _, p2, _).

接下来将最开始导入的有监督数据表 actor_movie_dbdata 导入到 play_label 中,并赋予权重3:

1
2
3
4
play_label(p1, p2, 3, "from_dbdata") :-
play_candidate(p1, p1_name, p2, p2_name),
actor_movie_dbdata(n1, n2),
[lower(n1) = lower(p1_name), lower(n2) = lower(p2_name)].

13. 预标记

接下来定义一些逻辑规则对文本进行预标记:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function supervise over (      
p1_id text, p1_begin int, p1_end int,
p2_id text, p2_begin int, p2_end int,
doc_id text,
doc_id text,
sentence_index int,
sentence_text text,
tokens text[],
lemmas text[],
pos_tags text[],
ner_tags text[],
dep_types text[],
dep_tokens int[]
) returns (p1_id text, p2_id text, label int, rule_id text)
implementation "udf/supervise_play.py" handles tsv lines.

程序 udf/supervise_play.py 里通过一些指定的规则如 出演这种特征来进行预标记。给出label和rule_id的值。

接下来调用标记函数,将规则抽到的数据写到play_label 表中:

1
2
3
4
5
6
7
8
9
10
11
12
play_label += supervise(
p1_id, p1_begin, p1_end,
p2_id, p2_begin, p2_end,
doc_id, sentence_index, sentence_text,
tokens, lemmas, pos_tags, ner_tags, dep_types, dep_tokens_indexes
) :-
play_candidate(p1_id, _, p2_id, _),
actor_mention(p1_id, p1_text, doc_id, sentence_index, p1_begin, p1_end),
movie_mention(p2_id, p2_text, _, _, p2_begin, p2_end),
sentences( doc_id, sentence_index, sentence_text,
tokens, lemmas, pos_tags, ner_tags, _, dep_types, dep_tokens_indexes
).

由于不同的规则可能覆盖了相同的实体对,因此利用 vote方法进行综合给出最终标记:

1
2
play_label_resolved(p1_id, p2_id, SUM(vote)) :-
play_label(p1_id, p2_id, vote, rule_id).

最后编译并执行:

1
2
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# chmod 777 udf/supervise_play.py
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do play_label_resolved

14. 变量表定义

首先定义最终存储的表格,[?]表示此表是用户模式下的变量表,即需要推到关系的表。这里我们需要推到的是演员和电影间是否存在演出关系。

1
2
3
4
5
@extraction
has_play?(
p1_id text,
p2_id text
).

根据打标结果,写入已知的变量:

1
2
3
4
has_play(p1_id, p2_id) = if l > 0 then TRUE
else if l < 0 then FALSE
else NULL end :-
play_label_resolved(p1_id, p2_id, l).

此时表中部分变量的label 已知,成为了先验变量。编译并执行:

1
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do has_play

15. 构建因子图

指定特征:

将每一对 has_play 中的实体对和特征表连接起来,通过特征因子连接,全局学习这些特征的权重 f

1
2
3
4
@weight(f)
has_play(p1_id, p2_id) :-
play_candidate(p1_id, _, p2_id, _),
play_feature(p1_id, p2_id, f).

编译并生成最终的概率模型:

1
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive compile && deepdive do probabilities

就完成了我们的推断,现在查询我们预测的演员-电影间的交易关系概率:

1
2
3
4
5
6
7
8
9
10
root@ubuntu-mmm:/usr/local/CNdeepdive/transaction2# deepdive sql "SELECT p1_id, p2_id, expectation FROM has_play_label_inference ORDER BY random() LIMIT 5"

p1_id | p2_id | expectation
------------+------------+-------------
6_38_20_20 | 6_38_44_44 | 0.926
0_30_36_36 | 0_30_57_57 | 0.082
0_39_83_83 | 0_39_94_95 | 0.214
6_21_7_8 | 6_21_43_43 | 0.003
5_66_0_0 | 5_66_20_21 | 0.008
(5 rows)

至此,使用deepdive 抽取非结构文本的演员-电影关系实战完成。

待续……