@johtaniの日記 2nd

@johtani ‘s blog 2nd edition

ElasticSearchにプラグインで日本語Wikipediaデータを入れてみました

久々のブログはElasticSearchネタです。勉強会開催する予定だったりすので、もう少し触っておきたいなと。 お手軽に検索するデータとして、よくWikipediaのデータを使っています。 ElasticSearchにはelasticsearch-river-wikipediaという便利なプラグインがあり、Wikipediaのデータを簡単に検索可能な状態にできます。このRiverを利用して日本語のWikipediaのデータを入れたので、メモを取っておきます。 まずは、river-wikipediaで日本語のデータをインデクシングしてみるまでの説明です。 日本語特有の設定(Kuromojiを利用したインデクシング)などはまた後日。

プラグインのインストール

対象とするElasticSearchは現時点で最新版の0.90.3とします。 最新版でRiver動かないなぁとつぶやいた影響かどうかはわかりませんが、2013/08/19に最新版のElasticSearchで動作するプラグインが公開されました。

まずはインストールです。 HPにも書いてありますが、以下のコマンドを実行すればインストールされます。

1
2
3
4
5
$ ./bin/plugin -install elasticsearch/elasticsearch-river-wikipedia/1.2.0
-> Installing elasticsearch/elasticsearch-river-wikipedia/1.2.0...
Trying http://download.elasticsearch.org/elasticsearch/elasticsearch-river-wikipedia/elasticsearch-river-wikipedia-1.2.0.zip...
Downloading ..........DONE
Installed river-wikipedia into /opt/elasticsearch/plugins/river-wikipedia

ElasticSearchが起動している場合はプラグインをインストール後、認識させるためにElasticSearchを再起動します。

日本語Wikipediaのインデクシング

通常は英語のWikipediaがインデクシングされますが、対象となるファイルを変更することで日本語のWikipediaもインデクシング可能です。 手元に日本語Wikipediaのダンプファイルがあるものとします。(ダウンロードはWikipediaデータベースダウンロードのページにあるpages-articles.xml.bz2のファイルです)

ファイルを指定してインデクシングするには、つぎのcurlコマンドを実行します。 コマンドを実行するとすぐにインデクシングが始まりますので注意が必要です。

1
2
3
4
5
6
7
8
9
10
curl -XPUT localhost:9200/_river/ja-wikipedia/_meta -d '
{
    "type" : "wikipedia",
    "wikipedia" : {
        "url" : "file:/home/johtani/src/jawiki-latest-pages-articles.xml"
    },
    "index" : {
        "bulk_size" : 1000
    }
}'

ここでURLに含まれる「ja-wikipedia」がインデックス名になります。 また、JSONの”url”にはファイルの場所を指定するため、file:で開始するパスを指定します。 例では、bz2を解凍したファイルを指定していますが、bz2のままのファイルでもOKです。

上記コマンドを実行すると、_riverというインデックスにつぎのようなエントリが増えています。 (curl -XGET 'localhost:9200/_river/ja-wikipedia/_search?pretty)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
{
   "took": 5,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 2,
      "max_score": 1,
      "hits": [
         {
            "_index": "_river",
            "_type": "ja-wikipedia",
            "_id": "_status",
            "_score": 1,
            "_source": {
               "ok": true,
               "node": {
                  "id": "gdyvwpiAR52lqUCcRhVwsg",
                  "name": "Blitzschlag, Baron Von",
                  "transport_address": "inet[/192.168.100.7:9300]"
               }
            }
         },
         {
            "_index": "_river",
            "_type": "ja-wikipedia",
            "_id": "_meta",
            "_score": 1,
            "_source": {
               "type": "wikipedia",
               "wikipedia": {
                  "url": "file:/home/johtani/src/jawiki-latest-pages-articles.xml"
               },
               "index": {
                  "bulk_size": 100
               }
            }
         }
      ]
   }
}

"_id": "_meta"というエントリがさきほど登録したWikipediaのRiverに関する設定です。 "_id": "_status"というエントリが起動したRiverの状態になります。

Riverの停止

日本語Wikipediaは結構サイズが大きく、手元のAirでインデクシングするのに30分程度かかりました。(bz2圧縮されていないファイルで、何もしていない状態)

途中でRiverを停止したくなった場合は、以下のcurlコマンドを実行します。

1
$ curl -XDELETE 'localhost:9200/_river/ja-wikipedia'

先ほど設定した_river/ja-wikipediaの情報を削除すると、エントリが削除されたのを検知してRiverが停止します。ログにはつぎのようなメッセージが表示されます。

1
2
[2013-08-26 18:26:50,130][INFO ][cluster.metadata         ] [Blitzschlag, Baron Von] [[_river]] remove_mapping [ja-wikipedia]
[2013-08-26 18:26:50,130][INFO ][river.wikipedia          ] [Blitzschlag, Baron Von] [wikipedia][ja-wikipedia] closing wikipedia river

Riverを停止してもそれまでインデクシングされたデータは検索できます。 データはちょっとだけで良いという場合は、先ほどの_riverのデータを削除してください。 (◯件だけ登録したいとかできるかは調べてないです。)

サイズとかマッピングとか

サイズ

インデックス前のXMLのサイズが5.7Gのとき、ElasticSearchのインデックスサイズ(Optimize後)は7.2Gとなりました。すこし古いファイルを利用しているため、最新版とはサイズが異なるかもしれません。

あと、データ数が、1540000件とやけにきりがいいのがちょっと気になっています。。。 bulkのサイズを10000で指定してインデックスしたので、切れてるのかなぁと。

ということは、データが欠落しているような気がするのでRiverの作りの問題なのか、ElasticSearchの問題なのかはちょっと調べてみないとわからないなと。

マッピング

出来上がったインデックスのマッピング(Solrでいうスキーマみたいなもの)は次のようになっています。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
{
   "ja-wikipedia": {
      "page": {
         "properties": {
            "category": {
               "type": "string"
            },
            "disambiguation": {
               "type": "boolean"
            },
            "link": {
               "type": "string"
            },
            "redirect": {
               "type": "boolean"
            },
            "special": {
               "type": "boolean"
            },
            "stub": {
               "type": "boolean"
            },
            "text": {
               "type": "string"
            },
            "title": {
               "type": "string"
            }
         }
      }
   }
}

Wikipediaの各種データが上記のフィールドに入っています。 また、マッピングタイプはデフォルトで「page」というタイプになっています。

検索

先ほどのマッピングを元に検索すればOKです。例えばつぎのような感じです。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
curl -XPOST 'localhost:9200/ja-wikipedia/_search?pretty' -d '
{
    "size" : 3,
    "script_fields": {
       "title_only": {
          "script": "_source.title"
       }
    },
    "query" : {
        "query_string": {
            "default_field": "title",
            "query" : "千葉"
        }
    }
}'

結果はこんな感じ。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
{
   "took": 51,
   "timed_out": false,
   "_shards": {
      "total": 5,
      "successful": 5,
      "failed": 0
   },
   "hits": {
      "total": 8616,
      "max_score": 5.8075247,
      "hits": [
         {
            "_index": "ja-wikipedia",
            "_type": "page",
            "_id": "3582",
            "_score": 5.8075247,
            "fields": {
               "title_only": "千葉"
            }
         },
         {
            "_index": "ja-wikipedia",
            "_type": "page",
            "_id": "2352241",
            "_score": 4.94406,
            "fields": {
               "title_only": "千葉千枝子"
            }
         },
         {
            "_index": "ja-wikipedia",
            "_type": "page",
            "_id": "14020",
            "_score": 4.8754807,
            "fields": {
               "title_only": "千葉千恵巳"
            }
         }
      ]
   }
}

結果を見やすくするため、タイトルだけを「title_only」という表示にしています。 ただ、この検索だと、一見「千葉」できちんとヒットしているように見えますが、ElasticSearchのフィールドの定義はstring型になっています。なので、実は「千」や「葉」だけのデータもヒットしています。 マルチバイト文字は1文字ずつインデックスされてしまい、query_stringというクエリでは、フレーズ検索などができていないためです。

まとめ

プラグインいれて、XMLファイルがあれば、検索できるデータが出来上がるので、 暇があったら、お試しで触ってみるデータを簡単に入れてみてはどうでしょうか。

ただ、いくつか気になる点も。

  • 日本語が検索しにくい(string型のフィールドなのでuni-gramっぽくなっている)
  • bulk_sizeの影響で端数が登録できてない(バグ?どうなの?)

ということで、ちょっと使いにくいかもなぁということで、つぎはKuromojiを利用してインデックスしてみてみようかなと。次回のエントリで書く予定です。

Comments