言語処理100本ノック 2015年版 (60~63)
第7章: データベース
artist.json.gzは,オープンな音楽データベースMusicBrainzの中で,アーティストに関するものをJSON形式に変換し,gzip形式で圧縮したファイルである.このファイルには,1アーティストに関する情報が1行にJSON形式で格納されている.JSON形式の概要は以下の通りである.
(略)
artist.json.gzのデータをKey-Value-Store (KVS) およびドキュメント志向型データベースに格納・検索することを考える.KVSとしては,LevelDB,Redis,KyotoCabinet等を用いよ.ドキュメント志向型データベースとして,MongoDBを採用したが,CouchDBやRethinkDB等を用いてもよい.
まずはKVS側の60~63を掲載します。
60. KVSの構築
Key-Value-Store (KVS) を用い,アーティスト名(name)から活動場所(area)を検索するためのデータベースを構築せよ
KyotoCabinet は別件で見たことがあるので、何も知らない LevelDB か Redis にしたいと思います。今回は LevelDB を採用しました。
しかしこの設問、60ができているかどうかテストするためには何度も61の作業を行うわけで、設問を分けている意味が分かりません。
#!/usr/bin/env python import codecs import json import plyvel fin = codecs.open('artist.json', 'r', 'utf_8') if __name__ == "__main__": db = plyvel.DB('artist.ldb',create_if_missing=True) for line in fin: jsonData = json.loads(line) if "name" in jsonData and "area" in jsonData: db.put(jsonData["name"].encode(), jsonData["area"].encode()) db.close()
61. KVSの検索
60で構築したデータベースを用い,特定の(指定された)アーティストの活動場所を取得せよ.
60の構築中に終わっています。
#!/usr/bin/env python import plyvel import sys if __name__ == "__main__": param = sys.argv db = plyvel.DB('artist.ldb',create_if_missing=True) if len(param)>1: name = param[1].encode() else: name = b"Oasis" area = db.get(name) print(name,area) db.close()
62. KVS内の反復処理
60で構築したデータベースを用い,活動場所が「Japan」となっているアーティスト数を求めよ.
#!/usr/bin/env python import plyvel if __name__ == "__main__": db = plyvel.DB('artist.ldb',create_if_missing=True) n = 0 for name,area in db: if area == b"Japan": print(name.decode(),area) n += 1 print(n) db.close()
タイトルの「KVS内の反復処理」という表現が気になりますが、ただの for文で終わらせてしまいました。
結果
龍山一平 b'Japan'
龍門渕透華 b'Japan'
류영기 b'Japan'
2番をつくらなくっちゃネ!実行委員会 b'Japan'
9人の麦わら海賊団 b'Japan'
ALiBi b'Japan'
GREGORY b'Japan'
MANNEQUIN b'Japan'
NHKみんなのうた b'Japan'
SHIOMI b'Japan'
22128
アーティスト名に「9人の麦わら海賊団」とかが入っていて笑ってしまいました。
63. オブジェクトを値に格納したKVS
KVSを用い,アーティスト名(name)からタグと被タグ数(タグ付けされた回数)のリストを検索するためのデータベースを構築せよ.さらに,ここで構築したデータベースを用い,アーティスト名からタグと被タグ数を検索せよ.
valueはバイト列でないといけないので、リストそのままでは放り込めません。
バイト列にする方法はいくつかありますが、json をインポートしているのでそのまま使ってしまいましょう。
プログラムを格納用の63-1.py, 検索用の63-2.pyに分割します。
問題は検索側で、jsonで文字列として格納しているためそのままではリストや辞書として扱えません。今回は astモジュールを使用しました。
63-1.py
#!/usr/bin/env python import codecs import json import plyvel fin = codecs.open('artist.json', 'r', 'utf_8') if __name__ == "__main__": db = plyvel.DB('artisttag.ldb',create_if_missing=True) for line in fin: jsonData = json.loads(line) if "tags" in jsonData: print(jsonData["name"],jsonData["tags"]) tags = json.dumps(jsonData["tags"]) db.put(jsonData["name"].encode(), tags.encode()) db.close()
63-2.py
#!/usr/bin/env python import plyvel from ast import literal_eval import sys if __name__ == "__main__": param = sys.argv if len(param)>1: name = param[1].encode() else: name = b"Oasis" db = plyvel.DB('artisttag.ldb',create_if_missing=True) tags = literal_eval(db.get(name).decode()) for tag in tags: print("tag:",tag["value"],"\tcount:",tag["count"]) db.close()
結果(Oasisで検索)
tag: rock count: 1 tag: britpop count: 3 tag: british count: 4 tag: uk count: 1 tag: britannique count: 1 tag: rock and indie count: 1 tag: england count: 1 tag: manchester count: 1