ElasticSearchで日本語の文章を検索できるようにする


やること

dockerでコンテナを立て、ElasticSearchに日本語を含むデータを投入し日本語で検索できるようにします。

Dockerコンテナを立てる

Elasticsearch公式に沿って進めます。

docker imageをDocker Hubからインストールします。

docker pull docker.elastic.co/elasticsearch/elasticsearch:7.10.1

docker-compose.ymlを書きます。
公式では3つのクラスターを立てていますが、今回は一つのクラスタのみにします。

docker-compose.yml
version: '2.2'
services:
  es01:
    image: docker.elastic.co/elasticsearch/elasticsearch:7.10.1
    container_name: es01
    environment:
      - node.name=es01
      - cluster.name=es-docker-cluster
      - cluster.initial_master_nodes=es01
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - data01:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - elastic

volumes:
  data01:
    driver: local

networks:
  elastic:
    driver: bridge

docker-compose.ymlがあるディレクトリで以下を実行し、コンテナを起動します。

docker-compose up

日本語解析プラグインをインストールする

公式の日本語解析プラグイン(kuromoji)をインストールします。
コンテナにログインします。

docker exec -it 立ち上げたコンテナID /bin/bash 

(↓docker上)

sudo bin/elasticsearch-plugin install analysis-kuromoji

インストール後、dockerコンテナからは出て、dockerを再起動します。

docker restart 立ち上げたコンテナID

ローカルに戻って、以下を実行します。

curl http://localhost:9200/_nodes/plugins?pretty

analysis-kuromoji があればOKです。

(略)
 "plugins" : [
        {
          "name" : "analysis-kuromoji",
          "version" : "7.6.2",
          "elasticsearch_version" : "7.6.2",
          "java_version" : "1.8",
          "description" : "The Japanese (kuromoji) Analysis plugin integrates Lucene kuromoji analysis module into elasticsearch.",
          "classname" : "org.elasticsearch.plugin.analysis.kuromoji.AnalysisKuromojiPlugin",
          "extended_plugins" : [ ],
          "has_native_controller" : false
        }
(略)

indexを作成する

今回Elasticsearch7で動かしているのでtypeはありません。
美術館・博物館を検索できるようなindexとします。

curl -X PUT http://localhost:9200/museum?pretty

↑の実行後以下で作成したindex名が表示されればOKです。

curl -X GET http://localhost:9200/_cat/indices?v

indexにデータを投入する

サンプルとして、以下のデータを投入します。
jsonファイルを作成します。

sample.json
{"pref_id": "13", "city_id": "13101", "name": "国立美術館東京国立近代美術館","location": [139.7547383, 35.6905368]}
{"pref_id": "13", "city_id": "13106", "name": "上野の森美術館", "location": [139.7747384, 35.7127347]}

museumは作成したindex名、作成したデータはsample.jsonとなります。

curl -H "Content-Type: application/json" -XPOST http://localhost:9200/museum/_bulk --data-binary @sample.json

以下で登録したデータが取得できればOKです。

curl -XGET http://localhost:9200/facility/_search?pretty

クエリの作成

Elasticsearchの文書の検索機能には何種類かあります(部分一致,完全一致など)が、ありますが
今回はmatch_phraseを使います。
match_phraseは指定した句を含むデータを返すことができます。

sample_query.json
{
  "query": {"match_phrase": { "name": "国立" } } 
}

検索

作成したjsonを指定して検索します。

curl -H "Content-Type: application/json" -X GET http://localhost:9200/facility/_search --data-binary @sample_query.json

結果として条件に当てはまるデータが取得できるようになりました。
(一部省略しています。)


{
  "took":324,
  "timed_out":false,
  "_shards":
    {
      "total":1,
      "successful":1,
      "skipped":0,
      "failed":0
    },
  "hits":
    {
      "_index":"museum",
      "_type":"_doc",
      "_id":"1",
      "_source":
        {
          "pref_id": "13", 
          "city_id": "13103", 
          "name": "国立美術館国立新美術館",  
          "location": [139.7263974, 35.6652779]
        }
     }
}

参考

https://www.elastic.co/guide/jp/elasticsearch/reference/current/gs-executing-searches.html
https://blog.chocolapod.net/momokan/entry/114