フリーキーズ | 独学プログラミング

さくっと全文検索を導入できるAlgoliaをNext.js(SSG)で使う

最終更新日
【画像】さくっと全文検索を導入できるAlgoliaをNext.js(SSG)で使う

少し前に、全文検索システムのFessの導入を試みましたが、CPU消費量がエグかったため断念しました。
低コストで全文検索を導入するという目論見があるため、たとえサービス自体がOSSであっても、インフラを考慮すると労力含めよろしくないといった判断です。

日本語全文検索を導入したいのでFessに入門してNext.jsで使ってみた

そこで、今回は逆に料金が高いAlgoliaを導入することにしました。導入コストや運用コストはFessやElasticsearchよりもはるかに低いですが、単純にレコード数が増えると料金が高いというのがAlgoliaの特徴です。
翻って言えば、**「レコード数が少なければ低コスト」**と言えるでしょう。

Algoliaとは

ドキュメントの全文検索だけでなく、ECサイトや動画配信サイトなどのコンテンツを持つサービス向けの検索機能を提供するSaaSです。
高速なレスポンスとAPI接続のシンプルさが売りです。また、AIを活用したNeuralSearchや、レコメンドエンジンも提供しているため、ワンストップな検索体験を統合的にサービスに付け加えられます。

オンプレミス環境やセルフホスト(自前のサーバーに設置すること)には対応していないことを明言しているため、あくまでもSaaSとして利用することになります。

Algoliaの料金体系

2023年9月現在、Algoliaの料金体系は以下となっています。
Growの上にPremium、Elevateがありますが、コストは要問い合わせとなっているため省略します。

BasicGrow
無料1,000検索リクエスト毎に$0.50
キーワード検索のみ左記同
無料帯域
月間1万リクエスト
100万レコード
無料帯域
月間1万リクエスト
10万レコード
アメリカ、イギリス、西欧リージョン左記同
追加レコード不可1,000レコード毎に$0.40
分析結果保持7日間分析結果保持30日間
インデックス毎に1,000シノニムインデックス毎に10,000シノニム
アプリ毎に10インデックス迄アプリ毎に50インデックス迄
最大インデックスサイズ1GB最大インデックスサイズ100GB
最大アプリサイズ1GB最大アプリサイズ100GB
1秒毎に3クエリまでの制限制限なし
30日未使用で非活性化制限なし

デベロッパーフレンドリーかつ日本語対応

開発者にとって嬉しい他のアプリケーションとの統合やUIコンポーネント、入力補助についてもガイドラインが提供されています。
デフォルトで分析機能もついている上、アドオンでクローラーも存在しているので、インデックスやレコードを作成する手間もかなり省略できます。

また、全文検索系サービスで鬼門となる日本語対応ですが、Algoliaは言語設定で日本語が選択可能です。(UIやドキュメントは日本語対応していません)
昨今のデファクトスタンダードになりつつある日本語形態素解析のKuromojiに対応しているのも嬉しい点です。

SSGなNext.jsをAlgoliaに対応させる手順

まずはこちらからAlgoliaに登録しましょう。
登録が完了すると以下のような画面が表示されるので、作りたいインデックスの名称を決めます。(Application Nameは後で変更可能です)

最初のインデックス名登録

最初のインデックス名登録

インデックスを作ったら、レコードを投入する前に言語設定も済ませておいたほうが良いです。
SearchIndexConfigurationLanguageから、Index LanguagesQuery LanguagesからJapaneseを追加します。

日本語設定

日本語設定

レコードを追加する

Algoliaには以下の4つのレコード追加方法があります。

  • ConnectorによるBigQueryやFTP、HTTPホストファイルを参照する方法
  • JSONを手書きで書いてマニュアル追加する方法
  • JSON、CSV、TSVいずれかのファイルをアップロードする方法
  • APIリクエストによって追加する方法

今回はSSGでつくったNext.jsアプリケーションがMDXで書かれたコンテンツを保有しているため、Pythonで整形してから一括で登録してみます。

まず、pipでAlgoliaのライブラリをインストールします。CLI実行を手軽に実施するにfire、環境変数を読み込むためにpython-dotenvも一緒にインストールしておきましょう。

pip install algoliasearch fire python-dotenv

CLIで実行するためのスクリプトを書きます。

import os

import fire
from algoliasearch.search_client import SearchClient
from dotenv import load_dotenv

load_dotenv()


def algolia_save():
    client = SearchClient.create(
        os.environ["ALGOLIA_APP_ID"], os.environ["ALGOLIA_API_KEY"]
    )
    index = client.init_index("test_index")

    obj = {
        "title": "サンプルコンテンツ",
        "description": "Pythonの楽しさを伝えます!",
        "updated_at": "2023-09-11 00:00:00",
        "tags": "Python,Python3",
    }

    index.save_object(obj, {"autoGenerateObjectIDIfNotExist": True})
    return "Success!"


if __name__ == "__main__":
    fire.Fire()

AlgoliaのAPIを使うための情報は、ログイン状態でドキュメントページへ行けば表示されます。
またはSettingsAPI Keysで取得可能です。

APP IDとAPI KEY取得①

APP IDとAPI KEY取得①

APP IDとAPI KEY取得②

APP IDとAPI KEY取得②

ここで得た情報を.envに記載しましょう。

ALGOLIA_APP_ID={自分のAPP ID}
ALGOLIA_API_KEY={自分のAPI KEY}

以下のコマンドを実行します。

python app.py algolia_save

成功したら、Algoliaの管理画面で該当のIndexを見てみましょう。先ほどリクエストした内容が反映されています。

投入されたサンプルデータ

投入されたサンプルデータ

SSGのNext.jsで検索してみる

SSRであればNext.jsのAPIルーターを使ってリクエストを送るのですが、今回はSSGのためCSF(Client-Side Fetching)を使います。

Algoliaへの接続部分は公式が提供しているパッケージを使います。

npm i algoliasearch

簡単なコンポーネントを作成しましょう。UIはMantineを使っていますが、お好きなUIコンポーネントをご利用ください。

import { useState } from 'react'
import { useForm } from '@mantine/form'
import { Box, Button, TextInput } from '@mantine/core'
import algoliasearch from 'algoliasearch/lite'

interface Item {
  title: string
}

export function Search() {
  const [items, setItems] = useState([])
  const algoliaClient = algoliasearch('{AlgoliaのAPP ID}', '{AlgoliaのAPI Key}')

  const form = useForm({
    initialValues: {
      query: '',
    }
  })

  const algoliaSearch = async () => {
    const index = algoliaClient.initIndex('test_index')
    const data = await index.search(form.values.query)
    setItems(data.hits)
  }

  return (
    <Box>
      <form onSubmit={form.onSubmit(() => algoliaSearch())}>
        <TextInput
          label="キーワード"
          placeholder="キーワード"
          {...form.getInputProps('query')}
        />
        <Button type="submit">検索</Button>
      </form>
      {items.length > 0 && (
        <p>検索結果</p>
        <ul>
          {items.map((item: Item) => (
            <li key={item.objectID}>
              <p>{item.title}</p>
            </li>
          ))}
        </ul>
      )}
    </Box>
  )
}

このコンポーネントを呼び出すと、フォームに表示された際、以下のようにリストが表示されます。(UIは若干変更しています)

Algoliaからのレスポンスデータ

Algoliaからのレスポンスデータ

スタートアップや個人開発規模はAlgoliaで十分

ここまで、Algoliaを簡単に導入する方法を見てきましたが、スタートアップや個人開発で「データを大量保有していない」「検索回数も多くない」ならAlgoliaで十分でしょう。
Growプランを適用しても、10,000検索リクエストを越えた後、1,000検索リクエストごとに$0.50なため、仮に10万リクエストでも$45です。おそらく10万リクエストあるサービスであれば収益化できているのではないでしょうか。

もし検索機能に開発リソースを割けないのであれば、ぜひAlgoliaを試してみてください。
規模が大きくなったときに、コストとにらめっこしてElasticsearchなどに引っ越しを検討するのも良い手です。

関連するコンテンツ