ロゴテキスト ロゴ

    Nuxtに全文検索サービスAlgoliaを導入する

    Nuxtに全文検索サービスAlgoliaを導入する

    ブログやサービスを作っていると、往々にして検索機能が欲しくなる事があります。


    いざ実装しようとするとどの部分に検索をかけるか、部分一致検索にするか完全文字一致にするか…などなど意外とめんどくさい作業ですよね 😅




    そんな中、Algoliaは検索に特化したサービスです!



    検索機能を自身のサービスに簡単に実装する事が出来ますし、

    しかも色んな言語やフレームワークをサポートしています。

    Algoliaがサポートしている言語フレームワークについて

    Algolia公式ページより引用

    フロントであれば今時のReactやVue、バックエンドはRubyにPythonと幅広く対応しています!




    実際にどのようなサービスかについては公式の動画があるんですが、


    それ以上に公式サイトのWidgetページを見ると、出来る事のイメージがしやすいです。

    Widgets Showcase | Vue InstantSearch | Building Search UI | Guide | Algolia Documentation




    ここではNuxt.jsにAlgoliaを導入します。

    Nuxt ContentというNuxtでブログなどSSGを作るのに特化したライブラリ上での解説ですが、Nuxt.jsで作った場合と差異はないはず。

    検証した環境

    1 nuxt 2.14.12
    2 @nuxt/content 1.11.1

    前準備

    料金について

    料金は0円からスタート可能です

    Algoliaの料金について

    ↑の公式のPRICINGページに書かれているように1ヶ月に10,000検索(10UNIT = 10 x 1,000検索)までは無料でいけます。

    とりあえず試してみて、検索ボリュームと利便性から費用対効果を考えて判断する、というのでも良さそうです。

    アカウント登録

    アカウント登録はこのようなサービスなのでGitHubも選択出来るのは嬉しいところ!

    Algoliaのユーザ登録はGitHubも選択出来る

    名前や会社の情報を入力して作成、特に迷うところはなし。



    またアカウント作成時にクレジットカードの登録は不要です。


    気付いたら支払わないといけない、、といった心配をしなくて済むので安心ですね 😊

    Algoliaの設定

    まずAlgoliaで大きく3つの設定をします。


    1. indexの作成(検索対象1つにつき、1つのindexを作成)
    2. 検索するための元となるデータを設定
    3. 検索対象のリストを作成(重み付けも合わせて)

    1. indexの作成

    検索する対象に対して1つのindexを作成します。

    To handle indices across multiple environments, just prefix/suffix your index name like dev_NAME, test_NAME, or prod_NAME

    複数の環境でインデックスを処理するには、dev_NAME、test_NAME、prod_NAMEなどのインデックス名のプレフィックス/サフィックスを付けるだけです(Google翻訳)

    prefix/suffixで環境を自動判別してくれる、また環境毎に1つのindexが必要

    と作成時に表示されるので、

    • dev_prod_のようにprefix/suffixをつければ自動的に開発用、本番用といった差異を自動判別してくれる
    • 開発用、本番用など環境毎に違うデータを試したい場合は違うindexを作る必要がある

    という事が分かります。

    2. 検索するための元となるデータを設定

    検索するためのデータを追加します。


    追加方法は

    1. API経由でAlgoliaにアップロード
    2. JSONファイルをローカルで作成してAlgoliaにアップロード
    3. Algolia上で入力

    の3つ。



    私の場合ブログのため、

    masterマージされたのをフック → CIでAPIを叩いて検索用のJSONをAlgoliaに自動アップロード

    というのが最終目標ですが、今は簡単に検索を試したいので検索用のファイルをアップロードします。

    testData.json
    [
      {
        "title": "reset.cssをNuxt.jsに導入する",
        "body": "reset.cssをNuxt.jsのプロジェクトに導入する方法を書きます",
        "tags": ["Nuxt.js", "reset.css"]
      },
      {
        "title": "Nuxt.jsで必要なFont Awesomeだけをimportする",
        "body": "Nuxt.jsでFont Awesomeを使用する際に使われる nuxt-fontawesome パッケージ。",
        "tags": ["Nuxt.js"]
      },
      {
        "title": "VueでのCSS Modulesの書き方",
        "body": ""
      },
      {
        "title": "Reset.cssをNext.jsに導入する",
        "body": "Reset.cssをNext.jsに導入します、ここでは2つのやり方をご紹介します。",
        "tags": ["Next.js", "reset.css"]
      }
    ]

    自分のブログの記事データをいくつか適当に、そこに対してタグを設定した状態で上げてみました。



    なおここでのアップロードはJSON以外にも、CSV, TSVが対応しています。

    JSON以外にもCSV,TSVに対応している

    3. 検索対象のリストを作成(重み付けも合わせて)

    検索対象とする属性を設定します。

    また、どの属性を優先的に検索対象とするかを設定します。

    検索対象とする属性と優先度を設定する

    例えば↑の画像の場合、

    body を検索対象から外し、優先度はtagsの方がtitleよりも高い、という設定になります。

    Nuxt.jsへの実装

    公式にVueを実装するやり方があるためそちらを参考にします

    https://www.algolia.com/doc/guides/building-search-ui/getting-started/vue/

    必要な値を取得する

    必要な値は3つ。

    • index名
    • Application ID
    • Search-Only API Key

    index名は、Algolia作成時に付けたもの。

    Application IDSearch-Only API KeyはAogoriaのAPI Keysページに載っています。

    AlgoliaのAPI KEYページ

    これらの値は実装時に使用します。

    ライブラリのインストールとNuxtの設定

    検索に必要なのはalgoliasearch

    UIを簡単に実装するのにvue-instantsearchinstantsearch.cssの2つを使います。

    $ yarn add vue-instantsearch algoliasearch instantsearch.css

    pluginsの作成

    Vue.use()を使う必要があるためpluginsを使います。

    私のプロジェクトではTypeScriptを使っているので.tsで作成、またvue-instantsearchがTypeScript未対応のため、ひとまず@ts-ignoreで回避。

    ~/plugins/Algolia.ts
    import Vue from 'vue'
    // @ts-ignore
    import InstantSearch from 'vue-instantsearch'
     
    Vue.use(InstantSearch)


    作成したプラグインをnuxt.config.jsで設定。

    mode: 'client' を使用しないとエラーが起きてしまうので設定しています。

    nuxt.config.js
    export default {
      plugins: [{ src: '~/plugins/Algolia.ts', mode: 'client' }],
    }

    コンポーネントを作成

    検索をするためのコンポーネントを作ります。

    ここで先ほどの index名Application IDSearch-Only API Keyを使用します。

    search/index.vue
    <template>
      <ais-instant-search :search-client="searchClient" index-name="<index名>">
        <ais-search-box />
        <ais-hits>
          <div slot="item" slot-scope="{ item }">
            <div>{{ item }}</div>
          </div>
        </ais-hits>
      </ais-instant-search>
    </template>
     
    <script>
    import algoliasearch from 'algoliasearch/lite'
    import 'instantsearch.css/themes/algolia-min.css'
     
    export default {
      data() {
        return {
          searchClient: algoliasearch('<Application ID>', '<Search-Only API Key>'),
        }
      },
    }
    </script>


    そして上記コンポーネントを使用するページでimportして呼び出します

    <template>
      <div>
        <search />
        ・・・
      </div>
    </template>
     
    <script>
    import Search from '~/components/organisms/search/index.vue'
     
    export default {
      components: { Search }
      ・・・
    }
    </script>

    Algoliaの検索が出来るようになった

    検索が出来るようになりました!



    ハイライト表示する

    検索結果は以下のコードの部分です

    <ais-hits>
      <div slot="item" slot-scope="{ item }">
        <div>{{ item }}</div>
      </div>
    </ais-hits>


    item は検索結果の1つになります。

    itemが該当する箇所


    ↑は「nux」というワードで調べた時の結果。


    _highlightResult.title.valueなどに検索結果があるのが分かります。

    そのため、先ほどのコードを以下のように書き換えてみると

    search/index.vue
    <template>
      <ais-instant-search :search-client="searchClient" index-name="TECH-BROCCOLI">
        <ais-search-box />
        <ais-hits>
          <div slot="item" slot-scope="{ item }">
            <div v-html="item._highlightResult.title.value" />
            <div v-html="item._highlightResult.body.value" />
          </div>
        </ais-hits>
      </ais-instant-search>
    </template>


    検索結果にハイライトしながら表示出来るようになりました!


    検索結果にハイライトを効かせながら表示する

    課題

    Nuxt.jsで実装時の課題としてCSR/SSRのDOMの違いに関するwarningメッセージがコンソールに表示されます。

    SSRとCSRでの違いがwarningとして表示される


    プラグインでUI実装のためのvue-instantsearchを使ったのが良くなかったかな… 🤔


    今回はAlgoliaの検索が出来る事を簡単に確認したかったので、 vue-instantsearchinstantsearch.cssを使いましたが、 次はこれらを使わずに実装してみたいと思います!

    プロフィールの背景画像 プロフィール画像
    Yuki Takara
    都内でフリーランスのエンジニアをやってます。フロントとアプリ開発メインに幅広くやってます。