サナギわさわさ.json

サナギさんとキルミーベイベーとプログラミングが好きです

ElasticSearchのインデクシングを高速化する

諸事情でElasticSearchの事ばっかり書いてますが、Solrの方が好きです。

ElasticSearchのインデクシングを高速化するためにやった事を残しておきます。
基本的には↓に書いてあることばかりです。

Performance Considerations for Elasticsearch Indexing | Elastic

データ投入方法

データの投入にはBulk APIを使います。 なお、公式では1つのbulk Importのサイズは5~15MBにすることを推奨しています。

curl -XPOST http://localhost:9200/_bulk --data-binary @databatch.json >/dev/null
メモリ関係

ES_HEAP_SIZEに実メモリの半分程度を割り当て、mlockall:trueでElasticSearchのメモリがスワップしないようにします。前の記事で書いてるので、詳細はそちらで。

ElasticSearchでmlockall:trueが効かない時にチェックすること - サナギわさわさ.json

レプリカシャードを0に設定

巨大インデックス作成中はレプリカシャードを作らないようにすることで、インデックス作成にかかる時間が割と短くなります。インデックス作成後に好きなだけ作ってください。

curl -XPUT http://localhost:9200/index_name/_settings -d '
{
    "index" : {
        "number_of_replicas" : 0
    }
}'
コミットの頻度を変更

ElasticSearchはNRT(Near Real-Time Search)機能を搭載しており、デフォルトで1sごとにソフトコミットが実行され、更新結果が検索に反映されます。巨大インデックスを作成する際にはこれが結構重いため、インデクシング中に更新結果をそこまでリアルタイムに反映する必要がない場合は、ソフトコミットの頻度は30sぐらいに設定した方が早くなります。
※sをつけないとmsecになってしまうので注意

curl -XPUT http://localhost:9200/index_name/_settings -d '
{
    "index" : {
        "refresh_interval" :  "30s"
    }
}'

また、バッチ処理が終わるまで更新結果を反映させる必要がなく、かつその間他から更新処理がこない事を保証できるなら、-1に設定すればソフトコミットが自動で行われなくなります。

curl -XPUT http://localhost:9200/index_name/_settings -d '
{
    "index" : {
        "refresh_interval" : -1
    }
}'
_allフィールドを無効化

インデクシングしたデータは全て_allフィールドにも入ります。必要ない場合はmappingの際に無効化することで、インデクシングが早くなります。

{
    "person" : {
        "_all" : {"enabled" :  false},
        "properties" : {
        }
    }
}
インデクシングが終わった後

インデクシングが終わった後はoptimizeを行い、レプリカシャードを好きな値に設定してください。

curl -XPOST 'http://localhost:9200/index_name/_optimize'
curl -XPUT http://localhost:9200/index_name/_settings -d '
{
    "index" : {
        "number_of_replicas" : 1
    }
}'

他にもハードコミットの頻度(translog.flush_threshold_size)や、_sourceの無効化や、indices.memory.index_buffer_sizeの設定など、チューニングするポイントはあると思うのですが、 今回は自分の環境で効果を感じたものだけ紹介しました。

公式では22k/secぐらいの速度が出ると言われていた気がするのですが、RAM:8GBのES_HEAP_SIZE:4GB環境では1億件の登録で8k/secぐらいしか出ませんでした。もう少し早くできたらまた記録を載せたいと思います。