👷‍♂️

日本語対応の全文検索エンジンMeilisearchをRuby on Railsから利用する

2023/06/14に公開

はじめにまとめ

  • meilisearch-rails gem があり、簡単に導入できる
  • インデックス対象を柔軟に設定できる
  • KaminariやPegy対応で他の検索方法との切り替えも簡単
  • 日本語での検索精度は正直用途を選びそう(v1.2)
    • マッチしてほしいものがマッチせず、マッチしてほしくないものがマッチしないことも

Meilisearch

https://www.meilisearch.com/

  • 全文検索エンジン
  • プログラムからはRESTful APIでアクセスして使う
  • Typo tolerance(タイプミス耐性)に自信
  • 多言語サポートに力を入れている
  • 起動してすぐ使える手軽さ
  • とにかく簡単に使えること
  • セルフホスト可能なOSS

とにかく簡単であることを哲学としている、らしい。

https://zenn.dev/topics/meilisearch

今回作成したサンプルプロジェクト

https://github.com/takeyuweb/meilisearch-rails-render-sample

郵便番号検索してみた

meilisearch-rails

公式のgemがある。
https://github.com/meilisearch/meilisearch-rails

導入は Getting startedの通りに進めればよい。

実際にLIKE句での検索からMeilisearchに置き換えたコミットがこちら
https://github.com/takeyuweb/meilisearch-rails-render-sample/commit/e2104d000fbe61b5a45fc26fe725cde3a2f405ca

config/initializer/meilisearch.rb

Meilisearchへのインデックス登録や検索は RESTful API経由で行う。
APIのアクセスに必要なURLとキーを指定してやる。
今回は Docker Compose で起動したMeilisearchコンテナに接続する設定を行った。HTTP 7700番ポートはMeilisearchデフォルト。masterKeyもコンテナ起動時に指定したキー文字列。

MeiliSearch::Rails.configuration = {
  meilisearch_url: ENV.fetch('MEILISEARCH_URL') { 'http://meilisearch:7700' },
  meilisearch_api_key: ENV.fetch('MEILISEARCH_API_KEY') { 'masterKey' },
}

config/initializer/pegy.rb

今回ページネーションにはpegy gemを使っているが、pegyには Meilisearch 用の拡張が存在するのでそれを使うよう指定する。

require 'pagy/extras/meilisearch'  # 追加

ActiveRecordモデル

MeiliSearch::Rails モジュールをインクルードすることで、 Meilisearchのインデックス設定用のDSLが利用できるようになる。
どの属性の文字列をインデックスに含めるか?検索動作のカスタマイズのためのインデックス設定をどうするか?といった設定が可能になる。

今回は Pagy の Meilisearch 用の拡張を使っているので、モデルに extend Pagy::Meilisearch も追加している。

https://github.com/takeyuweb/meilisearch-rails-render-sample/blob/56881a5b6862e1d5bf8f9f0d4abea6f7dc689c42/app/models/zipcode.rb#L3-L42

ActionController

モデルに追加した include MeiliSearch::Rails により、 #search メソッドで検索できる。簡単。

Zipcode.search('宮町 おおみや') # => [#<Zipcode>, #<Zipcode>, ...]

今回は Pagy の Meilisearch 用の拡張を使っているので、次のようにする。

https://github.com/takeyuweb/meilisearch-rails-render-sample/blob/56881a5b6862e1d5bf8f9f0d4abea6f7dc689c42/app/controllers/zipcodes_controller.rb#L7-L8

pagy_meilisearch の戻り値はpagyおなじみのもので、バックエンドがMeilisearchかどうかに依らず、置き換えは容易。
ビューではこのように使用する。

https://github.com/takeyuweb/meilisearch-rails-render-sample/blob/56881a5b6862e1d5bf8f9f0d4abea6f7dc689c42/app/views/zipcodes/index.html.erb#L9-L28

インデックスの再構築

後からMeilisearchを導入した場合や、何らかの理由で不整合が生じたときなどインデックスを再構築したくなることがある。

Zipcode.clear_index!
Zipcode.reindex!
Zipcode.some_scope.reindex!  # 一部のみもかんたん

検索プレビューUI

(Railsとは関係なく、Meilisearchの機能として)サーバーのURLにブラウザでアクセスすると検索プレビューUIが利用できる。
すぐ使える検索プレビュー

なお、起動モードを production にすると無効になる。

https://www.meilisearch.com/docs/learn/getting_started/search_preview

まとめ

  • Railsバックエンドで検索する場合、Meilisearchの特徴の高速さは活かせないが、簡単に統合できるのは素晴らしいと感じた
    • Dockerでポンと立てて、ほんの少しの設定ですぐ使えるのは本当に良い
    • MeilisearchはREST APIサーバなので、検索はフロントエンドから直接行う設計がよさそう
  • 実際に検索してみると、特に人名や住所などでは期待した応答が得られないと感じることが多い
    • すくなくとも完全な結果を期待する用途には無理
      • 受託案件で導入してお客に「これなんで検索しても出ないの?」と突っ込まれるととても苦しい
      • フワっとしたキーワードでそれらしい回答が得られれば良い用途なら使えそう

でも体験良い利用例もある

うちでも案件でお世話になっているWebRTC SFU Sora のドキュメントの検索体験がとても良いが、これはMeilisearchらしい。良い。
https://voluntas.medium.com/オンラインドキュメントと日本語全文検索-30cc38d7b1c3

Typo tolerance はあっても誤変換は無理

仕方ない

なおタイプミスには強くても誤変換には弱い模様で、ひらがなカタカナの違いや漢字の変換ミスでヒットしなくなってしまいました。
https://gigazine.net/news/20230430-meilisearch-search-engine/

タケユー・ウェブ株式会社

Discussion