この記事では、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インターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More可茂IT塾ではFlutterインターンを募集しています!可茂IT塾のエンジニアの判断で、一定以上のスキルをを習得した方には有給でのインターンも受け入れています。
Read More