言語処理100本ノック 2015の63本目「オブジェクトを値に格納したKVS」の記録です。RedisとPythonを使っています。
63本目はKVSのNoSQLデータベースに対して値の格納と検索をする処理です。
「言語処理100本ノック」記録
- 言語処理100本ノック-60(RedisとPython使用):KVSの構築
- 言語処理100本ノック-61(RedisとPython使用):KVSの検索
- 言語処理100本ノック-62(RedisとPython使用):KVS内の反復処理
- 言語処理100本ノック-63(RedisとPython使用):オブジェクトを値に格納したKVS
参考リンク
リンク | 備考 |
---|---|
書籍「RDB技術者のためのNoSQLガイド」 | RDBに浸かっていた私には非常にわかりやすかったです |
063_1.オブジェクトを値に格納したKVS.ipynb 063_2.オブジェクトを値に格納したKVS.ipynb |
回答プログラムのGitHubリンク 格納と検索で2つに分けています |
最新RedisのUbuntuへのインストールとPythonで使うまで | インストールについて |
【初心者向け】Redisのデータ型とPythonでの使い方サンプル | Redisのデータ型について整理 |
言語処理100本ノックでPython入門 #63 - KVSにオブジェクトを格納 | Redis-pyの回答として参考にしました |
素人の言語処理100本ノック:63 | 言語処理100本ノックで常にお世話になっています |
環境
インストールに関しては記事「最新RedisのUbuntuへのインストールとPythonで使うまで」を参照ください。
種類 | バージョン | 内容 |
---|---|---|
OS | Ubuntu18.04.01 LTS | 仮想で動かしています |
Redis | 5.0.4 | 2019/3/22時点でStableの最新です |
pyenv | 1.2.9 | 複数Python環境を使うことがあるのでpyenv使っています |
Python | 3.7.2 | pyenv上でpython3.7.2を使っています パッケージはvenvを使って管理しています |
reids-py | 3.2.1 | 2019/3/22時点で最新 |
問題
第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等を用いてもよい.
【注意事項】このデータは「アーティスト名」で一意になりません。なので、単純に「アーティスト名」をKVSのキーにすると2件目以降で上書きしてしまうためファイルの件数とKVSの件数が合致しません。
63. オブジェクトを値に格納したKVS
KVSを用い,アーティスト名(name)からタグと被タグ数(タグ付けされた回数)のリストを検索するためのデータベースを構築せよ.さらに,ここで構築したデータベースを用い,アーティスト名からタグと被タグ数を検索せよ.
プログラム
格納プログラム:063_1.オブジェクトを値に格納したKVS.ipynb
Jupyter Notebookの形式をPython形式に変換すると以下のコードです。
Jupyter Notebook形式の結果は、「063_1.オブジェクトを値に格納したKVS.ipynb」を見てください。
#!/usr/bin/env python
# coding: utf-8
from redis import Redis
import json
r = Redis( )
FNAME = './artist.json'
# ファイル読み込み、パース
with open(FNAME, encoding='utf8') as data_file:
# for line in data_file:
for i, line in enumerate(data_file):
data_json = json.loads(line)
# tagがない場合もあり
if 'tags' in data_json:
tags = json.dumps(data_json['tags'])
else:
tags = ''
# アーティスト名では一意でないためHashesデータ型として追加
r.hset(data_json['name'], data_json['id'], tags)
r.save()
# 確認のため登録件数を表示
print('{:,}件登録しました。'.format(r.dbsize()))
格納プログラム解説
1件のアーティストに対して複数タグがあるので、タグ部分はJSONでそのまま入れてしまっています。「アーティスト名」で一意にならないのでこんな形式に・・・
どうせ、タグで検索しないのでと思い、これ以上の思考・調査をサボりました。
もっといい方法がありそうな気もします。
検索プログラム:063_2.オブジェクトを値に格納したKVS.ipynb
Jupyter Notebookの形式をPython形式に変換すると以下のコードです。
Jupyter Notebook形式の結果は、「063_2.オブジェクトを値に格納したKVS.ipynb」を見てください。
#!/usr/bin/env python
# coding: utf-8
from redis import Redis
import json
r = Redis( )
def get_tags(name):
for values in r.hvals(name):
if values != b'':
for tag in json.loads(values.decode()):
print(tag)
else:
print('No tags')
get_tags("松任谷由実")
# => {'count': 1, 'value': 'fixme label mess'}
# => {'count': 1, 'value': 'likedis auto'}
get_tags("George Winston")
# => {'count': 1, 'value': 'new age'}
# => {'count': 1, 'value': 'folk'}
get_tags("The Woods Band")
# => No tags
検索プログラム解説
パラメータを使って「アーティスト名」を聞くなど親切な機能をつけていません。
適当に3つの「アーティスト名」で検索しています。
タグ部分はJSON形式となっているのでjson.loadsでパースしています。
最初の「松任谷由実」と2番目の「George Winston」で検索したときには、それぞれ2つのタグを表示しています。
3番目の「The Woods Band」の場合は、タグがありません。