LoginSignup
3
1

More than 5 years have passed since last update.

素人の言語処理100本ノック:64

Last updated at Posted at 2017-01-18

言語処理100本ノック 2015の挑戦記録です。環境はUbuntu 16.04 LTS + Python 3.5.2 :: Anaconda 4.1.1 (64-bit)です。過去のノックの一覧はこちらからどうぞ。

第7章: データベース

artist.json.gzは,オープンな音楽データベースMusicBrainzの中で,アーティストに関するものをJSON形式に変換し,gzip形式で圧縮したファイルである.このファイルには,1アーティストに関する情報が1行に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のデータをKey-Value-Store (KVS) およびドキュメント志向型データベースに格納・検索することを考える.KVSとしては,LevelDB,Redis,KyotoCabinet等を用いよ.ドキュメント志向型データベースとして,MongoDBを採用したが,CouchDBやRethinkDB等を用いてもよい.

64. MongoDBの構築

アーティスト情報(artist.json.gz)をデータベースに登録せよ.さらに,次のフィールドでインデックスを作成せよ: name, aliases.name, tags.value, rating.value

出来上がったコード:

main.py
# 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へのインストール手順はInstall MongoDB Community Edition on Ubuntuにあります。英語ですがそれほど難しくはありません。Install MongoDB Community Editionの通りにやっていくとインストールできました。

MongoDBのインストール
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本体のインストールができましたので、起動することを確認します。

MongoDBの起動
segavvy@ubuntu:~$ sudo service mongod start

正常に起動したかどうかは、Verify that MongoDB has started successfullyの手順で確認できます。

/var/log/mongodb/mongod.logの確認
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

最後の行に「waiting for connections on port 27017」とあるので、これで大丈夫そうです。

PyMongoのインストール

続いて、PythonでMongoDBを使うためのPyMongoのインストールですが、これはconda一発です。

PyMongoのインストール
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で使えることを確認しておきます。

PyMongoのインストールの確認
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の起動、終了、再起動

起動、終了、再起動の方法は、インストール手順の後半にあるRun MongoDB Community Editionにまとまっています。

MongoDBの起動
segavvy@ubuntu:~$ sudo service mongod start
MongoDBの終了
segavvy@ubuntu:~$ sudo service mongod stop
MongoDBの再起動
segavvy@ubuntu:~$ sudo service mongod restart

MongoDBのコマンド(インタラクティブシェル)

MongoDBの起動中はmongoコマンドでいろいろできます。svjunicさんがまとめられているMongoDB コマンドメモとか書きが便利です。
以下、DB一覧の表示例です。

mongoコマンドでDB一覧の表示
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コマンドの実行直後にワーニングがたくさん出てきています。ちゃんとしたシステムで使う時は対応した方が良さそうですね。ちなみにDB一覧の中にある「testdb」は、インストール直後にはありません。今回の問題を実行して作ったものです。

PyMongoを使ったプログラミング

PyMongoの使い方は、Tutorial(今回condaで入った3.3.0のもの)(最新はこちら)を見るとだいたいわかります。

今回の問題では、「testdb」というデータベースを作り、そこに「artist」というコレクションを作って、jsonのデータをどんどん登録していきました。

バルクインサート

登録はcollection.insert_one()最新)で1件ずつ繰り返してもいいのですが、今回は100万件近くもあるため、バルクインサートという機能を使いました。

collection.insert_one()は、実行の度にMongoDBのサーバーへ登録依頼を投げるので、大量に繰り返すと登録依頼の度に発生するオーバーヘッドが無視できません。collection.insert_many()最新)なら、リストに詰め込んだ複数件のデータの登録依頼を1回で投げるため、サーバーとの往復が減らせて効率的です。今回はこの機能を使って1万件ずつ登録しました。ただ、それでも100万件近くあると時間がかかるので、1万件ごとに処理経過を表示するようにしています。

バルクインサートについては、TutorialのBulk Inserts最新)に概要説明があります。

インデックスの作成

インデックスはcollection.create_index()最新)で作成でき、検索を高速化できます。TutorialのIndexing最新)に概要説明があります。

 
65本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。


実行結果には、100本ノックで用いるコーパス・データで配布されているデータの一部が含まれます。この第7章で用いているデータのライセンスはクリエイティブ・コモンズ 表示 - 非営利 - 継承 3.0 非移植日本語訳)です。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1