Blog

AWS Amplify を使って簡単に Algolia と連携した検索機能を作る

※この記事は現時点で 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!
}

ここから、Posttitle に対して検索インデックスを作成するよう、@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 フィールドに指定した文字列の最初の数文字を打った時点ですでに検索結果が表示されるようになります。

おわりに

いくつか細かい設定を必要とするため多少手間に感じることもあるかと思いますが、実際にやってみると多くの時間をかけることなく検索機能を実現できる方法となります。標準の OpenSearch を利用することも有効な選択肢ではありますが、Algolia を利用することで監視項目や管理対象のAWSリソースを減らし、従量課金のメリットを享受できるため、一度検討してみてはいかがでしょうか。

オンライン無料相談

サーバーレスの悩み事、お気軽にご相談ください

サーバーレスオペレーションズの担当者がオンラインで皆さんのサーバーレスに関するご相談やお問い合わせに無料でお答えいたします。 カレンダー (Calendly) からお好きな日程をブッキングしていたくだけで、お申込みいただけます。

こんなお悩みや課題を
抱えていませんか?

  • サーバーレスでやりたいことがあるが
    何から始めていいかわからない
  • サーバーレスのアーキテクチャレビューをしてほしい
  • サーバーレスで進めようとしているが
    適しているのかわからない
  • クラウド技術習得やこれからのキャリアに迷っている
  • 社内でサーバーレスを広めたいがブロッカーがある
  • 新卒エンジニアだがサーバーレスの勉強を
    どうしたらいいのかわからない