Firebase Cloud FunctionsとGoogle Cloud Vision APIで画像に自動タグ付けに続き、Firebase Realtime Databaseに保存されたドキュメントの全文検索にAlgoliaを使ってみたので、ざっくりとした手順とサンプルを紹介します。
AlgoliaはFirebase公式のドキュメントでも紹介されている全文検索SaaSで、Node.jsのSDK経由でインデックスの登録ができる為、Firebase Cloud Functionsを使ったFirebase Realtime Databaseとの連携もしやすくなっています。
また、クライアント(Web、iOS、Androidなど)のSDKも充実しているので、簡単に検索機能を実現することが出来るようです。
Firebase Cloud FunctionsとGoogle Cloud Vision APIで画像に自動タグ付けで作成した画像URLとタグ情報をAlgoliaのIndexに登録して、キーワードから画像検索を行ってみたいと思います。
前提
今回のサンプルは、Firebase CLI(v3.16.0)で作成し、TypeScriptで実装していきます。
また、今回使用するFirebaseのプロジェクトにはFirebase Cloud FunctionsとGoogle Cloud Vision APIで画像に自動タグ付けで使用したFunctionが既にデプロイされていることが前提です。
手順
Algoliaのセットアップ
まずは、Algoliaにサインアップします。
今回は、Firebaseを使っているGoogleアカウントで登録しました。
※ 後ほどCloud Functions内からAlgoliaのAPIを呼び出す際は、APIキーを使った認証を行うため同一アカウントである必要はないです
コンソールにアクセスできるようになったら、画面左側のメニューから「API Kyes」を開きます。
APIの利用に必要な情報が表示されるので、Cloud Functionで使用する次の2つを控えておきます。
- Application ID
- Admin API Key
Cloud Functionの実装
今回の実装例では、Algoliaの認証情報をFunction内にべた書きしています...雑でごめんなさい。
実際に使用する際には firebase functions:config:set
などのFirebase CLIのオプションを使って環境変数から読み込むのがよいかと思います。 (詳細: 環境の設定 -Firebase)
import * as functions from 'firebase-functions';
import * as algoliasearch from 'algoliasearch';
// Algoliaの認証情報
const ALGOLIA_APP_ID = 'XXXXXXXXXX'
const ALGOLIA_ADMIN_KEY = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx';
// 作成するIndexの名前
const ALGOLIA_INDEX_NAME = 'images';
const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_ADMIN_KEY);
export const createIndex = functions.database.ref('images/{imageId}').onCreate(event => {
const imageData = event.data.val();
// AlgoliaのIndexに保存する情報
const algoliaObject = {
objectID: event.params.imageId,
...imageData
}
// Indexを保存
const index = client.initIndex(ALGOLIA_INDEX_NAME);
return index.saveObject(algoliaObject);
});
-
Algoliaの認証情報
- Algoliaのセットアップで控えた認証情報を記述します。
-
functions.database.ref()...
- Realtime Databaseにドキュメントが追加された際にトリガーされます。今回の例では
images/
以下のドキュメントをサブスクライブしています。
- Realtime Databaseにドキュメントが追加された際にトリガーされます。今回の例では
-
AlgoliaのIndexに保存する情報
- ドキュメントのIDをobjectIDとしてAlgoliaのIndexに保存しているのは、検索結果からRealtime Databaseの単一ノードを取得可能とするためです。
-
Indexを保存
-
algoliasearch
のAPIを使ってIndexの保存を行っています。非常に完結に行うことができます。
-
package.jsonは次の通りです。
{
"name": "functions",
"scripts": {
"build": "./node_modules/.bin/tslint -p tslint.json && ./node_modules/.bin/tsc",
"serve": "npm run build && firebase serve --only functions",
"shell": "npm run build && firebase experimental:functions:shell",
"start": "npm run shell",
"deploy": "firebase deploy --only functions",
"logs": "firebase functions:log"
},
"main": "lib/index.js",
"dependencies": {
"algoliasearch": "^3.24.9",
"firebase-functions": "^0.7.1"
},
"devDependencies": {
"@types/algoliasearch": "^3.24.5",
"tslint": "^5.8.0",
"typescript": "^2.5.3"
},
"private": true
}
Cloud Functionのデプロイ
次のコマンドでFirebase CLIでFunctionをデプロイ。
$ firebase deploy --only functions
データを用意
まずは、FirebaseのコンソールからCloud Storageに直接画像をアップロードします。
今回は、ぱくたそでダウンロードした写真を30枚ほどアップロードしてみました。
アップロードが完了すると同時にDatabaseには今回保存した画像のURLとタグ情報が保存されています。
また、AlgoliaのコンソールをからIndices
を開くと、今回作成されたimages
が作成されていることがわかります。
AlgoliaのUI Demoから全文検索を試す
Algoliaには作成したIndexから全文検索をするデモを簡単に作成できるUI Demo
という機能があります。
今回は、これを使用してフロントのコーディングなしにGUIから全文検索を行ってみます。
AlgoliaのコンソールのIndices
ページから「UI DEMOS」タブを開きます。
GENERATE A UI DEMO
をクリックし、Title、Subtitleを入力し、 TemplateにInstant search & faceting
を選択します。

次の画面では、表示項目などを設定します。
今回は、次のように設定しました。

最後に「GENERATE UI & SHARE」を選択します。
作成されたデモ画面が表示され、全文検索が行えるかと思います。
まとめ
今回紹介した手順で、Realtime Databaseに保存された内容に対して全文検索が行えるようになりました。
Realtime DatabaseとAlgoliaのIndexの同期自体は、Cloud Functionひとつで実現できるため、非常にハードルが低いと感じました。
おそらく実際に利用する際には、Create時以外のRealtime DatabaseとAlgoliaのIndexの同期や、クライアント側の実装、Algoliaの詳細設定などが必要になってくるかと思います。
特に、クライアントアプリケーション側で、Algoliaから直接検索結果を取得する部分と、Realtime Databaseのデータをサブスクライブする部分の設計はよく考える必要がありそうです。