※この記事は現時点で Amplify の GraphQL Transformer v1 を対象としています。v2 対応については、連携に利用するライブラリのアップデート後に更新・追記を行う予定です。
最近人気を集めている高速な全文検索サービス Algolia ですが、AWS Amplify を使って簡単に連携する仕組みができていたので紹介していきます。例えば、手掛けているプロジェクトで AWS Amplify を使ったPoC/MVPアプリケーション開発をしていて、コンテンツ検索や絞り込みの機能が必要になった際、すぐに OpenSearch を取り入れるには多少負担になるといった場合におすすめできる方法です。
Algolia とは
高速・高機能かつ使いやすいダッシュボード付きの全文検索 API サービスです。従量課金のSaaS型であることからサーバーレスとの相性がよく、各種SDKとすぐに利用可能なクライアントサイドのUI部品まで用意されており、検索機能を実装する上で優れた開発者経験が得られるサービスと言えます。
実現したい機能と仕組み
Amplify バックエンドのテンプレートでお馴染みの Blog – Post – Comment スキーマを利用して検索機能を作っていきます。Post の title
というフィールドを Algolia に連携し、ブログ記事のタイトルを検索するイメージとして、検索窓から文字列の全文検索ができるようにします。
具体的には、@algolia
ディレクティブを指定した @model
タイプの DynamoDB Streams を有効化し、レコードが追加されたら Lambda Function 経由で Algolia に登録されます。 @model
名に対応するインデックスがなければ自動生成されます。
詳細は公式ドキュメントの Directives セクションにも以下のように紹介されています。
Algolia のセットアップ
Algolia のダッシュボードを開きます。アカウントがない場合は algolia.com を開いて作成しておきます。
メニューから「API Keys」という項目を選択し、ここから Application ID と Search-Only API Key, Admin API Key を確認しておきます。後ほど、フロントエンドとバックエンドにそれぞれセットして利用することになります。
Amplify プロジェクトのセットアップ
まずは新しく作成 or 既存のプロジェクトを開き、そこから Amplify CLI を利用して Amplify プロジェクトを展開します。
amplify init
※Amplify CLI を利用していない場合、こちらのドキュメントを参考にして入れておくと便利です。また、この記事ではサンプル作成のため create-next-app で作成した Next.js プロジェクトをベースにしています。
コマンドを実行するといくつか選択項目が出てきますが、利用環境に合わせて適宜指定する流れで問題ありません。作成が完了したら、引き続き GraphQL の API を追加します。本記事のサンプルで利用するスキーマのテンプレートは One-to-many relationship (e.g., “Blogs” with “Posts” and “Comments”)
を選択しました。
amplify add api
そうすると、amplify/backend/api/<PROJECT_NAME>/schema.graphql
が作成され、中身を見ると以下の形になっていることが確認できます。
type Blog @model {
id: ID!
name: String!
posts: [Post] @connection(keyName: "byBlog", fields: ["id"])
}
type Post @model @key(name: "byBlog", fields: ["blogID"]) {
id: ID!
title: String!
blogID: ID!
blog: Blog @connection(fields: ["blogID"])
comments: [Comment] @connection(keyName: "byPost", fields: ["id"])
}
type Comment @model @key(name: "byPost", fields: ["postID", "content"]) {
id: ID!
postID: ID!
post: Post @connection(fields: ["postID"])
content: String!
}
ここから、Post
の title
に対して検索インデックスを作成するよう、@algolia
ディレクティブを利用して以下のように指定します。
type Post @model @algolia(fields:{include:["title"]}) @key(name: "byBlog", fields: ["blogID"]) {
id: ID!
title: String!
blogID: ID!
blog: Blog @connection(fields: ["blogID"])
comments: [Comment] @connection(keyName: "byPost", fields: ["id"])
}
続いて、Amplify プロジェクトから定義したスキーマから Algolia 検索インデックスを作成、データ連携をしてくれるライブラリをパッケージに追加します。この記事ではその先のサンプル画面作成に必要なライブラリも合わせて記載しています。
yarn add graphql-algolia-transformer
# サンプル画面作成で利用するモジュール
yarn add \
aws-amplify \
algoliasearch \
react-instantsearch-dom \
@types/react-instantsearch-dom
transform.conf.json
に以下の設定を追加して先程追加したライブラリをインポートしておきます。
// amplify/backend/api/<API_NAME>/transform.conf.json
// VSCodeを使っていてもしファイルが見つからない場合、.vscode/settings.json にて
// file.exclude の "amplify/**/transform.conf.json" を true にすると表示される
{
// ...
"transformers": [
"graphql-algolia-transformer"
]
}
Algolia インデックス作成と連携に必要な API キーをセットします。
// /amplify/backend/api/<API_NAME>/parameters.json
// 現時点では冗長でも @model ごとにこの3つの項目をそれぞれ追加しなければならない
{
"AlgoliaProjectIdPost": "SAMPLE_PROJECT", // 連携に伴うAWSリソース及び Algolia のインデックス名に付く任意のPrefix
"AlgoliaAppIdPost": "APP_ID",
"AlgoliaApiKeyPost": "ADMIN_API_KEY",
}
ここまでで、Amplify バックエンド側のセットアップは一通り完了しました。以下コマンドを実行して変更を反映しておきます。
amplify push
ここからは、動作を確認するために簡単はフロントエンドの画面を作っていきます。以下サンプルで作成した動作確認用のコースコードを共有しておきます。
import algoliasearch from 'algoliasearch/lite'
import Amplify, { API, graphqlOperation } from 'aws-amplify';
import { InstantSearch, SearchBox, Hits } from 'react-instantsearch-dom'
import { createBlog, createPost } from '../graphql/mutations'
import awsconfig from '../aws-exports';
Amplify.configure(awsconfig);
const searchClient = algoliasearch(APP_ID, SEARCH_API_KEY)
const TestingPage = () => {
const onClickCreateBlogBtn = () => API.graphql(graphqlOperation(createBlog, {
input: { name: 'testing_blog_1' }
}))
const onClickCreatePostBtn = () => API.graphql(graphqlOperation(createPost, {
input: { blogID: '<BLOG_ID>', title: 'testing_post_1' }
}))
return (
<>
<p>Spikes Amplify features</p>
<button onClick={onClickCreateBlogBtn}>CreateBlog</button>
<button onClick={onClickCreatePostBtn}>CreatePost</button>
<div>
<InstantSearch indexName="SAMPLE_PROJECT-post-dev" searchClient={searchClient}>
<SearchBox />
<Hits />
</InstantSearch>
</div>
</>
)
}
export default TestingPage
画面の確認
まず Blog のレコードを作成し、次に testing_blog_1
という title で Post のレコードを作成します。DynamoDB の Post テーブルにはこういう形でレコードが登録されます。
その後すぐに Algolia に連携され、ダッシュボードから検索可能な形でインデックスが登録されていることが確認できます。
最後に、サンプルで作成した画面で実際に検索が動作することを確認します。title
フィールドに指定した文字列の最初の数文字を打った時点ですでに検索結果が表示されるようになります。