LoginSignup
2
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-01-11

言語処理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等を用いてもよい.

61. KVSの検索

60で構築したデータベースを用い,特定の(指定された)アーティストの活動場所を取得せよ.

出来上がったコード:

main.py
# coding: utf-8
import re
import leveldb

fname_db = 'test_db'

# keyをnameとidに分解するための正規表現
pattern = re.compile(r'''
    ^
    (.*)    # name
    \t      # 区切り
    (\d+)   # id
    $
    ''', re.VERBOSE + re.DOTALL)

# LevelDBオープン
db = leveldb.LevelDB(fname_db)

# 条件入力
clue = input('アーティスト名を入力してください--> ')
hit = False

# アーティスト名+'\t'で検索
for key, value in db.RangeIter(key_from=(clue + '\t').encode()):

    # keyをnameとidに戻す
    match = pattern.match(key.decode())
    name = match.group(1)
    id = match.group(2)

    # 異なるアーティストになったら終了
    if name != clue:
        break

    # 活動場所のチェック、表示
    area = value.decode()
    if area != '':
        print('{}(id:{})の活動場所:{}'.format(name, id, area))
    else:
        print('{}(id:{})の活動場所は登録されていません'.format(name, id))
    hit = True

if not hit:
    print('{}は登録されていません'.format(clue))

実行結果:

実行結果
アーティスト名を入力してください--> Oasis
Oasis(id:20660)の活動場所:United Kingdom
Oasis(id:286198)の活動場所:United States
Oasis(id:377879)の活動場所:United Kingdom

例になっているOasisは3件該当しました。

実行結果
アーティスト名を入力してください--> SMAP
SMAP(id:265728)の活動場所:Japan

このデータベースでは、SMAPはまだ日本で活動中です。

アーティストとして登録されていても、活動場所の情報がない場合があります。

実行結果
アーティスト名を入力してください--> 比嘉真優子
比嘉真優子(id:1075206)の活動場所は登録されていません

比嘉真優子さんは、活動場所が登録されていないアーティストの一覧を眺めていて、たまたま漢字で目立ったので例に使わせていただきました。沖縄出身の方のようです。

なお、アーティストそのものが登録されていない場合は、次のようになります。

実行結果
アーティスト名を入力してください--> segavvy
segavvyは登録されていません

LevelDBの検索

keyで探すだけであれば、LevelDB.Get()でkeyを指定すればvalueが返ってきて終わりなのですが、前問で作ったデータベースは、アーティスト名の重複に対応するため、keyをアーティスト名+'\t'+ユニーク識別子にしています。ユニーク識別子は事前には分からないので、イテレータを取得してチェックする形にしました。

イテレータの取得はLevelDB.RangeIter()で行いますが、普通に全件取得してチェックしていたらKVSを使うメリットがなくなってしまうため、LevelDBのkeyが常にソートされていることを利用しています。
LevelDB.RangeIter()はkey_fromでイテレータの開始条件を指定できるので、探したいアーティスト名+'\t'を指定してそれ以降だけをチェックすれば、ユニーク識別子がなんであっても該当アーティストのvalueが直接取得できます。
なお、key_toで終了条件も指定できるのですが、LevelDBのソートロジックが明確には分からず指定方法がうまく思いつかなかったので、今回は指定していません。その代わりに、アーティスト名が目的のものではなくなったらbreakするようにしました。

表記ゆれ、Unicodeコードポイント

余談ですが、私が好きなフュージョンバンドのT-SQUAREがなぜか登録されていません。

実行結果
アーティスト名を入力してください--> T-SQUARE
T-SQUAREは登録されていません

不思議に思いちょっとデータを覗いたところ、-(ハイフン)がいつもの文字(Unicodeコードポイント:45)ではなく別の文字(同:8208)になっていました。その文字で入力すればヒットします。

実行結果
アーティスト名を入力してください--> T‐SQUARE
T‐SQUARE(id:9707)の活動場所:Japan

こういった表記のゆれは検索漏れの原因になってしまうので、検索の仕組みを作ろうとした場合、なかなか頭の痛いテーマではないかと思います。これまでの問題でも、形態素解析して原型にして扱うとかステミングするとか、いろいろな手法を学んできましたが、他にも大小文字や全半角、異体字や新旧漢字、漢字なのか開く(=ひらがなにする)のか、フルスペルなのか略すのかとか、いろいろありそうです。

ちなみにUnicodeコードポイントは、Pythonではord()で調べられます。

Unicodeコードポイントって何?という方は、ギークを目指してさんの文字コードの考え方から理解するUnicodeとUTF-8の違いの解説が分かりやすいかと思います。

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


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

2
0
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
2
0