アイソモカ

知の遊牧民の開発記録

開発記録 200210 Mon (100本ノック #060, LevelDB)

今回から 第7章: データベース です。今回は JSON 形式のデータを読んで、Key-Value-Store (KVS) データベースを作りました。LevelDB を初めて使いました。

言語処理100本ノック #060

第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等を用いてもよい.

 

60. KVSの構築

Key-Value-Store (KVS) を用い,アーティスト名(name)から活動場所(area)を検索するためのデータベースを構築せよ.

LevelDB の準備

参考 👉 PythonでLevelDBを使ってみる(plyvel) - Qiiita

LevelDB と plyvel、msgpack-python をインストール

$ brew install leveldb
$ pip install plyvel
$ pip install msgpack-python

 

練習用に書いてみたコード

# study_plyvel.py
import plyvel
my_db = plyvel.DB('test.lbd', create_if_missing=True)
import pickle
import msgpack


def study_pickle():
    for key, value in my_db:
        my_db.delete(key)

    print('[using pickle]')
    for i in range(8):    
        serialized1 = pickle.dumps(list(j for j in range(i)))
        my_db.put(('key'+str(i)).encode('utf-8'), serialized1)

    for key, value in my_db:
        print(key, '=>', pickle.loads(value))


def study_msgpack():
    for key, value in my_db:
        my_db.delete(key)

    print('\n[using msgpack]')
    for i in range(8):
        serialized2 = msgpack.packb(list(j for j in reversed(range(i))))
        my_db.put(('key'+str(i)).encode('utf-8'), serialized2)

    for key, value in my_db:
        print(key, '=>', msgpack.unpackb(value))


if __name__ == '__main__':
    study_pickle()
    study_msgpack()
    my_db.close()

解答

json を使うのは 100本ノック #020 でやったはずだったけど忘れてしまったので、 以前に書いたコードを見たらなんとなく使えた(思い出したとは言っていない)。 100本ノックは始めてから休み休みやっているので、もう2年も前なんやな。以前に比べて頻度が上がっているから良しとするか……。

# knock_060.py
import gzip
import json
DATAFILE = './artist.json.gz'
import plyvel
name_area_db = plyvel.DB('artist_name_area.lbd', create_if_missing=True)

def read_json(file):
    with gzip.open(file, 'rt') as datafile:
        for l in datafile:
            data_json = json.loads(l)
            if 'area' in data_json:
                yield (data_json['name'], data_json.get('area'))


def make_name_area_db(file):
    for key, value in name_area_db:
        name_area_db.delete(key)

    for artist in list(read_json(file)):
        name_area_db.put(artist[0].encode('utf-8'), artist[1].encode('utf-8'))


if __name__ == '__main__':
    make_name_area_db(DATAFILE)
    print(name_area_db.get('Avicii'.encode('utf-8')).decode('utf-8'))

 ↓ 出力

$ python knock_060.py 
Sweden