Elasticsearchでの全文検索

本記事は[東京学芸大学 櫨山研究室 Advent Calendar 2020](https://qiita.com/advent-calendar/2020/hazelab)の十一日目の記事になります．


# はじめに

本記事ではElasticsearchをDockerで構築し，RESTful APIを使ってElasticsearchにドキュメントを登録・検索する手順を扱います．

# Elasticsearchの準備

ElasticsearchはElastic社が開発している全文検索エンジンです．
今回はDockerで起動します．

バージョンは`7.10`を使用します．

```docker:Dockerfile
FROM docker.elastic.co/elasticsearch/elasticsearch:7.10.0
RUN elasticsearch-plugin install analysis-kuromoji
```

日本語を対象とした全文検索を行うため`kuromoji`プラグインを導入しています．

ポートや環境変数の設定をしたいので`docker-compose.yml`を用意します．

```yml:docker-compose.yml
version: '3.7'

services:
 elasticsearch:
    container_name: elasticsearch
    build: ./
    environment:
      - discovery.type=single-node
      - cluster.name=docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ports:
      - 9200:9200
    tty: true
```

`docker-compose up`コマンドで立ち上げます．

```bash:bash
docker-compose up
```

正常に起動したら`curl`コマンドでリクエストを送ってみましょう．
レスポンスがきちんと返ってくれば正常に動いています🙆‍♂️

```bash:bash
curl http://localhost:9200
{
  "name" : "a868b38a737e",
  "cluster_name" : "docker-cluster",
  "cluster_uuid" : "xASK1SUISqKRchPyg2OFFg",
  "version" : {
    "number" : "7.10.0",
    "build_flavor" : "default",
    "build_type" : "docker",
    "build_hash" : "51e9d6f22758d0374a0f3f5c6e8f3a7997850f96",
    "build_date" : "2020-11-09T21:30:33.964949Z",
    "build_snapshot" : false,
    "lucene_version" : "8.7.0",
    "minimum_wire_compatibility_version" : "6.8.0",
    "minimum_index_compatibility_version" : "6.0.0-beta1"
  },
  "tagline" : "You Know, for Search"
}

```


# Elasticsearchにドキュメントを登録する

早速`curl`コマンドを使ってElasticsearchにドキュメントを登録します．
今回は以下のような形の`json`を登録してみます．

```json
{
  "poet": "天智天皇",
  "verse": "秋の田のかりほの庵の苫をあらみ わが衣手は露にぬれつつ"
}
```

index名は`ogura`とします．

```bash
curl -XPOST -H 'Content-Type:application/json' \
-d '{"poet":"天智天皇", "verse":"秋の田のかりほの庵の苫をあらみ わが衣手は露にぬれつつ"}' \
http://localhost:9200/ogura/_doc
```

# Elasticsearchからドキュメントを検索する

Elasticsearchに登録されているドキュメントから全文検索で取り出してみましょう．
**"秋"**をクエリにして検索してみましょう．

```json
{
  "query": {"query_string": { "query": "秋" }}
}
```

```bash:bash
curl -XPOST -H 'Content-Type:application/json' \
-d '{"query": {"query_string": {"query": "秋"}}}' \
http://localhost:9200/ogura/_search
```

```json:出力（jqで整形済み）
{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.2876821,
    "hits": [
      {
        "_index": "ogura",
        "_type": "_doc",
        "_id": "Au7XUXYBQ0gvhrysI8q9",
        "_score": 0.2876821,
        "_source": {
          "poet": "天智天皇",
          "verse": "秋の田のかりほの庵の苫をあらみ わが衣手は露にぬれつつ"
        }
      }
    ]
  }
}
```

スコアは`0.2876821`と低いですがヒットしていることがわかりますね．

**"天皇"**をクエリに検索してみましょう．

```bash:bash
curl -XPOST -H 'Content-Type:application/json' \
-d '{"query": {"query_string": {"query": "天皇"}}}' \
http://localhost:9200/ogura/_search
```

```json:出力（jqで整形済み）
{
  "took": 11,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 1,
      "relation": "eq"
    },
    "max_score": 0.68324494,
    "hits": [
      {
        "_index": "ogura",
        "_type": "_doc",
        "_id": "ZiHlUXYB-j-65sbqA5hz",
        "_score": 0.68324494,
        "_source": {
          "poet": "天智天皇",
          "verse": "秋の田のかりほの庵の苫をあらみ わが衣手は露にぬれつつ"
        }
      }
    ]
  }
}
```

先ほどよりも高いスコア`0.68324494`でヒットしていることがわかります．

# おわりに

今回は全文検索エンジンのElasticsearchをDockerで立ててRESTful APIを使ってドキュメントの登録・検索をやってみました．

Elasticsearchでは前回までの記事で扱っていたMySQLと異なり非構造化データ(json)で検索対象を保存することができます．

触ってみるとRESTful APIによるインターフェースやチューニングの幅も広く，非常に優れたソフトウェアであることがわかるかと思います．