言語処理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等を用いてもよい.
###68. ソート
"dance"というタグを付与されたアーティストの中でレーティングの投票数が多いアーティスト・トップ10を求めよ.
####出来上がったコード:
# coding: utf-8
import json
import pymongo
from pymongo import MongoClient
# MongoDBのデータベースtestdbにコレクションartistにアクセス
client = MongoClient()
db = client.testdb
collection = db.artist
# 検索
results = collection.find({'tags.value': 'dance'})
# ソート
results.sort('rating.count', pymongo.DESCENDING)
# 10件表示
for doc in results.limit(10):
if 'rating' in doc:
rating = doc['rating']['count']
else:
rating = '(none)' # ratingがないドキュメントもあるので
print('{}(id:{})\t{}'.format(doc['name'], doc['id'], rating))
####実行結果:
Madonna(id:89) 26
Björk(id:1022) 23
The Prodigy(id:44954) 23
Rihanna(id:262731) 15
Britney Spears(id:791) 13
Maroon 5(id:66179) 11
Adam Lambert(id:627661) 7
Fatboy Slim(id:255) 7
Basement Jaxx(id:1060) 6
Cornershop(id:798) 5
###ソート
ソートは検索結果のCursorオブジェクトに対してsort()(最新)で実行します。そこから列挙すればソートされた結果が取得できる流れです。
###ソート対象のフィールドが存在しなかったり型が違ったりする場合の扱い
ソート対象のフィールドが存在しないドキュメントがある場合や、ドキュメント間でそのフィールドの型が異なる場合のルールは、Comparison/Sort Orderで解説されています。
今回の問題ではrating.countが存在しないドキュメントがヒットしますが、その場合、Non-existent Fieldsの説明によるとnullと同じ扱いになり、nullはどの型よりも小さな値として扱われるようです。今回の問題は大きい順でソートしますので、rating.countが存在しないドキュメントは末尾に寄せられています。もし先頭に寄せられる仕様だった場合は、何か工夫しないといけないところでした。
###最初の10件を取り出す
検索結果のCursorオブジェクトに対してlimit()(最新)で取り出せます。(@takatsugukatoさん、アドバイスありがとうございます。)
69本目のノックは以上です。誤りなどありましたら、ご指摘いただけますと幸いです。
実行結果には、100本ノックで用いるコーパス・データで配布されているデータの一部が含まれます。この第7章で用いているデータのライセンスはクリエイティブ・コモンズ 表示 - 非営利 - 継承 3.0 非移植(日本語訳)です。