この記事では、GW中にAlgoliaを用いた検索機能を実装することがあったので、それの備忘録として、FlutterとAlgolia、firebaseを用いた検索機能の実装の仕方について紹介していきます。
Algoliaとは、全文検索('りんご'のデータの場合、'り'、'ん'、'ご'、それぞれの単語で'りんご'がヒットする)サービスをSaaSとして提供をしており、様々なプログラミング言語にも対応しているサービスです。
この記事で説明するのは以下の画像の色が付いている部分です。
この画像は、あるエンジニアの方が説明をしてくださったの時に凄く分かりやすかったのでその図を再現したものです。

flutterのアプリでAlgoliaを使用するには、3つの手順を行う必要があります。
まず、「firebaseとAlgoliaを繋げる」においては、TypeScript等を用いたFunction機能の使用とFirebaseのextension機能を用いる2通りのやり方があります。今回の記事では、Firebaseのextension機能を用いたやり方について説明していきます。
※Firebaseのextension機能を用いるには、Firebaseを従量制にする必要があり、 extension機能をインストールすると、使用の有無に関わらず使用料が発生します。
次に、「flutterアプリとAlgoliaを繋げる」においては、algoliaと言うパッケージを使用します。
firebaseとAlgoliaの接続においては、Qiitaのこちらの記事がすごく参考になりました!
この章では、こちらの記事に少し補足を加えた構成となっています。
まずはAlgoliaのサイトでアカウントを作成し、登録をします。
続いて、AlgoliaでApplicationを作っていくのですが、その前にAlgoliaには特有の階層があるのでその部分について説明をしていきます。

Algoliaを使うにはまず、Algolia内にApplicationというものを作成します。これは、Firebaseで言うプロジェクトに該当するものです。
続いて、作成したApplicationの階層の下にIndexと言うものを作成します。これは、Firebaseで言うFirestore Databaseのコレクションに該当するものです。
そのため、上の画像のようにトークアプリを例にユーザーとメッセージをそれぞれ検索したいと思った場合は、Firestoreにuserとmessageのフィールドをそれぞれ追加すると同様に、AlgoliaにもuserとmessageのIndexを追加する必要があります。
では、いよいよAlgoliaにApplicationとIndexを作成していきます。

画像のように、Applicationの名前とサブスクリプションのタイプを選びます。自分の場合は、FREEにしました。その後、右側にあるNext Step: Data Centerをクリック。そして、位置情報を選択し次の画面の右下にあるCreate Applicationを選択して作成します。
そして、Indexの作成画面に遷移するのでIndexの名前を入力して、Createボタンを押して作成します。Firestoreの複数のコレクションを検索したい場合は、そのコレクションの数に応じてIndexを作成します。
Indexが作成されたら、画面左にあるOverviewボタンを押して、API Keysを押すと以下の画像のような画面にいくので、そこでNew API Keyボタンを押してAPIキーを作成します。このAPIはこの記事内のFirebaseのExtensionをインストールの部分で使用します。

以下の空欄に記入していきます。
DescriptionはそのAPIを使う用途の説明などを書いておきます。
Indicesには作成するAPIを使うIndexを書いていきます。作成したApplication内の複数のIndexで検索を行いたい場合は、検索したいIndex名全てを入力します。
ACLにはFirebaseとどの機能を連携するかを入力します。search、addObject、deleteObjectを追加するのがおすすめです。これによって、Firestoreにデータが追加されたり削除された時にAlgoliaのデータも編集されるようになります。

これでAlgoliaの設定は完了です。
FirebaseのExtensionsでSearch with Algoliaを導入したいプロジェクトを選んでインストールします。
そして、「拡張機能のインスタンスIDを更新」「お支払いの情報と利用状況」「有効なAPIと作成済みのリソースの確認」「この拡張機能に付与されたアクセス権を確認」を確認して次へを押します。
そして、以下の空欄に記入していきます。
Collection PathはAlgoliaで検索を行いたいFirestoreのフィールド名を書いておきます。
Indexable Fields(Optional)はIndexの検索対象にするフィールドを指定します。空白なら全フィールドが対象になりますが、パフォーマンス的には指定した方が良いです。
Algolia Index Nameは、この記事のAlgoliaの設定の項目で作成したIndexの名前を指定します。
Algolia Application Idは、Algoliaの画面左にあるOverviewボタンを押して、API Keysを押すとApplication IDの部分に表示されているので、それを入力します。
Algolia API Keyは、この記事のAlgoliaの設定の項目で作成したAPI Keyを入力します。Admin API Keyを入力しないように注意してください。
Cloud Functions locationは東京を選択すれば良いと思います。

※複数のFirestoreのコレクションを検索したい場合は、それぞれのコレクション一つにつき一つ、FirebaseのextensionからSearch with Algoliaをインストールする必要があります。
extension機能がインストールした後、設定がうまく出来ていればFirestoreにデータを追加すればAlgoliaの方にも追加されるようになっているはずです。同様に削除機能も同期されているはずです。
※Firestoreのデータ編集にはAlgoliaのデータも同期されていますが、Algoliaからデータを編集した場合は、Firestoreのデータは編集されません。
データの追加&削除は同期することができたので、次はFirestoreにあるデータをAlgoliaにも反映させていきます。
まずは、Firestoreのデータを移行させる時に必要となるCredentialを持っていない方はCredentialを入手します。Firebase Consoleのプロジェクトの設定から「サービスアカウント」タブを選択します。そして、「新しい秘密鍵の生成」ボタンを押してCredentialを入手します。
次に自分のPCにnpxをインストールされていない方はnpxをインストールします。ターミナルで以下のコードを打ちます。
npm install --global npx
続いて、Firebase Extensionsの先ほどインストールしたSearch with Algoliaの拡張機能の画面に遷移し、
左のタブから「この拡張機能の動作」画面を開きます。
すると、画面下部にExecute the below command:と言う項目があって以下のコマンドが書いてあるのでそれをコピーします。
LOCATION=asia-northeast1\ ←設定時に東京を選択した場合
PROJECT_ID=元々書かれている部分のため変更しない\
ALGOLIA_APP_ID=自分のAlgoliaのApp IDを入力\
ALGOLIA_API_KEY=自分の場合、自分のAlgoliaのAdmin API Keyを入力\ ←もしかしたらAdmin API Keyは入力しない方が良いかもしれません🙇♂️
ALGOLIA_INDEX_NAME=元々書かれている部分のため変更しない\
COLLECTION_PATH=元々書かれている部分のため変更しない\
FIELDS=\ ←{ unspecified parameter }と書かれている部分は、特に指定が無ければ左のようにしておく
TRANSFORM_FUNCTION=\ ←{ unspecified parameter }と書かれている部分は、特に指定が無ければ左のようにしておく
GOOGLE_APPLICATION_CREDENTIALS=先ほど入手したCredentialが置いてあるパスに修正する\
npx firestore-algolia-search
これをターミナルに入力して実行すると、うまくいけば以下のような警告が出ます。
WARNING: The back fill process will index your entire collection which will impact your Search Operation Quota.
Please visit https://www.algolia.com/doc/faq/accounts-billing/how-algolia-count-records-and-operation/ for more details.
Do you want to continue? (y/N):
これは、Search Operation Quotaに影響を与えますがよろしいですか?と聞かれているのでyを入力することで、データの同期が再実行されます。
そして、データの同期がうまく出来ると以下のようなメッセージが出てくると思います。
{"severity":"INFO","message":"[ 'Sending rest of the Records to Algolia' ]"}
{"severity":"INFO","message":"[ 'Preparing to send 59 record(s) to Algolia.' ]"}
{"severity":"INFO","message":"[ 'Document(s) imported into Algolia' ]"}
これで、FirestoreにあったデータをAlgoliaにも同期させることができました。
FirestoreのデータをAlgoliaにも同期させることができましたので、次は実際にFlutterのアプリでAlgoliaを用いて全文検索の実装をしていきます。
FlutterアプリでAlgoliaを使うには、FlutterとAlgoliaを繋いでくれるalgoliaと言うパッケージを導入する必要があります。パッケージはこちらになります。
pubspec.yamlファイルに以下のように記述して、flutter pub getします。
dependencies:
algolia: ^1.1.1 // バージョンはその時によって変わります。
`
`
これでパッケージの導入が完了し、Flutterアプリの方でAlgoliaを使用できるようになりました。
続いて、algoliaパッケージの使い方を説明していきますが、まずはコードの全文を紹介します。
※コピペだけでは、Algoliaの指定したIndex内にあるデータを取得する所までしかできないため、自分のプロジェクトで使えるように各自でコードを追加して下さい。
lib/algolia_app_test.dart
class Application {
static final Algolia algolia = Algolia.init(
applicationId: '自分のAlgoliaのApp IDを記入',
apiKey: 'AlgoliaのOverviewのAPI Keysのところから確認出来るSearch API Keyを入力',
);
}
lib/test.dart(Algolia検索を使いたいファイルに記述)
'
'
'
// 今回の例ではTextFormFieldのonChangedに使用
TextFormField(
onChanged: (text) {
Algolia algolia = Application.algolia; // lib/algolia_app_test.dartで定義したalgoliaをtest.dartでも使えるようにしている。
AlgoliaQuery query = algolia.instance.index('Algoliaの検索したいIndex名を入力').query(text); //今回の例ではTextFormFieldに入力した文字について、指定したIndex内で検索
query = query.facetFilter('isBlock:true'); // facetFilterでは、取得したquery内に指定した値がないかフィルターを掛けることができます。
query = query.setLength(100); // queryの最大取得件数を設定
AlgoliaQuerySnapshot snap = await query.getObjects(); // 検索を実行
final hits = querySnap.hits; // 検索にヒットしたオブジェクトのリスト
for (final hit in hits) { // 検索にヒットした内容を一つずつ見たい場合などに使用
final object = hit.data; // オブジェクトの内容をMap型に変換→jsonなどを使ってUser型(例)などに変換することでユーザー検索等の機能の実装もできます
`
`
`
}
},
);
'
'
'
.facetFilterでは、取得したquery内に指定した値がないかフィルターを掛けることができます。私自身は主にboolの値を持つフィールドを指定するのが良いかなと思います。Algoliaでは全文検索ができますが、特に設定していない限り、例えばトークアプリにおいてブロックしているユーザーを検索したい場合は、trueの文字で検索をしないとブロックしているユーザーがヒットしません。
そのため.facetFilterを設定することによって、例えばユーザー名を検索したい時に「太郎」と検索すると、ユーザー名に「太郎」と言う文字を含んでいるかつ、ブロックしているユーザーを検索結果として出力されるようになります。
※注意点として、.facetFilterはAlgoliaの方で設定をしないと機能しないので、その設定を次の「Algoliaを使いこなす」の所で説明していきます。
初期設定のAlgoliaでは、Indexに登録されているデータの全てのフィールドにおいて検索が適応されます。そのため、トークアプリの場合ではユーザー名だけの検索をしたい場合でも、ユーザー名以外のフィールドで検索を掛けた文字が入っている場合は、そのデータも検索結果として出力されます。
そのため、こちらの項目では検索範囲を指定する設定を紹介していきます。
以下の画像のようにAlgoliaの左画面にある🏠の一つ下にある📍のボタンを押します。すると、画面中央部の少し上辺りに6つのタブが表示されるので、その中のConfigurationの項目をクリックします。そして、Searchable attributesを押します。

ここで、Add a Searchable Attributeを押すと、Index内に登録されているデータが所持するフィールドが表示されるはずです。そこで、検索結果を適応したいフィールドを全て選択します。これにより、検索結果を適応したい範囲を指定することができるようになります。
続いては、この記事のコードの説明の項目で触れた.facetFilterをFlutterアプリでも使えるように設定していきます。先ほど検索結果を適応する範囲を指定した画面で、Facetsタブを押します。

すると、先ほどと同様にAdd an Attributeを押すと、Index内に登録されているデータが所持するフィールドが表示されるはずです。そこで、.facetFilterを適応したいフィールドを選択します。これにより、.facetFilterをFlutterアプリで.facetFilterを使用できるようになります。
※.facetFilterを使用する時は、コード全文の所で紹介したように.facetFilter('先ほど設定したFacetsのフィールド名:指定したい値')のように使います。
query = query.facetFilter('isBlock:true'); // ←使用例
いかがでしたでしょうか?
FlutterアプリにAlgoliaの導入はFirebaseのExtension機能とalgoliaのパッケージを使用すると意外と簡単に導入することができたのではないでしょうか?
Algoliaにはこれ以外にも便利な機能が色々と用意されているようなので、是非一度試してみてください。
あまり上手くまとめられなかった部分もありますが、AlgoliaをFlutterアプリに導入しようか考えている方達の手助けに少しでもなればと思います。
分からないことや質問したいこと等が御座いましたら、お気軽にTwitterのDMにてご連絡して頂ければと思います。できる範囲での対応となりますが、お応えさせて頂きます。
TwitterでのDMはこちらです。
https://qiita.com/mogmet/items/943c0450957298f007ac#extension%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88%E3%83%BC%E3%83%AB (Algoliaの設定)
https://qiita.com/taku_kw/items/9e6367bf2ef2a9338692 (FlutterアプリでのAlgoliaの使い方)
可茂IT塾ではFlutter/Reactのインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More可茂IT塾ではFlutter/Reactのインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More