開発しているWebサービスでユーザ検索機能を作ってみたときの備忘録。
Algoliaつかうとすぐできた(´ω`)
流れ
大まかな流れはこんな感じ。
- Algoliaのアカウント作成
- Algoliaのコンソールでインデックスを作成
- 検索したい初期データを登録する
- Algoliaのコンソールで検索対象のフィールドを設定
- Webサービス側で検索処理を実装
- Cloud FunctionsのFirestoreトリガーで連動処理を実装
アカウント作成やインデックスの作成とかは省略。。
ライブラリを使った検索やFirestoreとの連動部分のまとめ。
インストール
ライブラリが用意されているので、まずはインストール
$ npm install algoliasearch # TypeScriptの型定義 $ npm install -D @types/algoliasearch
検索したいデータを登録する
とりあえず、初期データを登録するためのスクリプトを用意。
実行すると、Algoliaのコンソールに反映されるので、確認してみる。
ALGOLIA_APP_IDとかは、Algoliaのコンソールの「API Key」で確認できる。
登録とかもしたい時は、Admin API Key
の方を使う。
import algoliasearch from "algoliasearch"; async function main() { const ALGOLIA_APP_ID = "..."; const ALGOLIA_API_KEY = "..."; const ALGOLIA_INDEX_NAME = "..."; // クライアントの初期化 const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY); // インデックスの取得 const index = client.initIndex(ALGOLIA_INDEX_NAME); // 検索したいデータ const users = [ { uid: "...", name: "..." }, { uid: "...", name: "..." } ]; // objectIDを設定 const data = users.map((v) => Object.assign(v, { objectID: v.uid })); // Algoliaに登録 await index.saveObjects(data); } main().then();
ガイドも用意されているので、一読しておくといい感じ。
・Importing with the API | How to | Sending and Managing Data | Guide | Algolia Documentation
注意点として、Algolia上のIDはobjectID
という名前ということ。
このフィールドがないと自動生成してくれるけど、更新時に必要なので、あらかじめ設定しておく。
FirestoreならDocumentのIDとかでもいいかも。
検索する
Algoliaのコンソールで「Indices > Configuration > Searchable attributes」に移動して、検索対象のフィールドを設定。
設定が終わったら、とりあえず、スクリプトで検索してみる。
検索だけの時は、Search-Only API Key
の方を使う。
// 検索だけならalgoliasearch/liteを使う import algoliasearch from "algoliasearch/lite"; async function main() { const ALGOLIA_APP_ID = "..."; const ALGOLIA_API_KEY = "..."; // ※ API KeyはSearchOnlyのもの!! const ALGOLIA_INDEX_NAME = "..."; // 初期化は同じ感じ const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY); const index = client.initIndex(ALGOLIA_INDEX_NAME); // 検索する const res = await index.search("検索ワード", { attributesToHighlight: [], responseFields: ["hits", "page", "hitsPerPage", "query", "nbHits", "nbPages"], }); console.info(`res=${JSON.stringify(res, null, 2)}`); } main().then();
検索に関するAPI Referenceはこのあたり。
・Search | API Reference | Algolia Documentation
あとは、検索部分をWebサービスに埋め込めばOK。
API KEYの種類を間違えないように確認が大事
FunctionsとAlgoliaを連動させる
検索ができたので、データがわかったときに連動するようにしていく。
CloudFunctionsにFirestoreのトリガーがあるので、
追加/変更/削除が発生したら、Algoliaのライブラリを呼び出すようにして連動させる。
環境変数を設定する
まずはCloudFunctionsの環境変数を設定する。
# 環境変数を設定。API_KEYはAdmin用のを使う $ firebase functions:config:set algolia.app_id="..." $ firebase functions:config:set algolia.api_key="..." $ firebase functions:config:set algolia.index_name="..." # 確認 $ firebase functions:config:get # { # "algolia": { # "app_id": "..." # "api_key": "...", # "index_name": "...", # } # }
Cloud FunctionsのFirestoreトリガーで連動処理を実装
こんな感じ。onWriteを使って、追加/変更/削除を1関数で実装してる。
import * as functions from "firebase-functions"; import algoliasearch, { SearchClient, SearchIndex } from "algoliasearch"; export default functions .runWith({ timeoutSeconds: 540, memory: "512MB" }) .firestore.document(`users/{uid}`) .onWrite(async (change, context) => { const uid = context.params.uid; const oldData = change.before.data() | undefined; const newData = change.after.data() | undefined; // Algolia Clientの初期化 const ALGOLIA_APP_ID = functions.config().algolia.app_id; const ALGOLIA_API_KEY = functions.config().algolia.api_key; const client = algoliasearch(ALGOLIA_APP_ID, ALGOLIA_API_KEY); // Algolia Indexの取得 const ALGOLIA_INDEX_NAME = functions.config().algolia.index_name; const index = this.client.initIndex(ALGOLIA_INDEX_NAME); if (!!newData) { // 追加時/更新時: objectIDを追加して保存 const data = Object.assign(newData, { objectID: uid }); await index.saveObject(data); } else if (!!oldData) { // 削除時: objectIDに設定しているUIDを指定して削除 await this.index.deleteObject(uid); } });
これでFirestoreの変更に応じて、Algoliaのインデックスを更新してくれる。
Indexの操作に関するAPI Referenceはこのあたり。
・Indexing | API Reference | Algolia Documentation
1万レコードまでは無料なので、すごく増えるものでなければ、よさげ(´ω`)