はてだBlog(仮称)

私的なブログど真ん中のつもりでしたが、気づけばWebサイト系のアプリケーション開発周りで感じたこと寄りの自分メモなどをつれづれ述べています。2020年6月現在、Elasticsearch、pandas、CMSなどに関する話題が多めです。...ですが、だんだんとより私的なプログラムのスニペット置き場になりつつあります。ブログで述べている内容は所属組織で販売している製品などに関するものではなく、また所属する組織の見解を代表するものではありません。

検索練習用のサンプルデータのインポート@Elasticsearch:住所マスタを使おう

はじめに

Elasticsearchの検索やヒットの仕方をいろいろためしてみたいという時に、そもそものデータをどう用意するかというところは地味ながら悩ましいです。

というのも、bulk APIはあるものの、Elasticsearchは良くも悪くもJSONの世界観ですし、試したり慣れたりしたいのに、そこにいくまでに無視できない量と手間のアナログな作業が発生します。

別にElasticsearchに限りませんが、波に乗るまでのハードルをどう超えるかは初学時のテーマです。

また、サンプルデータとして、ほど良いものをチョイスすることもぼちぼち大事です。

例えば、データがどんな感じで分布しているか分からない、想像つかないようなデータをインポートしても実際の当たり具合が想像つかなく、データ自体への習熟に時間を要してしまいます。

Elastcisearchの公式でサンプルデータを用意してくれていますが、これにケチをつける意味ではないものの、古くはscott/tigerの例と同様に、元のデータの分布や件数がにピンとこない場合、試行と結果の腹落ちに支障をきたします。

RDBならまだマシですが、全文検索の場合はスコアリングが絡むため、やはり元データについて予備知識がないものは避けたいところです。

前置きが長くなりましたが、テストデータとしてほど良いもの(と私が考える例として)、住所マスタ的なものに思い当たりましたので、そいつをサクッとインポートする手順を以下にまとめてみました。

住所マスタであれば、47都道府県ぐらいは(私個人は一部あやふやなところがあるものの)ソラでタイプできますし、最上位をaggsすれば47種類になることも想像つきます。

自分の身近な地名であれば、配下にどのような地域があるかもイメージしやすいですし、形態素解析分かち書きで、都合よく行く場合とそうでない場合などの感覚も掴みやすいと考えます。

仮想環境のイメージファイルもを配る余裕もスキルもないので、コマンド打ちコピペで対応ですが、その分手軽です。

特別なことはしていないですが、特別でないからこそ、ひとまずElasticsearchはポチポチインストールした、そのあと標準で入っているコマンドなどで対応できるようなものとしました。

考え方

  1. 住所マスタのCSVを入手します。
  2. ワンライナーの範囲で、バルクロード用のJSONに変換します。簡単のため 「a」というフィールドの1項目だけ(この項目中に元CSVの9項目がスペース区切りで入っている)のドュメントとします。
  3. バルクロードしますが、この際、ingest nodeでpipeline方式をかまします。pipelineのprocessorでは、空白区切りの文字列を9つのフィールドにバラしてドキュメント登録するような「grok」編集を使います。

Elasticsearchはインストール済みで、ここではanalyzerにkuromojiを登録できていることとします。

手順

事前準備(ファイルのダウンロード)

住所マスタといえば、日本郵政が郵便番号マスタとしてフリーで配布しているものがあるので、これを使います。

www.post.japanpost.jp

全国一括

でダウンロードできます。

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ということで、次の記事を発見しました。

たまたま本サイトに、住所関連の検索ノウハウをもとめて迷い込んだ方は、こちらのサイトさんの方がより適切と思われますので、リンクをご紹介させていただきます。

komaken.me

以上、おわりです。