patorashのブログ

方向性はまだない

SearchBoxのmax_result_windowは変更できない

私が関わっている製品で、HerokuのElasticsearchのアドオンはSearchBox(Searchly)を使っているのですが、これでハマったのでちょっと調査した結果を残しておきます。

検索結果画面のページ移動のところで、ページ番号の大きなページにアクセスしようとすると、500エラーが発生していました。メッセージは以下のような感じです。

Result window is too large, from + size must be less than or equal to: [10000] but was [80000]. See the scroll api for a more efficient way to request large data sets. This limit can be set by changing the [index.max_result_window] index level parameter

from + sizeが10,000以上だから大きすぎる。scroll apiを使うか、index.max_result_windowの値を大きくしてくれということです。ページング処理自体はkaminari gemに任せていたのですが、件数が多すぎたらこんなことになるとは…。ちなみにこの制限はElasticsearch2から加わったそうです。max_result_windowが大きいと、その分多くのメモリを使ってデータを確保した後に絞込みを行なうことになるので、やたらと大きな数値であることはよくないようです。

とはいえ、変えるだけで済むなら…と思い調べたところ、max_result_windowを設定する方法はすぐに見つかりました。

ElasticSearch - Result window is too large, from + size must be less than or equal to: [10000] · GitHub

これをローカルで変更してみたところ、直りました。

curl -XPUT http://localhost:9200/index_name/_settings -d '{ "index" : { "max_result_window" : 1000000 } }'

SearchBoxのほうでも変えようとしたのですが、設定画面がありません。同じ様にcurlAPIにアクセスしてみたのですが、バリデーションエラーで弾かれました。公式ドキュメントを見た所、settings APIは公開していない模様です。

devcenter.heroku.com

elasticsearch-modelを使っているので、create_index!をするタイミングでなら設定できるかもしれないと思い、やってみました。 その後、以下のように設定を取得してみました。

curl -XGET http://localhost:9200/index_name/_settings

ローカルでは、max_result_windowが書き換えることができました。

{"index_name":{"setting":{"index":{"max_result_window":1000000,...}}}}

これをSearchBoxに対して実行したら、max_result_window自体がありませんでした。

{"index_name":{"setting":{"index":{...}}}}

ローカルでは成功しましたが、やはりSearchBoxではダメでした。

対処法

対処方法としては、以下の2つが考えられます。

  1. 上位1万件までを表示対象にする
  2. 別のアドオンを使う(bonsaiなど)

2の方法は、teratailの質問でそういう回答があったので、おそらくbonsaiだとmax_result_windowの値が変更できるのだと思いますが、検証はしていません。

teratail.com

今回は1の方法で対応するようしました。

まとめ

Elasticsearchはランダムページアクセスに弱いようです。 search_afterを使えば、1万を超えたアクセスはできるようですが、ページング向きではありません。search_afterは、ステートレスなscroll apiのような動きのようです。

www.elastic.co

とはいえ、ちゃんと絞込みすればいいだけの話なので、そちらに合わせる様にしたほうがよさそうだなと思います。