LoginSignup
2
7

More than 5 years have passed since last update.

Elasticsearch 2.4.4 設定サンプル等

Last updated at Posted at 2017-01-27

OSはCentOS 7.2

elasticsearch.yml

cluster.name: クラスタ名
node.name: "ノード名"
node.master: true
node.data: true

network.host: '_eth0:ipv4_'
discovery.zen.minimum_master_nodes: 1
discovery.zen.ping.timeout: 3s
discovery.zen.ping.unicast.hosts: ["ホスト名orIPアドレス"]
path.data: /data/elasticsearch
index.number_of_shards: 1
index.number_of_replicas: 0
bootstrap.memory_lock: true

script.groovy.sandbox.enabled: true
script.engine.groovy.inline.aggs: true
script.engine.groovy.indexed.aggs: true
script.engine.groovy.indexed.mapping: true
script.inline: true
script:indexed: true

1ノードでmaster兼用設定
多ノードの場合もshardsの数は1,6,12,24,36,60等データノードを随時増やしても割り切れる数を指定するようにしている。
scriptはfunction_scoreでカスタムの_scoreを計算するためのもの。もっと権限絞りこめるが、とりあえず動かすこと優先。
bootstrap.memory_lockは以前はbootstrap.mlockだったものが名称変更。内部的にはまだmlockでも互換性のために残っているが非推奨なのかな。
Multi-AZでZone毎にデータ完結させたい(Zoneを跨がないので通信遅延の削減にもなる)場合は下記を追加

node.zone: ap-northeast-1a *ノードのあるzone
cluster.routing.allocation.awareness.attributes: zone
cluster.routing.allocation.awareness.force.zone.values: ap-northeast-1a,ap-northeast-1c

mapping template

{
    "template" : "適用インデックスの頭文字列*",
    "order" : 0,
    "settings" : {
      "refresh_interval" : "1m",
      "index.analysis.filter.romaji.type" : "kuromoji_neologd_readingform",
      "index.analysis.filter.romaji.use_romaji" : "true",
      "index.analysis.filter.synonym.type" : "synonym",
      "index.analysis.filter.synonym.synonyms_path" : "user_synonym.txt",
      "index.analysis.tokenizer.ja_tokenizer.type" : "kuromoji_neologd_tokenizer",
      "index.analysis.tokenizer.ja_tokenizer.user_dictionary" : "userdict_ja.txt",
      "index.analysis.tokenizer.ja_tokenizer.mode" : "search",
      "index.analysis.analyzer.default.tokenizer" : "ja_tokenizer",
      "index.analysis.analyzer.facet_analyzer.type" : "custom",
      "index.analysis.analyzer.facet_analyzer.char_filter.0" : "html_strip",
      "index.analysis.analyzer.facet_analyzer.tokenizer" : "keyword",
      "index.analysis.analyzer.facet_analyzer.filter.0" : "cjk_width",
      "index.analysis.analyzer.facet_analyzer.filter.1" : "lowercase",
      "index.analysis.analyzer.ws_analyzer.type" : "custom",
      "index.analysis.analyzer.ws_analyzer.char_filter.0" : "html_strip",
      "index.analysis.analyzer.ws_analyzer.tokenizer" : "whitespace",
      "index.analysis.analyzer.ws_analyzer.filter.0" : "cjk_width",
      "index.analysis.analyzer.ws_analyzer.filter.1" : "lowercase",
      "index.analysis.analyzer.ws_analyzer2.type" : "custom",
      "index.analysis.analyzer.ws_analyzer2.char_filter.0" : "html_strip",
      "index.analysis.analyzer.ws_analyzer2.tokenizer" : "whitespace",
      "index.analysis.analyzer.ja_analyzer.type" : "custom",
      "index.analysis.analyzer.ja_analyzer.char_filter.0" : "html_strip",
      "index.analysis.analyzer.ja_analyzer.char_filter.1" : "kuromoji_neologd_iteration_mark",
      "index.analysis.analyzer.ja_analyzer.tokenizer" : "ja_tokenizer",
      "index.analysis.analyzer.ja_analyzer.filter.0" : "cjk_width",
      "index.analysis.analyzer.ja_analyzer.filter.1" : "lowercase",
      "index.analysis.analyzer.ja_analyzer.filter.2" : "kuromoji_neologd_stemmer",
      "index.analysis.analyzer.ja_analyzer.filter.3" : "kuromoji_neologd_part_of_speech",
      "index.analysis.analyzer.ruigi_analyzer.type" : "custom",
      "index.analysis.analyzer.ruigi_analyzer.char_filter.0" : "html_strip",
      "index.analysis.analyzer.ruigi_analyzer.char_filter.1" : "kuromoji_neologd_iteration_mark",
      "index.analysis.analyzer.ruigi_analyzer.tokenizer" : "ja_tokenizer",
      "index.analysis.analyzer.ruigi_analyzer.filter.0" : "cjk_width",
      "index.analysis.analyzer.ruigi_analyzer.filter.1" : "lowercase",
      "index.analysis.analyzer.ruigi_analyzer.filter.2" : "kuromoji_neologd_stemmer",
      "index.analysis.analyzer.ruigi_analyzer.filter.3" : "kuromoji_neologd_part_of_speech",
      "index.analysis.analyzer.ruigi_analyzer.filter.4" : "synonym"
    },
    "mappings" : {
      "_default_" : {
        "dynamic_templates" : [ {
          "string_fields2" : {
            "match_pattern" : "regex",
            "mapping" : {
              "type" : "string",
              "fields" : {
                "raw" : {
                  "index" : "not_analyzed",
                  "type" : "string"
                },
                "ws2" : {
                  "analyzer" : "ws_analyzer2",
                  "type" : "string"
                }
              }
            },
            "match_mapping_type" : "string",
            "match" : "str_特殊なフィールド名.*"
          }
        }, {
          "string_fields" : {
            "match_pattern" : "regex",
            "mapping" : {
              "type" : "string",
              "fields" : {
                "raw" : {
                  "index" : "not_analyzed",
                  "type" : "string"
                },
                "facet" : {
                  "analyzer" : "facet_analyzer",
                  "type" : "string"
                },
                "ws" : {
                  "analyzer" : "ws_analyzer",
                  "type" : "string"
                },
                "ja" : {
                  "analyzer" : "ja_analyzer",
                  "type" : "string"
                },
                "ruigi" : {
                  "analyzer" : "ruigi_analyzer",
                  "type" : "string"
                }
              }
            },
            "match_mapping_type" : "string",
            "match" : "str_.*"
          }
        }, {
          "text_fields" : {
            "mapping" : {
              "type" : "string",
              "fields" : {
                "raw" : {
                  "index" : "not_analyzed",
                  "type" : "string"
                }
              }
            },
            "match_mapping_type" : "string",
            "match" : "txt_.*"
          }
        }, {
          "double_fields" : {
            "match_mapping_type" : "double",
            "mapping" : {
              "type" : "double"
            },
            "match" :"dbl_.*"
          }
        }, {
          "long_fields" : {
            "match_mapping_type" : "long",
            "mapping" : {
              "type" : "long"
            },
            "match" :"l_.*"
          }
        }, {
          "integer_fields" : {
            "match_mapping_type" : "integer",
            "mapping" : {
              "type" : "integer"
            },
            "match" :"i_.*"
          }
        }, {
          "boolean_fields" : {
            "match_mapping_type" : "boolean",
            "mapping" : {
              "type" : "boolean"
            },
            "match" :"b_.*"
          }
        }, {
          "date_fields" : {
            "match_mapping_type" : "date",
            "mapping" : {
              "type" : "date",
              "format": "yyyy-MM-dd hh:mm:ss"
            },
            "match" :"date_.*"
          }
        }, {
          "timezone_fields" : {
            "match_mapping_type" : "date",
            "mapping" : {
              "type" : "date",
              "format": "hh:mm:ss"
            },
            "match" :"tz_.*"
          }
        } ],
        "_all" : {"enabled" : false}
      }
    },
    "aliases" : { }
}

投入するデータの型をカラム名で決める方式。途中でスキーマ変わるかもとか仕様が不確定な場合とか。
str_は文字列解析有り、txt_は文字列解析無し。
string_fields2はアルファベットの大文字小文字を区別したい場合用
NGRAMは検索精度が悪くなりすぎるので使いません。
refresh_interval設定はBulk転送時の負荷を下げるため。
 elasticsearch.ymlでは設定できなくなったようなのでテンプレートに移動
 反映待ち1分だと長過ぎる場合は30sとかに、単位付けないとms扱いらしい。デフォルト値は1s
*2.4以降から?5.0でindex系の設定がelasticsearch.ymlで設定できなくなった影響かも
 情報元:https://github.com/elastic/elasticsearch/issues/20584

/etc/sysconfig/elasticsearch

MAX_LOCKED_MEMORY=unlimited
ES_HEAP_SIZE=8g

搭載メモリが16GBの例
ただし、8gだと丁度半分なので起動時にWARNINGが発生する。
*31gまでか搭載メモリの半分まで制限がある。
*ES_HEAP_NEWSIZEと両方指定するとCPU負荷が上がりっぱなしになる。
/etc/init.d/elasticsearch
で指定する例も見かけるが、現状それではヒープサイズはデフォルトのまま。
*「ps -aelf |grep elas」とかして-Xms,-Xmxとかの値で確認できる。

/etc/systemd/system/elasticsearch.service

CentOS系(6.8, 7.2で確認)ではbootstrap.memory_lock: trueのために追加でsystemdの設定が必要
cp /usr/lib/systemd/system/elasticsearch.service /etc/systemd/system/elasticsearch.service
雛形をコピーして編集(コメントアウトを外す)

LimitMEMLOCK=infinity

変更したら
systemctl daemon-reload
/etc/init.d/elasticsearch restart

検索のクエリ例(PHP)

$query = [
  'query' => [
    'function_score' => [
      'query' => [
        'filtered' => [
          'query' => [
            'bool' => [
              'must' => [
                [ 'query_string' => [
                    'query' => $検索文字列,
                    'default_field' => 'str_検索対象.ws'
                  ]
                ]
              ]
            ]
          ],
          'filter' => [
            'bool' => [
              'must' => [
                [ 'term' => [ "$フラグ" => true ] ]
              ],
              'must_not' => [
                [ 'wildcard' => [ 'str_特殊なフィールド名.ws2' => $検索文字列 ] ]
              ]
            ]
          ]
        ]
      ],
      'script_score' => [
        "script" => "(float)_score * doc['dbl_score_coff'].value + doc['dbl_score_term'].value"
      ],
      'boost_mode' => 'replace'
    ]
  ]
  ,'from' => 0
  ,'size' => 10
];

ポイントは
・function_scoreの中にfilteredクエリ。逆はエラー。
・script内の_scoreは前に(float)を付けないと結果が整数値になる
・wildcardは「検索対象と全く同じであること」という条件に使用している。
 →matchでいい。matchだと0/1ではなく、query_stringで完全一致したときと同じようなスコアを得られる。

・/var/log/elasticsearchを追加ディスクのシンボリックリンクに変更する。
*ルートと同じディスクに置かない。
・query_stringの特殊文字対策(とりあえず削る)

$k = preg_replace("/\'/", ' ', $k);
$k = preg_replace("/\"/", ' ', $k);
$k = preg_replace("/\//", ' ', $k);
$k = preg_replace("/\{/", ' ', $k);
$k = preg_replace("/\}/", ' ', $k);
$k = preg_replace("/\(/", ' ', $k);
$k = preg_replace("/\)/", ' ', $k);
$k = preg_replace("/\[/", ' ', $k);
$k = preg_replace("/\]/", ' ', $k);
$k = preg_replace("/\~/", ' ', $k);
$k = preg_replace("/\^/", ' ', $k);
$k = preg_replace("/\$/", ' ', $k);
$k = preg_replace("/\+/", ' ', $k);
$k = preg_replace("/\./", ' ', $k);
$k = preg_replace("/\?/", ' ', $k);
$k = preg_replace("/\*/", ' ', $k);
$k = preg_replace("/:/", ' ', $k);
$k = preg_replace("/;/", ' ', $k);
$k = preg_replace("/,/", ' ', $k);
$k = preg_replace("/!/", ' ', $k);
$k = preg_replace("/ +/", ' ', $k);
$k = preg_replace("/\t+/", ' ', $k);
$k = preg_replace("/\s+/", ' ', $k);
$k = trim($k);

求む

・データを完全にメモリー上に置く設定
 *path.dataをtmpfs上に置くと安定して早くなるが、データ量が少ない場合しか使えない。

2
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
7