Rails + ElasticSearch 調査メモ

# ElasticSearch

java8以上が必要 ([ダウンロード](https://qiita.com/Hitoshi5858/items/02a8e231cb346e5efbf9))

```
# ESのインストール
$ brew install elasticsearch

# ESの起動
$ /usr/local/Cellar/elasticsearch/7.8.1/bin/elasticsearch
or
$ elasticsearch

# 動作確認
$ curl http://localhost:9200

```

### プラグインの追加

- kuromoji (分かち書き)
- ICU (文字の正規化フィルター)

```
$ elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-kuromoji/analysis-kuromoji-7.8.1.zip
$ elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-7.8.1.zip
```

<br />

## データ構造

RDBと比べたときのESの構造 ([参考](https://vitalify.jp/blog/2017/02/elasticsearch_matome.html))

```
Cluster > Node > Index( = DB) > Type(=Table) >Document( =Row)
```

<br />

## 基本的な使い方
```
# index一覧
curl -X GET http://localhost:9200/_cat/indices

# index作成
curl -XPUT http://localhost:9200/インデックス名

# indexの削除
curl -XDELETE localhost:9200/インデックス名

# docの追加
curl -XPOST http://localhost:9200/インデックス名/タイプ名/ -d '{
    "field_01": "hoge1",
}'


# docの取得
curl -XGET http://localhost:9200/new_index/_search

curl -H "Content-Type: application/json" -XGET localhost:9200/インデックス名/_search\?pretty  -d '{"size":100}'

    ※?prettyで結果を整形して出力
    ※ -d '{"size":100}'で件数を指定しないとマックス10件しかでない。
    ※ jsonを送るときは「 -H "Content-Type: application/json"」が必要


# docの検索
curl -H "Content-Type: application/json" -XGET localhost:9200/インデックス名/_search\?pretty  -d'
{
  "query": {
    "match": {
      項目名: 検索値
    }
  }
}'


# docの追加
curl -H "Content-Type: application/json" -XPOST http://localhost:9200/インデックス名/new/ -d'{
  項目名: 値
}'
```

<br />

## Kibana
リクエストビルダー的な機能があるので開発で必要なら入れる

```
# install
$ brew install kibana
$ brew info kibana

# 起動
$ kibana

# ダッシュボードにアクセス
http://localhost:5601/app/kibana#/dev_tools/console
```

<br />

## 参考リンク

- [searchAPI](https://www.elastic.co/guide/en/elasticsearch/reference/current/search-search.html)
- [queryDSL](https://www.elastic.co/guide/en/elasticsearch/reference/current/query-filter-context.html)
- [クエリの例 SQLと比較](https://qiita.com/NAO_MK2/items/630f2c4caa0e8a42407c)
- [Elasticsearch実運用時の注意点とアンチパターンまとめ](http://kakakazuma.hatenablog.com/entry/2016/07/19/100000_2#_all%E3%81%AE%E4%BD%BF%E7%94%A8%E3%81%AF%E5%BF%85%E8%A6%81%E3%81%AA%E6%99%82%E3%81%AE%E3%81%BF%E8%A1%8C%E3%81%86)
- [Elasticsearch を検索エンジンとして利用する際のポイント](https://engineering.linecorp.com/ja/blog/using-elasticsearch-as-a-search-engine/)
- メモリはデフォルトは2Gでサーバーのメモリの50%以下が目安。
なのでサーバーとしては4Gは欲しい。[参考](https://www.elastic.co/guide/en/elasticsearch/reference/7.9/heap-size.html#heap-size)



# RailsからElasticSearchを利用する

- [elasticsearch-rails](https://github.com/elastic/elasticsearch-rails) gem を利用。
- `include Elasticsearch::Model` してModel経由で操作する。
- index名は環境で変わるように、`index_name "articles-#{Rails.env}"` と設定している。

```
# index作成
<Model名>.create_index

# DBのデータを全部インポートし直し
<Model名>__elasticsearch__.import

# データ検索例
<Model名>.search query:{ match_all: {}}
<Model名>.search query:{ match: {title:”hello”}}
```

Model変更処理の際にsidekiqをasync実行（`ArticleIndexer.perform_async`） → Redis にキューイングされて非同期で ElasticSearchのインデックスが作成される（`models/concerns/article_searchable`）

<br />

## sidekiq

非同期でのインデックス更新のために必要。
Redisにキューイングされて非同期でElasticSearchにインデックスされる。

```
$ brew install redis 

$ gem 'sidekiq'

$ bundle exec sidekiq -C config/sidekiq.yml
```

[参考](https://qiita.com/yumiyon/items/6835d90e621e73268021)




## ElasticSearch日本語用プラグインの話




・インデックスの設定の確認(analyzerを指定していればれで確認できる。)

```
curl -H "Content-Type: application/json"  http://localhost:9200/articles-test/_mappings\?pretty
curl -H "Content-Type: application/json"  http://localhost:9200/articles-test/\?pretty
```

・esでクエリーがどのように分割されるのか（分かち書き== tokenize)の確認

```
curl -H "Content-Type: application/json" -XGET localhost:9200/articles-test/_search\?pretty  -d'
{
  "query": {
    "match": {
      "title": "東京都"
    }
  }
}'
```


### そもそも全文検索について
基本的には完全一致ではない。
全文検索は英語などだと、スペースで単語を区切り、その単語毎に分割してインデックスを作成する。
その分割した単語でマッチさせるため、完全一致で検索するとは限らない。

kuromojiとngramはこの分かち書きのための設定。ngramの方が一致率は高い。

icuでやってくれることは半角カナとかをうまく、普通の文字としてインデックスしてくれる。
日本語のUTF-8文字を上うまいこと変換してくれるフィルター的な..



#### 全文検索について 参考リンク

https://dev.classmethod.jp/articles/es-02/
https://tech-blog.rakus.co.jp/entry/20191002/elasticsearch#Analyzer%E3%81%A8%E3%81%AF
https://medium.com/hello-elasticsearch/elasticsearch-833a0704e44b
https://qiita.com/shin_hayata/items/41c07923dbf58f13eec4


#### タームベースクエリ(完全一致)
https://blog.chocolapod.net/momokan/entry/114

#### filterとqueryの違い
query(full text search)は検索結果の取得にスコアを考慮しなし。
検索結果に関連性が高いかを示すスコアが大事な時は query を使うという感じ

#### スコアとは
検索結果の順位をどう決めるのか
一つの文書の中で該当検索語がよくマッチしていて、しかもそれは他の文書ではあんまり見られない該当文書のユニークな検索語で、しかもそれが短い文書であれば、マッチ度は高い
https://qiita.com/r4-keisuke/items/d653d26b6fc8b7955c05


#### ICUフィルターがしてくれること

https://medium.com/hello-elasticsearch/elasticsearch-c98fd9ce6a18
フィルターに設定して文字の正規化を行う



## 日本語用プラグインのインストール
#### Kuromojiインストール

```
/usr/local/Cellar/elasticsearch/7.8.1/bin/elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-kuromoji/analysis-kuromoji-7.8.1.zip
```

#### ICU インストール
```
/usr/local/Cellar/elasticsearch/7.8.1/bin/elasticsearch-plugin install https://artifacts.elastic.co/downloads/elasticsearch-plugins/analysis-icu/analysis-icu-7.8.1.zip
```

#### railsでの設定参考
https://qiita.com/chase0213/items/381b1eeacb849d93ecfd
https://qiita.com/yamashun/items/e1f2157e1b3cf3a716e3