この記事はElasticsearch Advent Calendar 2017の12/12分の記事です。
Elasticsearchは1.xから2.x、そして5.x(今月にはもう6が出ましたね)と年々バージョンアップしてきました。そんななかまだ1.x、2.x系を使っているという方は多いのではないでしょうか。Elasticsearchはバージョンアップごとに大きくクエリやマッピングが変わります、またサービスの稼働率を考えるとクラスタのリスタートやホットスワップは難しいシステムとなっていたりしていると思います。
そんな障壁を超えるほどの魅力が5.xにはありました。弊社の検索システムではElasticsearchのバージョンアップにより平均レスポンスタイムが2倍も速くなりました。それだけで十分アップグレードする価値はあるのではないでしょうか。
要点
- 検索クエリごとにきちんとテストを書きましょう、Elasticsearchを実際に使ったCIを組み立てる
- テスト環境のElasticsearchのバージョンアップしてひたすらGreenを目指す
- Deprecated クエリをちゃんと書き換えましょう、Deprecation logを活用する
背景
弊社クックパッドは国内のみならず全世界21言語、67カ国にレシピサービスを提供しています。21以上の言語をサポートするグローバルプラットフォームのレシピ検索にElasticsearchが使われています。言語ごとにindex mappingを用意し、その言語、地域に対して最適な検索を提供しています。
長らく、Elasticsearch v1.7を使っていたのだが、サービスの規模が大きくなるに連れパフォーマンスが気になってきました。それを今年にかけて、段階的にv1.7ー>v2.4ー>v5.5にバージョンアップしました。メジャーバージョンアップごとにたくさんのmapping, query DSLの変更があり、それらをどうやって効率的に解消していったかをはなしたいと思います。
アップグレード手順
- Elasticsearch branch 作成
- ローカルでテストが通るまでコードを直す
- マニュアルチェック(テストでカバーされていないバグ発見)
- ステージング環境にESクラスタを立ててコード&インフラ周りのチェック
- プロダクションデプロイ(hot swap)
- 追加の改善, fix, deprecatedクエリ書き換え
クックパッドでは、検索の機能ごとにElasticsearch上で実際にクエリを走らせて挙動を確認するインテグレーションテストを用意しています。なのでElasticsearchをバージョンアップしてテストを走らせるだけで大体の問題箇所を探すことができました。
テストが走るとき、まずテスト用のindexが作成できないと始まらないので真っ先にmappingを直します。それからquery DSLをひたすら直していきます。ElasticsearchドキュメントのBreaking changesとひたすらにらめっこです。
https://www.elastic.co/guide/en/elasticsearch/reference/2.4/breaking-changes-2.0.html
https://www.elastic.co/guide/en/elasticsearch/reference/5.5/breaking-changes-5.0.html
1.7 -> 2.4 のときの主な変更
mapping changes
- 名称変更:
index_analyzer
,position_offset_gap
など - マッピングのなかで同じフィールド名が使えなくなった
- stopwords, custom_stemファイルなどをElasticsearchの設定ディレクトリ以外から読めなくなった
- Javaのセキュリティアップデートにより外部ファイルを指定したディレクトリからしか読み込めなくなりました。
- stopwordsなどのカスタムファイルを
/etc/elasticsearch/
内に置いた
その他変更
- gem update: https://rubygems.org/gems/elasticsearch/versions
- CI環境をv2.4にセットアップ
- gemアップデートによるpercolateクエリの不具合
- multi percolateクエリを
Elasticsearch::API::Utils.__bulkify(body)
というメソッドを直接たたいてビルドしていたのがだめになった。 - 以前percolateクエリにおいてbulkifyが動いていたのが、この変更により出来なくなっていた
- multi percolateクエリを
この通り、ほとんどマッピング変更でCIもパスし、マニュアルチェックで見つかったバグも直しアップグレードできました。しかし、お気付きの通りクエリの変更がほとんどありません。実は殆どのクエリがdeprecatedになっていたが一応サポートしていたため正常に動いていただけでした。これがv5.5アップグレードのときに大きな負債となりました。
2.4 -> 5.5 のときの主な変更
上述の通り、v1.7 -> v2.4の際にクエリの変更をほとんどしませんでした。v2でdeprecatedになったクエリがなんとか動いていたという状態でした。それがv5になってdeprecatedクエリたちがすべて使えなくなって、クエリエラーがv2変更のエラーなのかv5変更のエラーなのかわからず、v2とv5のドキュメントを行き来することになりました。
このことから学び、v5へのアップグレードではElasticsearchのdeprecation logをもとにdeprecatedになったAPIやクエリを直しました。Deprecation logはバージョンアップでdeprecatedになったクエリのログを出してくれます。次のバージョンでなくなる予定のクエリなので直しておくと、バージョンアップがスムーズに行くと思います。
mapping changes
-
type: "string"
totype: "keyword"
- Significant terms aggregation機能が
keyword
フィールドを推奨 - https://www.elastic.co/guide/en/elasticsearch/reference/5.5/breaking_50_aggregations_changes.html#_significant_terms_on_numeric_fields
- Significant terms aggregation機能が
fielddata: true
- Suggestion変更
-
multi_field
removed -
percolator
の大きな変更によりpercolator用のマッピングを追加
クエリ変更
- v2.xで廃止されたfilterをqueryに変更
- function_score クエリ書き換え
- filterクエリ書き換え
{
filter: { bool: { must: filters } },
query: [queries],
functions: [functions]
}
->
{
query: { bool: { must: [filters, queries] } },
functions: [functions]
}
- なぜかv2で使えていた時間unitの
1w
が使えなくなってた - v2.xでdeprecatedになった
filtered
クエリがv5.xで削除されたので書き換え -
execution "or"
deprecated - Suggestion completionの大型変更によりレスポンスボディが変わってた
-
size: 0
in terms aggregation function is deprecated - GroovyをPainlessへ書き換え
- (Painlessのドキュメント少ない )
-
scan & scroll
でreindexしていたのを、v5から新設されたreindex APIに置き換えた
その他
- suggestion query に約8000文字以上のリクエストが来るとクラスタが落ちる
- 起動オプションが変わった
-
-D es.network.host=xxx
to-E network.host=xxx
-
- 他に特定の言語向けの自然言語処理プラグインを新しいバージョン向けに自前で書き直す必要がありました
v5.xでdeprecatedになった機能の書き換え
上記の変更でテストも通り、プロダクションデプロイできました。バージョンアップ後にdeprecation logをもとに以下のAPIを書き換えました。
その他tips
Elasticsearchに実際に投げられているクエリをproxyツールなどでキャプチャして、Cerebroなどから直接投げて、直るまでCerebroを使ってデバッグするとやりやすかったです。
所感
Elasticsearchはバージョンアップごとにアップグレードしやすくなってきていますね。ES6ではrolling upgradeも対応しましたしね。Deprecation logがデフォルトでonになっていたり、間違ったクエリを投げたときちゃんとどこが悪いのかを返してくれるようになってきていました。そのためデバッグもしやすかったです。
公式ドキュメントの充実しているのもとても助かります。バージョンアップで変わったところをどう書き換えればいいかなど、ちゃんと書かれています。
今回はインフラ周りの話しまでは触れることはできませんでした。サービスの特徴上ホットスワップはある程度やりやすかったのもあります。
また具体的な話しが少なく、いろいろ詳細部分がもれてわかりにくい記事になっているかもしれません m(_ _)m それらについてはコメント等で聞いていただければと思います。
明日は"Elasticsearchのための新しい形態素解析器「Sudachi」"についてですね。アドベントカレンダーこれからも楽しみにしています。