こんにちは、クラウドソーシングサービス「クラウドワークス」でエンジニアをしている神山です。クライアントとワーカーのマッチングに関わる機能の運用・改善を行うデリバードチームに所属しています。
本サービスではRails環境での検索エンジン運用に Elasticsearch Rails を使用してますが、この度 Searchkick への移行を決定し、現在移行作業中です。この移行作業を通じて、Elasticsearch RailsとSearchkickの間にはいくつか顕著な違いがあり、特にElasticsearch Railsからの移行に際して注意が必要な点がいくつか存在しました。今回はその点を中心に書きました。
Searchkick移行の背景
趣旨とは逸れるため簡潔に書きますが、検索エンジンを Elasticsearch から OpenSearch へ移行する予定があり、Elasticsearch RailsではOpensearchに対応していないためSearchkickに移行することを決めました。(他のGemも候補にありましたが選定理由は省略いたします。)
またElasticsearch RailsがElasticsearch8に対応していなかったこともGemを移行したい理由の一つにありましたが、それがSearchkick移行の大きな要因ではありません。そのため2024年4月16日にElasticsearch RailsはElasticsearch8に対応した v8.0.0.pre をリリースし2024年5月31日に v8.0.0 をリリースしておりますが、Searchkick移行は継続して行っております。
移行の際に気付いたSearchkickの注意点
Searchkickではデータ作成や更新時のコールバック処理がデフォルトで作動する
Elasticsearch Railsの場合、Elasticsearch::Model::Callbacks
をモデルに明示的にインクルードしない限り、データ作成や更新の際にElasticsearchのインデックスに対する処理は発生しません。
しかし、Searchkickではデフォルト設定でRailsの after_commit
コールバックにインデックスへのドキュメントの追加などの処理を含めます。これによりElasticsearchへのリクエストが増加したり、意図しないデータ更新が自動的にインデックスされるため、その挙動を理解しておいたほうが良さそうです。
以下のように callbacks
オプションを false
に設定すると、コールバック処理を行わなくなります。
class Job < ApplicationRecord searchkick callbacks: false # ... end
Searchkickが用意しているインデックス生成メソッドの挙動が想像と少し違う動きをした
SearchkickではSearchkick::Index#create
とSearchkick::Index#create_index
の2つのインデックス生成メソッドを提供しています。
Searchkick::Index#create
はElasticsearch::API::Indices::IndicesClient#create
をそのまま使用します。しかしマッピングやセッティングなどの設定をモデルに記述していても反映されないため、必要な設定を引数に渡す必要があります。
一方Searchkick::Index#create_index
はモデルに記述した設定を反映してインデックスを作成しますが、インデックス名がタイムスタンプを含んだ特定の形式("#{name}_#{Time.now.strftime('%Y%m%d%H%M%S%L')}"
)になってしまいます。これはインデックス名の重複を防ぐのに役立ち、インデックス名の形式を統一できる利点がありますが、既存のインデックス名との整合性を保つためには注意が必要です。
私個人としてはモデルに記載した設定を素直に反映しインデックス名は任意の値にしたかったので、この2つのメソッドを扱うのは少し苦労しました。
Searchkick::Index#all_indices
はすべてのインデックスを取得しない
Searchkick::Index#all_indices
は、モデルに関連するすべてのインデックス名の配列を取得する便利なメソッドのように見えます。しかし特定の正規表現パターン( /\A#{Regexp.escape(name)}_\d{14,17}\z/
)にマッチするインデックス名のみを取得します。
この正規表現パターンは、Searchkick::Index#create_index
で作成したインデックス名に適用されますが、Elasticsearch Railsから移行する際には、この命名規則に従っていないインデックスが存在する可能性があるため使用には注意が必要です。
またSearchkick::Index#full_reindex
、Searchkick::Index#clean_indices
も内部で all_indices
を使用しているため、この形式のインデックスにしか対応していない点に留意してください。
Searchkickに用意されてある reindex
メソッドはReindexAPIとは別物
Searchkickには reindex
という名前のメソッドがいくつかあります。名前からしてElasticsearchの ReindexAPI を彷彿とさせますが、ReindexAPIを内部で使用していることもなく、処理の内容も全く異なります。
特にREADMEにもある Product.reindex
のようなSearchkick::Model.reindex
を使う際には注意が必要です。内部で Searchkick::Index#reindex
に処理を委託していますが、このメソッドはモデルに関連するインデックスを一度すべて削除する処理が含まれます。消す必要のないインデックスを削除してしまったり処理コストが増大する恐れがあるため、使用の際にはコードをよく確認することをおすすめします。
ちなみに Searchkick::Index#reindex
には以下のようなコメントがあるので、アプリケーションでの使用は避けた方が良いかもしれません。
# reindex # note: this is designed to be used internally # so it does not check object matches index class def reindex(object, method_name: nil, full: false, **options)
Searchkickの魅力的な点
ここまではSearchkickの注意点を挙げてきましたが、Searchkickは魅力的なところも沢山あります。私が感じた魅力を一部取り上げてみました。
メンテナンスが頻繁に行われている
SearchkickのCommitsを見ると、継続的にメンテナンスされていることが確認できます。今年に入ってから新バージョンのリリースはありませんが、継続的にコミットされているため安心感があります。
ライブラリのメンテナンス状況は使用するか否かにおいて非常に重要な判断基準となります。その点で、頻繁にメンテナンスが行われている点は大きいです。
Elasticsearch RailsはElastic社のOSSであるためそこの安心感はありますが、長い間メンテナンスされていなかったことが大きな不安要素でした。Elasticsearch8対応を機に、引き続きメンテナンスが行われるかは気になるところです。
便利なインターフェースが用意されている
例えばSearchkickが提供するインターフェースの一つに、Searchkick::Index#promote
があります。これはエイリアスの貼り替えを行ってくれるメソッドで、インデックスを複数運用するにあたってとても有り難いです。
また、Searchkickでは Searckick::Index#bulk_index
、 Searckick::Index#bulk_update
、 Searckick::Index#bulk_delete
など、Elasticsearchの Bulk API を利用しやすくなっています。こちらも頻繁に使用しております。
他にも多数の便利なメソッドが用意されており、SearchkickはRailsから検索エンジンを非常に扱いやすくしてくれています。また、様々な機能開発リクエストが起票されており、今後もさらに使い勝手が良くなることが期待されます。
ライブラリを使用する際、自前実装を避けてライブラリに依存する方が効率的なことが多いです。その点で多様なインターフェースを提供してくれるSearchkickには非常に助かっております。
おわりに
今回はSearchkick移行時の注意点を中心に書きましたが、Searchkickが劣っている、または優れているという話ではなく、Elasticsearch Railsとは異なることを伝えられていたら幸いです。個人的な感想としては、Searchkickはシンプルで使いやすいと感じております。 Searchkickの使用を検討している方は、ぜひ一度コードを読んで見てください。非常に読みやすくコード量も少ないため、Gemを読む練習としても最適です。
この記事が、Elasticsearch RailsからSearchkickへの移行を検討している方や、Searchkickの使用を考えている方にとって参考になれば幸いです。