素人的自然语言处理100训练:第64题

這是2015年《自然語言處理100本挑戰》的紀錄。我所使用的環境是Ubuntu 16.04 LTS + Python 3.5.2 :: Anaconda 4.1.1 (64-bit)。您可以在這裡找到之前挑戰的列表。

第七章:数据库

artist.json.gz是一个文件,它是在开放音乐数据库MusicBrainz中,将与艺术家相关的信息转换为JSON格式,并以gzip格式进行压缩的。该文件中每一行都以JSON格式存储了关于一个艺术家的信息。JSON格式的概述如下:

字段 类型 内容 示例
id 唯一标识符 整数 20660
gid 全局标识符 字符串 “ecf9f3a3-35e9-4c58-acaa-e707fba45060”
name 艺术家名字 字符串 “Oasis”
sort_name 艺术家名字(用于字典顺序排序) 字符串 “Oasis”
area 活动地点 字符串 “United Kingdom”
aliases 别名 字典对象列表
aliases[].name 别名 字符串 “オアシス”
aliases[].sort_name 别名(用于排序) 字符串 “オアシス”
begin 活动开始日期 字典
begin.year 活动开始年 整数 1991
begin.month 活动开始月 整数
begin.date 活动开始日 整数
end 活动结束日期 字典
end.year 活动结束年 整数 2009
end.month 活动结束月 整数 8
end.date 活动结束日 整数 28
tags 标签 字典对象列表
tags[].count 标签出现次数 整数 1
tags[].value 标签内容 字符串 “rock”
rating 评分 字典对象
rating.count 评分投票数 整数 13
rating.value 评分值(平均值) 整数 86

考虑将artist.json.gz的数据存储和检索到键值存储(KVS)和面向文档的数据库中。可以使用LevelDB、Redis、KyotoCabinet等作为KVS。作为面向文档的数据库,选择使用MongoDB,也可以使用CouchDB或RethinkDB等。

64. MongoDB的建立

将艺术家信息(artist.json.gz)注册到数据库。并在以下字段上创建索引:name、aliases.name、tags.value、rating.value。

完成的代码出来了。

# coding: utf-8
import gzip
import json
import pymongo
from pymongo import MongoClient

fname = 'artist.json.gz'
unit_bulk = 10000       # バルクインサートする単位(件)

# MongoDBのデータベースtestdbにコレクションartistを作成
client = MongoClient()
db = client.testdb
collection = db.artist

# gzファイル読み込み
with gzip.open(fname, 'rt') as data_file:

    # 1行ずつパースしてbufに詰め込む
    buf = []
    for i, line in enumerate(data_file, 1):
        data_json = json.loads(line)
        buf.append(data_json)

        # unit_bulk件たまったらartistへバルクインサート
        if i % unit_bulk == 0:
            collection.insert_many(buf)
            buf = []
            print('{}件追加完了'.format(i))

    # 最後のunit_bulkに入らなかった半端分の追加
    if len(buf) > 0:
        collection.insert_many(buf)
        print('{}件追加完了'.format(i))

# インデックス作成
collection.create_index([('name', pymongo.ASCENDING)])  
collection.create_index([('aliases.name', pymongo.ASCENDING)])  
collection.create_index([('tags.value', pymongo.ASCENDING)])
collection.create_index([('rating.value', pymongo.ASCENDING)])

执行结果:

10000件追加完了
20000件追加完了
30000件追加完了
40000件追加完了
50000件追加完了
(中略)
890000件追加完了
900000件追加完了
910000件追加完了
920000件追加完了
921337件追加完了

MongoDB 是什么?

MongoDB是一种被称为文档数据库的东西,它具有类似于本次问题中使用的音乐数据库的结构,能够存储和管理这种数据的特点。这是它的官方网站,很遗憾是用英文的,但MongoDB的概述有日文。此外,因为网络上有很多关于MongoDB的解释,所以请自行搜索以获取更详细的信息。

此外,据我了解,MongoDB也有付费版,但本次我们使用的是免费的Community Edition。

安装MongoDB

我以为用conda只需要一步,但是需要编写服务脚本吗?听起来有点麻烦,所以这次我按照官方网站的步骤进行了安装。

我在使用的Ubuntu 16.04 LTS上安装MongoDB Community Edition的步骤可以在”在Ubuntu上安装MongoDB Community Edition”找到。虽然是用英文写的,但并不难。按照”安装MongoDB Community Edition”的指示进行操作,就能成功安装。

segavvy@ubuntu:~$ sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 0C49F3730359A14518585931BC711F9BA15703C6
[sudo] segavvy のパスワード: 
Executing: /tmp/tmp.8h93YVjQSG/gpg.1.sh --keyserver
hkp://keyserver.ubuntu.com:80
--recv
0C49F3730359A14518585931BC711F9BA15703C6
gpg: 鍵A15703C6をhkpからサーバkeyserver.ubuntu.comに要求
gpg: 鍵A15703C6: 公開鍵"MongoDB 3.4 Release Signing Key <packaging@mongodb.com>"をインポートしました
gpg: 処理数の合計: 1
gpg:               インポート: 1  (RSA: 1)
segavvy@ubuntu:~$ echo "deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.4.list
deb [ arch=amd64,arm64 ] http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 multiverse
segavvy@ubuntu:~$ sudo apt-get update
無視:1 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 InRelease
取得:2 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 Release [3,452 B]
ヒット:3 http://us.archive.ubuntu.com/ubuntu xenial InRelease                  
取得:4 http://security.ubuntu.com/ubuntu xenial-security InRelease [102 kB]    
取得:5 http://us.archive.ubuntu.com/ubuntu xenial-updates InRelease [102 kB]   
取得:6 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4 Release.gpg [801 B]
取得:7 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4/multiverse amd64 Packages [2,778 B]
取得:8 http://us.archive.ubuntu.com/ubuntu xenial-backports InRelease [102 kB] 
取得:9 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4/multiverse arm64 Packages [2,784 B]
取得:10 http://security.ubuntu.com/ubuntu xenial-security/main amd64 DEP-11 Metadata [68.1 kB]
取得:11 http://us.archive.ubuntu.com/ubuntu xenial-updates/main amd64 DEP-11 Metadata [303 kB]
取得:12 http://security.ubuntu.com/ubuntu xenial-security/main DEP-11 64x64 Icons [43.0 kB]
取得:13 http://security.ubuntu.com/ubuntu xenial-security/universe amd64 DEP-11 Metadata [19.4 kB]
取得:14 http://security.ubuntu.com/ubuntu xenial-security/universe DEP-11 64x64 Icons [25.6 kB]
取得:15 http://security.ubuntu.com/ubuntu xenial-security/multiverse amd64 DEP-11 Metadata [212 B]
取得:16 http://us.archive.ubuntu.com/ubuntu xenial-updates/main DEP-11 64x64 Icons [179 kB]
取得:17 http://us.archive.ubuntu.com/ubuntu xenial-updates/universe amd64 DEP-11 Metadata [121 kB]
取得:18 http://us.archive.ubuntu.com/ubuntu xenial-updates/universe DEP-11 64x64 Icons [145 kB]
取得:19 http://us.archive.ubuntu.com/ubuntu xenial-updates/multiverse amd64 DEP-11 Metadata [2,520 B]
取得:20 http://us.archive.ubuntu.com/ubuntu xenial-backports/main amd64 DEP-11 Metadata [208 B]
取得:21 http://us.archive.ubuntu.com/ubuntu xenial-backports/universe amd64 DEP-11 Metadata [212 B]
取得:22 http://us.archive.ubuntu.com/ubuntu xenial-backports/multiverse amd64 DEP-11 Metadata [212 B]
ヒット:23 http://archive.ubuntulinux.jp/ubuntu xenial InRelease                
無視:24 http://archive.ubuntulinux.jp/ubuntu-ja-non-free xenial InRelease      
ヒット:25 http://archive.ubuntulinux.jp/ubuntu-ja-non-free xenial Release      
1,223 kB を 15秒 で取得しました (80.2 kB/s)                                    
AppStream cache update completed, but some metadata was ignored due to errors.
パッケージリストを読み込んでいます... 完了
segavvy@ubuntu:~$ sudo apt-get install -y mongodb-org
パッケージリストを読み込んでいます... 完了
依存関係ツリーを作成しています                
状態情報を読み取っています... 完了
以下のパッケージが自動でインストールされましたが、もう必要とされていません:
  ubuntu-core-launcher
これを削除するには 'sudo apt autoremove' を利用してください。
以下の追加パッケージがインストールされます:
  mongodb-org-mongos mongodb-org-server mongodb-org-shell mongodb-org-tools
以下のパッケージが新たにインストールされます:
  mongodb-org mongodb-org-mongos mongodb-org-server mongodb-org-shell
  mongodb-org-tools
アップグレード: 0 個、新規インストール: 5 個、削除: 0 個、保留: 16 個。
66.6 MB のアーカイブを取得する必要があります。
この操作後に追加で 269 MB のディスク容量が消費されます。
取得:1 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4/multiverse amd64 mongodb-org-shell amd64 3.4.1 [7,955 kB]
取得:2 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4/multiverse amd64 mongodb-org-server amd64 3.4.1 [14.2 MB]
取得:3 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4/multiverse amd64 mongodb-org-mongos amd64 3.4.1 [8,093 kB]
取得:4 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4/multiverse amd64 mongodb-org-tools amd64 3.4.1 [36.3 MB]
取得:5 http://repo.mongodb.org/apt/ubuntu xenial/mongodb-org/3.4/multiverse amd64 mongodb-org amd64 3.4.1 [3,564 B]
66.6 MB を 12秒 で取得しました (5,236 kB/s)                                    
以前に未選択のパッケージ mongodb-org-shell を選択しています。
(データベースを読み込んでいます ... 現在 209736 個のファイルとディレクトリがインストールされています。)
.../mongodb-org-shell_3.4.1_amd64.deb を展開する準備をしています ...
mongodb-org-shell (3.4.1) を展開しています...
以前に未選択のパッケージ mongodb-org-server を選択しています。
.../mongodb-org-server_3.4.1_amd64.deb を展開する準備をしています ...
mongodb-org-server (3.4.1) を展開しています...
以前に未選択のパッケージ mongodb-org-mongos を選択しています。
.../mongodb-org-mongos_3.4.1_amd64.deb を展開する準備をしています ...
mongodb-org-mongos (3.4.1) を展開しています...
以前に未選択のパッケージ mongodb-org-tools を選択しています。
.../mongodb-org-tools_3.4.1_amd64.deb を展開する準備をしています ...
mongodb-org-tools (3.4.1) を展開しています...
以前に未選択のパッケージ mongodb-org を選択しています。
.../mongodb-org_3.4.1_amd64.deb を展開する準備をしています ...
mongodb-org (3.4.1) を展開しています...
man-db (2.7.5-1) のトリガを処理しています ...
mongodb-org-shell (3.4.1) を設定しています ...
mongodb-org-server (3.4.1) を設定しています ...
システムユーザー `mongodb' (UID 121) を追加しています...
新しいユーザー `mongodb' (UID 121) をグループ `nogroup' に追加しています...
ホームディレクトリ `/home/mongodb' を作成しません。
グループ `mongodb' (GID 129) を追加しています...
完了。
ユーザー `mongodb' をグループ `mongodb' に追加しています...
ユーザ mongodb をグループ mongodb に追加
完了。
mongodb-org-mongos (3.4.1) を設定しています ...
mongodb-org-tools (3.4.1) を設定しています ...
mongodb-org (3.4.1) を設定しています ...

由于安装MongoDB核心已经完成,现在确认启动。

segavvy@ubuntu:~$ sudo service mongod start

可以通过”验证MongoDB是否成功启动”的步骤来确认它是否已经正常启动。

2017-01-09T22:00:38.186+0900 I CONTROL  [initandlisten] MongoDB starting : pid=4384 port=27017 dbpath=/var/lib/mongodb 64-bit host=ubuntu
2017-01-09T22:00:38.186+0900 I CONTROL  [initandlisten] db version v3.4.1
2017-01-09T22:00:38.186+0900 I CONTROL  [initandlisten] git version: 5e103c4f5583e2566a45d740225dc250baacfbd7
2017-01-09T22:00:38.186+0900 I CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.0.2g  1 Mar 2016
(中略)
2017-01-09T22:00:38.254+0900 I FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory '/var/lib/mongodb/diagnostic.data'
2017-01-09T22:00:38.265+0900 I INDEX    [initandlisten] build index on: admin.system.version properties: { v: 2, key: { version: 1 }, name: "incompatible_with_version_32", ns: "admin.system.version" }
2017-01-09T22:00:38.265+0900 I INDEX    [initandlisten]      building index using bulk method; build may temporarily use up to 500 megabytes of RAM
2017-01-09T22:00:38.266+0900 I INDEX    [initandlisten] build index done.  scanned 0 total records. 0 secs
2017-01-09T22:00:38.266+0900 I COMMAND  [initandlisten] setting featureCompatibilityVersion to 3.4
2017-01-09T22:00:38.267+0900 I NETWORK  [thread1] waiting for connections on port 27017

因为在最后一行写着“在端口27017上等待连接”,所以看起来应该没问题。

安装PyMongo

接下来是安装PyMongo来使用Python操作MongoDB,但这只需要一行conda命令。

segavvy@ubuntu:~$ conda search pymongo
Fetching package metadata .......
pymongo                      2.7.2                    py26_0  defaults        
                             2.7.2                    py27_0  defaults        
                             2.7.2                    py33_0  defaults        
                             2.7.2                    py34_0  defaults        
                             2.8                      py26_0  defaults        
                             2.8                      py27_0  defaults        
                             2.8                      py33_0  defaults        
                             2.8                      py34_0  defaults        
                             3.0.3                    py27_0  defaults        
                             3.0.3                    py34_0  defaults        
                             3.0.3                    py35_0  defaults        
                             3.3.0                    py27_0  defaults        
                             3.3.0                    py34_0  defaults        
                             3.3.0                    py35_0  defaults        
                             3.3.0                    py36_0  defaults        
segavvy@ubuntu:~$ conda install pymongo
Fetching package metadata .......
Solving package specifications: ..........

Package plan for installation in environment /home/segavvy/anaconda3:

The following packages will be downloaded:

    package                    |            build
    ---------------------------|-----------------
    pymongo-3.3.0              |           py35_0         376 KB

The following NEW packages will be INSTALLED:

    pymongo: 3.3.0-py35_0

Proceed ([y]/n)? y

Fetching packages ...
pymongo-3.3.0- 100% |################################| Time: 0:00:00   8.30 MB/s
Extracting packages ...
[      COMPLETE      ]|###################################################| 100%
Linking packages ...
[      COMPLETE      ]|###################################################| 100%

我会确认一下Python的可用性。

segavvy@ubuntu:~$ python
Python 3.5.2 |Anaconda 4.1.1 (64-bit)| (default, Jul  2 2016, 17:53:06) 
[GCC 4.4.7 20120313 (Red Hat 4.4.7-1)] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import pymongo
>>> 

环境已经搭建完毕。

启动、关闭、重启MongoDB

在安装步骤的后半部分,启动、关闭和重新启动的方法被整理在”运行 MongoDB Community Edition”中。

segavvy@ubuntu:~$ sudo service mongod start
segavvy@ubuntu:~$ sudo service mongod stop
segavvy@ubuntu:~$ sudo service mongod restart

使用MongoDB的命令行界面(交互式Shell)

在MongoDB启动时,可以使用mongo命令执行各种操作。使用svjunic整理的MongoDB命令备忘录非常方便。
以下是显示数据库列表的示例。

segavvy@ubuntu:~$ mongo
MongoDB shell version v3.4.1
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.4.1
Server has startup warnings: 
2017-01-14T12:51:31.792+0900 I STORAGE  [initandlisten] 
2017-01-14T12:51:31.792+0900 I STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
2017-01-14T12:51:31.792+0900 I STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] 
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] 
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] 
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] 
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'.
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] **        We suggest setting it to 'never'
2017-01-14T12:51:32.332+0900 I CONTROL  [initandlisten] 
> show dbs
admin   0.000GB
local   0.000GB
testdb  0.254GB
> 

在运行mongo命令后,会出现许多警告信息。在使用正式系统时,最好进行相应的处理。顺便提一下,在数据库列表中的“testdb”在安装后是不存在的。它是根据本次问题执行而创建的。

使用PyMongo进行编程

如果你看一下PyMongo的教程(本次使用conda安装的版本是3.3.0)(最新版本在这里),基本上就能理解怎么使用PyMongo。

在这个问题中,我们创建了一个名为”testdb”的数据库,并在其中创建了一个名为”artist”的集合,并且持续不断地向其中注册JSON数据。

大容量插入

为了处理目前近百万条记录,注册使用了Bulk Insert功能,尽管使用collection.insert_one()(最新)逐一注册也是可以的。

每次执行collection.insert_one()都会向MongoDB服务器发送注册请求,所以批量重复执行时会产生不可忽视的开销。而使用collection.insert_many()(最新)可以将多个数据打包成一个列表,并一次性发送注册请求,从而减少与服务器的往返次数,提高效率。本次使用这个功能将每次注册1万条数据。然而,即使如此,如果接近100万条数据,仍然需要较长时间,因此我们设置每1万条数据显示一次处理进度。

关于Bulk Insert,Tutorial的Bulk Inserts(最新)中有一个概述说明。

创建索引

你可以使用collection.create_index()函数创建索引,从而提高搜索速度。在“Tutorial的Indexing”中有关于此的概要说明。

第65号的练习到此为止了。如果有错误或者其他问题,请指正,谢谢。


实施结果中包含一部分使用100本敲击所使用的语料库数据,这些数据是通过发行的。第7章使用的数据的许可是创作共用 署名-非商业性使用-相同方式共享3.0(非移植)(中文翻译)。

bannerAds