VPS

ElasticSearchのインストール/設定/運用

ElasticSearchとは

オープンソースの検索エンジン。

https://github.com/elastic/elasticsearch
HelloWork+で使う検索エンジンを検討するにあたって、
– 自作
– Groonga
と比較して考えたが、世界的なシェアを考えて採用してみた。

とはいえ、逆に世界向けの検索は、日本語関連の問題が多いが、それに関する情報は少なく(+あっても現バージョンでは古くて使えない)、それなりに苦労するというデメリットがあった事も書いておく。

インストール

参照
https://www.elastic.co/guide/en/elasticsearch/reference/7.8/rpm.html#rpm-repo

CentOS系の場合
/etc/yum.repos.d/elasticsearch.repo を以下の中身で作成

[elasticsearch]
name=Elasticsearch repository for 7.x packages
baseurl=https://artifacts.elastic.co/packages/7.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=0
autorefresh=1
type=rpm-md
yes | sudo dnf install --enablerepo=elasticsearch elasticsearch
sudo systemctl daemon-reload;
sudo systemctl enable elasticsearch.service;
sudo systemctl start elasticsearch.service;

Job for elasticsearch.service failed because a timeout was exceeded.
というメッセージが出て、タイムアウトで起動に失敗してしまったらタイムアウトの秒数を伸ばしてみる。

sudo systemctl show elasticsearch | grep ^Timeout;
sudo mkdir /etc/systemd/system/elasticsearch.service.d;
echo -e "[Service]\nTimeoutStartSec=300" | sudo tee /etc/systemd/system/elasticsearch.service.d/startup-timeout.conf;
sudo systemctl daemon-reload;
sudo systemctl show elasticsearch | grep ^Timeout;
sudo systemctl start elasticsearch;

但し、そうはいっても立ち上げに時間がかかりすぎる事自体、適切な事ではなく、これで解決する場合には、メモリ不足が理由の可能性がある。
topコマンドを打つと、swap領域を使っている状態になっていたりする。
ElasticSearchはデフォルトでは最低1GBは使う設定になっているので、サーバー全体としてはメモリは最低1.5GB以上なければ、そうした状態になってもおかしくない。

日本語対応の設定

デフォルトままだと、英語の検索は出来るが、日本語の検索に問題があるので、日本語対応をする。

まずそのために必要なプラグインのインストール。

cd /usr/share/elasticsearch/bin;
sudo ./elasticsearch-plugin install analysis-kuromoji;
sudo ./elasticsearch-plugin install analysis-icu;
sudo systemctl restart elasticsearch;

ここから、指定したIndexにて、kuromojiを使う様に指定する。
例えば、jobsというインデックスに対して適用するには、以下の様にする

ESSERVER="es1";
INDEX="jobs";
curl -XGET $ESSERVER:9200/jobs/_settings;

# 変更には一旦Indexを閉じる事が必要
curl -XPOST $ESSERVER:9200/jobs/_close;
# REST API経由でインデックス事に設定。 昔の文章にある様に /etc/elasticsearch/elasticsearch.yml 経由では設定できない
curl -H "Content-Type: application/json"  -XPUT http://$ESSERVER:9200/$INDEX/_settings?preserve_existing=true -d '{
  "index.analysis.analyzer.default.tokenizer" : "kuromoji_tokenizer",
  "index.analysis.analyzer.default.type" : "custom"
}';

# ここで日本語の分ち書きの設定
curl -H "Content-Type: application/json" -XPUT "localhost:9200/jobs/_settings?pretty" -d'
{
  "settings": {
    "index":{
      "analysis": {
        "filter": {
          "greek_lowercase_filter": {
            "type": "lowercase",
            "language": "greek"
          }
        },
        "tokenizer": {
          "kuromoji": {
            "type": "kuromoji_tokenizer"
          },
          "ngram_tokenizer": {
            "type": "nGram",
            "min_gram": "2",
            "max_gram": "3",
            "token_chars": [
              "letter",
              "digit"
            ]
          }
        },
        "analyzer": {
          "kuromoji_analyzer": {
            "type": "custom",
            "tokenizer": "kuromoji_tokenizer",
            "filter": [
              "kuromoji_baseform",
              "pos_filter",
              "greek_lowercase_filter",
              "cjk_width"
            ]
          },
          "ngram_analyzer": {
            "tokenizer": "ngram_tokenizer"
          }
        }
      }
    }
  }
}';

# Indexを開き直す
curl -XPOST $ESSERVER:9200/jobs/_open;

# 設定の確認
ESSERVER="es1";
INDEX="jobs";
curl -H "Content-Type: application/json"  -GET http://$ESSERVER:9200/$INDEX/_settings;

# 実際のわかち書きの稼働の確認 / 1文字毎でなく単語で切れていれば成功
ESSERVER="es1";
INDEX="jobs";
curl -H "Content-Type: application/json"  -XGET 'http://es1:9200/jobs/_analyze?pretty' -d '{"text":"富山市"}';

日本語をきちんと検索出来る式を作る

日本語の特性とESは、そのままだと色々相性が悪いです。
設定の問題は先の手順で解決したとして、Queryの方も工夫する必要があります。
自分は既存のPHPのライブラリでは問題があったので、自作でQueryを作って、投げる事で解決させた。
結論からいうと、bool検索でmust条件の中でmatch_pharase条件での検索を、単語ごとに投げる事で解決させた。

なお、検索結果から返されてくるJSONを、配列に変換して、プログラム内では表示する必要が当然ある。

使用メモリを抑える

ElasticSearchはメモリを大量に使うので、あえてそれを下げて使いたい場合の設定。

/etc/elasticsearch/jvm.optionsを編集して

#-Xms1g
#-Xmx1g
-Xms200m
-Xmx200m

と書き換える。

尚、100mを指定した時は、結構すぐElasticSearchが落ちたので、200mにした。
何もしないで動かすのならこのサイズでもOKだが、索引対象の量が増えていくと

"error":{"root_cause":[{"type":"circuit_breaking_exception","reason":"[parent] Data too large, data for [<http_request>] would be [208471918/198.8mb], wh  
  ich is larger than the limit of [199229440/190mb], real usage: [205831976/196.2mb], new bytes reserved: [2639942/2.5mb], usages [request=0/0b, fielddata=0  
  /0b, in_flight_requests=2639942/2.5mb, accounting=37672/36.7kb]","bytes_wanted":208471918,"bytes_limit":199229440,"durability":"TRANSIENT"}]...

といったエラーで処理が途中で止まってしまう事が起きたりする。
そしたらこの定義の数値を上げて、また走らせてみよう。

なお、勝手に落ちる事がありえるので、定期的にプロセスを立ち上げる処理をcronで設定しておくと良いだろう。

ElasticSearchの索引の中身の統計情報を確認

curl localhost:9200/_stats

と打つと返ってくるJSONで確認出来る。

ElasticSearchの中身のVisualizeツールKibanaのインストール・設定

dnf(yum)でのインストール

/etc/yum.repos.d/kibana.repo
を編集し

[kibana-5.x]
name=Kibana repository for 5.x packages
baseurl=https://artifacts.elastic.co/packages/5.x/yum
gpgcheck=1
gpgkey=https://artifacts.elastic.co/GPG-KEY-elasticsearch
enabled=1
autorefresh=1
type=rpm-md

と書く

そしたら

dnf install kibana

でインストール可能

Kibanaの起動は

systemctl start kibana

自動起動するようにするには

systemctl enable kibana

そしたら
ポート5601
でアクセスできるようになっている
http://…:5601/

最後にBasic認証、IP制限等で制限をかけて、他人がアクセスできないようにする。