[Elasticsearch] aggregationに任意の値を含める

郵便局が公開してくれているKEN_ALL.csvをElasticsearchに入れて
住所入力の補完とかに使ってたときのメモ。

前提として

  1. インデックス名はsample
  2. ドキュメント名はaddress
  3. 型はtextとkeywordの両方を定義

したとします。

郵便局 郵便番号データダウンロード

上記のデータを下記のようにマッピングして、Elasticsearchに突っ込みました。
(analyzerとかは一旦置いときます)

  • zip_code 郵便番号
  • address1 都道府県
  • address2 市区町村
  • address3 丁目以下
  • address1_kana 都道府県カナ
  • address2_kana 市区町村カナ
  • address3_kana 丁目以下カナ

やりたいことから順番にクエリ書いてみます。

1. 郵便番号を入力したら、住所出てきてほしい

よくユーザ登録のフォームにあるやつですね。
これはシンプル

POST /sample/address/_search

これで郵便番号1000000の住所が出てきます。
(IDを郵便番号にしたらもっと簡単じゃない?って一瞬思ったけど、問題あるっぽい)

参考 郵便番号や市区町村データを取り扱うときにはまったこと

2. 郵便番号100で始まる住所全部ほしい

これもまだシンプル

POST /sample/address/_search

今ぼくの手元では50件強の結果がきてるので、sizeの指定が必要。
指定しないとぼくの環境では10件しか来ないです。

3. 都道府県の一覧が欲しい

ここからが本題

都道府県が簡単に増えたり減ったりすることは、まぁ考えられませんが
住所以外でも汎用的に使えそうなので。

何も考えず、前述の応用でいくなら下記

POST /sample/address/_search

これで全件取得して、プログラムでaddress1の重複を排除すれば、一応都道府県の一覧ができる、はず。

ですが問題だらけ。

  • データの件数が凄まじいことになる(今手元の環境でも全件で12万件超)
  • つまり通信量がすごい
  • そこからプログラムで重複排除するための必要になるメモリの量もすごい

Elasticsearchのデフォルトの最大取得件数は10,000件で、変えられるけど
増減を考えるとアホみたいにでかい数字を設定するのは現実的じゃないです。

fromとsizeを組み合わせることでページングのようにすれば
可能かと思いきや、検索条件がなければID順に出てくるので、後から追加した
都道府県が2度出てきてしまったりする。

そこでaggregationという仕組みを使う

これでaddress1が等しいものの数を出してくれます。
これで都道府県の一覧が取得できました。(下記は一部抜粋)

4. 市区町村の一覧が欲しい

これは前述の応用で簡単にできます。

address1が東京都のものを抽出し、その結果に対してaddress2でaggregationしています。

結果が100件以上ある場合はfrom,sizeを組み合わせてページングすれば問題ありません

5. カナも一緒に結果に返してほしい

書きたかったのはここ。
住所に難しい漢字が使われてたりして、読み方はわかるけど、漢字がわからない、
みたいなケースに対応するために、都道府県や市区町村の一覧にカナも一緒につけたくなりました。

先程に挙げた通り、aggregationには利用したキーと、結果しか返ってきません。

そこで、aggregationのscriptという仕組みを使います。
多分もっと色々できそうな気がするけど、簡単にいうと、結果に対してスクリプトの処理を噛ませる
ことができる。

※書いてる過程で知ったんですが、ここはElasticsearch5.xと6.xで書き方が違うみたいです。
ここでは5.xの書き方をあげてます。

6.xの書き方はTerms Aggregationを参照してください。

こうすると、結果(一部抜粋)が

こんな感じになりました。あとはこれを取得後にカンマでsplitすれば、カナ付きの
都道府県一覧が取得できました。

おわり!

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です