Flutter x Firestoreで全件検索サービスを導入してみた（Meilisearch）

本記事は、[Flutter Advent Calendar 2023](https://qiita.com/advent-calendar/2023/flutter)の18日目の記事です。

# 概要
 - 現在開発中のアプリにFirestoreの全件検索サービスを導入しました。（Meilisearch）
 - 様々なサードパーティの中で、なぜMeilisearchを選んだのかを比較した結論を纏めます。

## 前提 
- チャット機能を開発中。
  - データはFirestoreに保存を行っており、投稿したチャットの全件検索を行う必要が出てきた。
- Firestore単体での投稿内容の検索には現状限界があり(※)、今後の拡張性を考えて外部サービスを採用。
- ひとまず導入を試みたかったので、FirebaseExtenstionsを利用。

※Firebaseの公式でもFirestoreの全件検索はサードパーティー使用が推奨されています。

https://firebase.google.com/docs/firestore/solutions/search?hl=ja&provider=elastic
> Cloud Firestore では、ネイティブ インデックスの作成やドキュメント内のテキスト フィールドの検索をサポートしていません。Cloud Firestore データの全文検索を有効にするには、専用のサードパーティの検索サービスを使用します。

各種サードパーティのサービスを自前で構築する方法もありますが、Firebase Extensionsを使うと効率化できそうだったので、今回初めてExtensionsを活用して構築しました。

また、私自身全文検索の検索アルゴリズムに深い理解がある訳でもないので、予めご了承頂きますようお願いします。
全文検索の仕組みについては以下の記事が参考になりました。

https://zenn.dev/segavvy/articles/e97fa8417a0ee3

#### FirebaseExtensionの検索サービス一覧
Firebase Extensions Hubには現状たくさんの全件検索サービスが用意されています。

https://extensions.dev/extensions?q=&category=search

![スクリーンショット 2023-12-02 20.12.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410187/5443bd4f-7cd7-236e-3840-5a2450b0e4e3.png)

## 現状使えそうな全件検索のFirebaseExtensions
現状(2023/12)6個のサービスが用意されていますが、参考文献が豊富な点や現実的に導入できそうなものを参考に以下4つのサービスを比較対象としました。
各サービスのDart Packageもありドキュメントもほとんど豊富な印象でした。

### Algolia

https://extensions.dev/extensions/algolia/firestore-algolia-search

https://pub.dev/packages/algolia

### Typesense

https://extensions.dev/extensions/typesense/firestore-typesense-search

https://pub.dev/packages/typesense

### ElasticAppSearch

https://extensions.dev/extensions/elastic/firestore-elastic-app-search

https://pub.dev/packages/elastic_app_search

### Meilisearch

https://extensions.dev/extensions/meilisearch/firestore-meilisearch

https://pub.dev/packages/meilisearch

### 私の検索サービス選定基準
1. **値段が安価**
1. **日本語に対応しているか**
1. **高可用性**
1. **導入しやすさ**


Typesenseの公式サイトにかなり詳しい上記4点の比較一覧を作成されているので、詳細はこちらを見ると恐らく分かりやすいです。

https://typesense.org/typesense-vs-algolia-vs-elasticsearch-vs-meilisearch/

### 判断した結果まとめ

| 項目 | **Algolia** | **Typesense** | **ElasticAppSearch** | **Meilisearch** |
| ----| ---- | ---- |---- |---- |
| 安価 | × | ○ | ○ | △(最低30$~) |
| 日本語対応 | ○([こちら参考](https://floclo.net/pages/cl4071kjg0392p7fp4yiysa43#%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%AB%E3%81%A1%E3%82%83%E3%82%93%E3%81%A8%E5%AF%BE%E5%BF%9C%E3%81%97%E3%81%A6%E3%81%84%E3%82%8B)) | △([こちら参考](https://nipo-plus-doc.sndbox.jp/tech/typesense/#%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%AA%E3%81%A9%E5%8D%8A%E8%A7%92%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%81%A7%E5%8C%BA%E5%88%87%E3%82%89%E3%81%AA%E3%81%84%E8%A8%80%E8%AA%9E%E3%81%AB%E5%8E%B3%E3%81%97%E3%81%84)) | △(後述) | ○ |
| 高可用性 | ○ | ○ | ○ | △ |
| 導入しやすさ | ◎ | - (未導入) | × | ○ |

## Meilisearchに決定。
全サービス一長一短の部分があるかと思いますが`Meilisearch`を採用しました。
### 導入理由
1. 導入が簡単そうだった。
1. 試したところ日本語の精度が高かった。
1. 値段が現実的に運用できそうな価格だった。
    - 最低プラン: 30`$` + 10万リクエストまで無料(超過以降は0.2$/1k req)
1. ドキュメントが豊富なのと、サポート体制が比較的整っていそうだった
    - 公式Discordにて質問対応されているなど

こちらの方の記事がMeilisearchの特徴を纏めておられて、とても分かりやすかったです。

https://qiita.com/mosuka/items/fbda479b25a7ccd7c350#meilisearch-%E3%81%A8%E3%81%AF

### 使ってみた感想
導入が簡単で日本語の精度も割と高く、これから運用していく段階ではありますが現実的に使えそうだなという印象です。
FirestoreExtensionsでMeilisearchを導入した後、Meilisearchにデータを送信し、Meilisearch標準機能のプレビューで検索結果を確認できました。

#### 挙動チェック一例
プレビュー画面に仮のテキスト文言があると仮定します。（テストなう）
![ss_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410187/8eb33ff7-f3f3-c4ff-35c2-d7648bf6cf8a.png)

完全一致ヒットします。
![ss_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410187/2cb3ec47-641d-ec89-a10c-bbcd662f3b46.png)

部分一致でもヒットしてくれます。
![ss_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410187/af37771f-2e3c-96d5-4a5e-93eee7f43ef0.png)

その他テキストでも大体は意図した形でヒットしてくれたので今の所大きな問題は出ておりません。
内部的な日本語形態素解析としては[lindera](https://github.com/lindera-morphology/lindera)が用いられているようで、こちらのおかげかもしれません。

### Meilisearchのデメリット
#### 高可用運用に少し不安
↓を見るにpro以上のプランであれば高可用性に対応されていますが、まだ包括的なサポートはできていない模様。
> Challenges
While it can handle a considerable amount of data, the open-source version of Meilisearch (self-hosted) may not be the best fit for applications requiring a distributed architecture to handle massive amounts of data across multiple nodes or clusters.Meilisearch Cloud, on the other hand, already provides scalability and high availability with its Pro and Enterprise plans.

https://blog.meilisearch.com/meilisearch-vs-elasticsearch/#:~:text=of%2050%20milliseconds.-,Challenges,scalability%20and%20high%20availability%20with%20its%20Pro%20and%20Enterprise%20plans.,-However%2C%20our%20team

ただ、k8sでのデプロイも開発チームの開発タスクとして積まれているようで今後は改善されるかもしれません。

https://roadmap.meilisearch.com/c/168-deploy-on-a-private-kubernetes

#### Tokenizer等のカスタマイズができない
日本語性能がいいので現状に不満はありませんがカスタマイズができる場所が見当たらず、恐らくElasticsearchのようにTokenizerのカスタマイズは現状厳しそうです。

## 他3サービス不採用理由
前提としてあくまでも**私が求める要件**にマッチしなかっただけで、各PJの要件次第ではどれも選択肢になりうると思います。

----
### Algolia
値段がネックで諦めました。
今年の4月から無料枠が増えたという記事も見かけましたが、それでも他サービスとの値段を改めて比較した結果、選択肢から外しました。

https://qiita.com/qrusadorz/items/74a2e0e5edd7061d8b21

https://qiita.com/Michinosuke/items/d618a297373682bf4dd5

ただ、評判を見る限りFirebaseExtensionによるAlgoriaの導入自体は比較的容易なようなので、とにかくスピードを求めているPJ等で使ってみると良いのかなと感じました。

----
### Typesense

日本語対応に不安があったため、選択肢から外しました。

今候補として挙げている検索サービスで用いられるアルゴリズムは、事前に索引（インデックス）を準備（抽出）して、その値とマッチする値を探す仕組みで検索を実現してくれています。
抽出する代表的なアルゴリズムとして **形態素解析** と **N-gram** があり、Typesenseでは**N-gram**のみ対応しているようです。
形態素解析=`単語単位`、N-gram=`文字単位`で抽出する認識で、日本語検索精度に少し不安を感じたため一旦導入はスルーとしました。

https://nipo-plus-doc.sndbox.jp/tech/typesense/#%E6%97%A5%E6%9C%AC%E8%AA%9E%E3%81%AA%E3%81%A9%E5%8D%8A%E8%A7%92%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9%E3%81%A7%E5%8C%BA%E5%88%87%E3%82%89%E3%81%AA%E3%81%84%E8%A8%80%E8%AA%9E%E3%81%AB%E5%8E%B3%E3%81%97%E3%81%84

----
### Elastic App Search

日本語検索精度をカスタマイズできなかった為、候補から外しました。
※ **Elasticsearch** の話ではないのでご注意。

https://www.elastic.co/jp/enterprise-search/search-applications

Elastic App Search詳細は以下引用させて頂きます。

https://qiita.com/yuuto_odo/items/233dc17227903dc180b2

> Elastic社のElastic Enterprise Searchというサービスの一部で、
全文検索エンジンのElasticsearchを抽象化して、アプリケーション検索用に使いやすくしたサービスです。

検索サービスといえば私自身「Elasticsearch」のイメージがあったので同類だと思っていましたが、「`Elastic App Search`」は検索用に使いやすくしたサービスのようです。

一度実際に導入を試みたのですが、私の手元の動作確認では日本語検索がイマイチ精度が高くなく、結局採用を見送りました。
例： テストというデータを「テスト」で検索しても一致しない、など。

Elastic Search Cloudの導入やFirebaseExtensionの導入自体は比較的簡単だったため少し残念でした。

#### 日本語精度の考察 （Elastic App Search）

（恐らく）`Elastic App Search`では[analyzer](https://tech-blog.rakus.co.jp/entry/20191002/elasticsearch#Analyzer%E3%81%A8%E3%81%AF)や[tokenizer](https://qiita.com/ksk1993/items/8d6b87ad1d5e26b89c3f#tokenizer)が固定されており、カスタマイズできないようです。そのデフォルト設定が日本語向けにはなっていないかもしれない？

日本語は文字の切れ目が英語と異なっており検索アルゴリズムとは相性の悪い仕組みの言語なので、形態素解析では[kuromoji_tokenizer](https://www.elastic.co/guide/en/elasticsearch/plugins/current/analysis-kuromoji-tokenizer.html)など、[kuromojiプラグイン](https://techblog.zozo.com/entry/elasticsearch-mapping-config-for-japanese-search#kuromoji%E3%83%97%E3%83%A9%E3%82%B0%E3%82%A4%E3%83%B3%E6%A9%9F%E8%83%BD)を利用することで日本語の精度がより向上します。（n-gramも組み合わせることでより向上）

調べてみた感じkuromojiプラグインも導入できる気配が無かったため、これに時間掛けるのも勿体無いと思い諦めてMeilisearchの導入を決定しました。

## まとめ
Meilisearch自体はまだ比較的新しいサービスなようで、2019年から徐々に普及されており、
![star-history-20231217.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410187/647279e7-090d-e6bd-f359-e14016e12027.png)

https://star-history.com/#meilisearch/meilisearch&Date

最近はコンソール画面にBeta機能として新機能(Analytics)が追加されていたり、
![スクリーンショット 2023-12-17 1.29.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/410187/77025db3-e313-908b-dad0-9db9a5b477ba.png)

サポート対応として公式Discordで質問ができたり、（0~2日で返事は返ってくる）

開発RoadMapが提示されていたりと、かなり活発に開発されている印象を受けました。

https://roadmap.meilisearch.com/tabs/1-under-consideration


検索サービスの導入にあまり知見が無いけども、とりあえず日本語を考慮した形でFirestoreの全件検索サービスを導入してみたい。みたいな方にはMeilisearchを候補の1つとして挙げてみると良いかもしれません。

いちユーザのまとめ記事ではありますが、導入検討時の参考になれば幸いです。