はじめに
Elasticsearchの検索やヒットの仕方をいろいろためしてみたいという時に、そもそものデータをどう用意するかというところは地味ながら悩ましいです。
というのも、bulk APIはあるものの、Elasticsearchは良くも悪くもJSONの世界観ですし、試したり慣れたりしたいのに、そこにいくまでに無視できない量と手間のアナログな作業が発生します。
別にElasticsearchに限りませんが、波に乗るまでのハードルをどう超えるかは初学時のテーマです。
また、サンプルデータとして、ほど良いものをチョイスすることもぼちぼち大事です。
例えば、データがどんな感じで分布しているか分からない、想像つかないようなデータをインポートしても実際の当たり具合が想像つかなく、データ自体への習熟に時間を要してしまいます。
Elastcisearchの公式でサンプルデータを用意してくれていますが、これにケチをつける意味ではないものの、古くはscott/tigerの例と同様に、元のデータの分布や件数がにピンとこない場合、試行と結果の腹落ちに支障をきたします。
RDBならまだマシですが、全文検索の場合はスコアリングが絡むため、やはり元データについて予備知識がないものは避けたいところです。
前置きが長くなりましたが、テストデータとしてほど良いもの(と私が考える例として)、住所マスタ的なものに思い当たりましたので、そいつをサクッとインポートする手順を以下にまとめてみました。
住所マスタであれば、47都道府県ぐらいは(私個人は一部あやふやなところがあるものの)ソラでタイプできますし、最上位をaggsすれば47種類になることも想像つきます。
自分の身近な地名であれば、配下にどのような地域があるかもイメージしやすいですし、形態素解析の分かち書きで、都合よく行く場合とそうでない場合などの感覚も掴みやすいと考えます。
仮想環境のイメージファイルもを配る余裕もスキルもないので、コマンド打ちコピペで対応ですが、その分手軽です。
特別なことはしていないですが、特別でないからこそ、ひとまずElasticsearchはポチポチインストールした、そのあと標準で入っているコマンドなどで対応できるようなものとしました。
考え方
- 住所マスタのCSVを入手します。
- ワンライナーの範囲で、バルクロード用のJSONに変換します。簡単のため 「a」というフィールドの1項目だけ(この項目中に元CSVの9項目がスペース区切りで入っている)のドュメントとします。
- バルクロードしますが、この際、ingest nodeでpipeline方式をかまします。pipelineのprocessorでは、空白区切りの文字列を9つのフィールドにバラしてドキュメント登録するような「grok」編集を使います。
Elasticsearchはインストール済みで、ここではanalyzerにkuromojiを登録できていることとします。
手順
事前準備(ファイルのダウンロード)
住所マスタといえば、日本郵政が郵便番号マスタとしてフリーで配布しているものがあるので、これを使います。
の
でダウンロードできます。
1) zipを展開します。するとKEN_ALL.CSVというファイルが出力されます。
2) 続いて、バルクロード用のJSONファイルに変換します。
export META='{ "index" : {"pipeline": "pcode-pl" } }'; cat KEN_ALL.CSV | nkf | ruby -ne 'puts $_.gsub(/[" ]/,"").split(",")[0..8].join(" ")' | ruby -nle 'puts ENV["META"] + "\n{\"a\":\"" + $_ + "\"}"'> ken_all.json
※手元の環境はmacなのでなんとなくインストールされているnkfを使っています。
3) Elasticsearch側のmappingとpipelineの設定をします。
ここでは、kibanaのDev Toolsに貼り付けるイメージで示しています。
コマンドラインからだとcurlなどのオプションに注意ください。
PUT _ingest/pipeline/pcode-pl { "description" : "pcode", "processors": [ { "grok": { "field": "a", "patterns": ["%{NOTSPACE:1_ps} %{NOTSPACE:2_ps} %{NOTSPACE:3_ps} %{NOTSPACE:4_ps} %{NOTSPACE:5_ps} %{NOTSPACE:6_ps} %{NOTSPACE:7_ps} %{NOTSPACE:8_ps} %{NOTSPACE:9_ps}"] } } ] } PUT your_index3 { "mappings": { "your_type3": { "dynamic_templates": [ { "_ps_as_kuromoji": { "match_mapping_type": "*", "match": "*_ps", "mapping": { "type": "text", "analyzer":"kuromoji", "fielddata":true } } } ] } } }
4) コマンドラインに移ってバルクロードします。
curl -H "Content-type: application/x-ndjson" -X POST localhost:9200/your_index3/your_type3/_bulk?refresh --data-binary @ken_all.json
ここまででサンプルデータの取り込みは完了です。
5) kibanaのDev Toolsで検索してみます。
POST /your_index3/_search { "query": {"match_all": { }} } ↓リザルト { "took": 2, "timed_out": false, "_shards": { "total": 5, "successful": 5, "skipped": 0, "failed": 0 }, "hits": { "total": 124243, "max_score": 1, "hits": [ { "_index": "your_index3", "_type": "your_type3", "_id": "jh43iWcBA4FDKIYMBOCw", "_score": 1, "_source": { "a": "01101 064 0640941 ホツカイドウ サツポロシチユウオウク アサヒガオカ 北海道 札幌市中央区 旭ケ丘", "1_ps": "01101", "2_ps": "064", "8_ps": "札幌市中央区", "7_ps": "北海道", "9_ps": "旭ケ丘", "5_ps": "サツポロシチユウオウク", "6_ps": "アサヒガオカ", "3_ps": "0640941", "4_ps": "ホツカイドウ" } }, { "_index": "your_index3", "_type": "your_type3", "_id": "kR43iWcBA4FDKIYMBOCw", "_score": 1, "_source": { "a": "01101 064 0640820 ホツカイドウ サツポロシチユウオウク オオドオリニシ(20-28チヨウメ) 北海道 札幌市中央区 大通西(20〜28丁目)", "1_ps": "01101", "2_ps": "064", "8_ps": "札幌市中央区", "7_ps": "北海道", "9_ps": "大通西(20〜28丁目)", "5_ps": "サツポロシチユウオウク", "6_ps": "オオドオリニシ(20-28チヨウメ)", "3_ps": "0640820", "4_ps": "ホツカイドウ" } },
ヒットしてそうです。
おわりに
よくあるCSVの情報源であれば、上記をコピペしてしかもほとんど改変せずにデータを登録できると思います。
参考リンク
住所関連でElasticsearchということで、次の記事を発見しました。
たまたま本サイトに、住所関連の検索ノウハウをもとめて迷い込んだ方は、こちらのサイトさんの方がより適切と思われますので、リンクをご紹介させていただきます。
以上、おわりです。