algoliaとは

Products to accelerate search and discovery experiences across any device and platform.

algoliaとは全文検索エンジンサービスです。「algoliaサーバにブログやドキュメントなどのコンテンツデータをアップすると、そのデータを全文検索するAPIを利用できる」といった感じのものです。

例を挙げると、Vue, React, Webpack, babel などの公式ドキュメントにある検索機能が、algoliaのDocSearchという機能によって実現されています。

今回は、このalgoliaを使ってブログに全文検索を実装した方法をまとめてみます。

手順

  1. algoliaのフリーアカウントを取得する
  2. jekyll-algoliaを使い、ブログコンテンツをalgoliaサーバにアップする
  3. autocomplete.jsを使い検索窓を実装する

1. algoliaのフリーアカウントを取得する

サービスを利用するためにフリーアカウントを作成します。

dashboard ダッシュボード画面のサンプル

アカウントを作成するとコンテンツをアップロードでき、そのデータに対してAPI経由で全文検索できるようになります。algoliaが提供している機能は基本的にここまでで、検索窓や検索結果の表示などのUIは別途用意する必要があります。

ただ「ドキュメント」に全文検索を導入する場合は、検索窓などのWidgetがセットになったDocSearchという機能を使うことができます。
ちなみにこれを利用するには審査が必要です。私は当初「algolia = DocSearch」だと思い込んでいたのでDocSearchの登録申請を出しましたが、審査で「これはドキュメントじゃなくてブログよね?」とツッコミいただき、通常のalgoliaアカウントを作成するよう助言いただきました…。

2. jekyll-algoliaを使い、ブログコンテンツをalgoliaにアップする

algoliaにコンテンツをアップする方法はいろいろあります。その中のひとつがjekyll-algoliaです。

おさらいすると、Jekyllは「markdown等で書かれたコンテンツデータから静的サイトを生成する」ものです。対してjekyll-algoliaは「markdown等で書かれたコンテンツデータから静的サイトを生成し、生成したコンテンツをalgoliaにアップする」ものです。要はアップロードを手助けしてくれるプラグインですね。

このjekyll-algoliaを導入していきます。

Environment

  • Jekyll >= 3.6.0
  • Ruby >= 2.3.0

Installation

Gemfileにプラグインを追加し、インストールします。

source 'https://rubygems.org'

gem 'jekyll', '~> 3.6'

group :jekyll_plugins do
  gem 'jekyll-algolia'
end
$ bundle install

Configuration

algoliaアカウントを作成後、ダッシュボードの「API Keys」にてApplication IDを確認し、_config.ymlに設定を既述します。


algolia:
  application_id: your_application_id
  index_name: mf_code # indexingする対象の名前をここで決めます。

私はブログを生成するための設定とAlgoliaにアップするための設定を一部変えたかったので、_config.algolia.ymlと別ファイルにしました。

Usage

ダッシュボードの「API Keys」からAdmin API Keysを確認し、実行時に渡します。

$ ALGOLIA_API_KEY='your_admin_api_key' bundle exec jekyll algolia

読み込む設定ファイルを変更するには--configオプションを使います。

$ ALGOLIA_API_KEY='your_admin_api_key' bundle exec jekyll algolia --config ./_config.algolia.yml

execute demo Getting startedより

Advanced

毎回手動で実行するのは面倒なので、CIで実行するようにします。
ただalgoliaのフリーアカウントでは1ヶ月のアップロード回数に限度があるので、むやみにアップロードするのは避けたいところ。記事コンテンツが修正された時だけアップロードするようにしてみます。具体的には「前回のCI実行時のリビジョンと比較し_posts以下に差分がある場合」にアップロードします。

そのために必要なことは以下のとおりです。

  • CIの環境変数にAdmin API Keyを登録する
  • jekyll-algoliaを実行するスクリプトを実装する
    • CIの過去の実行結果を取得し、そのトリガーとなったCommit Idを取得する
    • 現在のCI実行のトリガーとなったCommit Idを取得する
    • それらのCommit Idのdiffを取得し、_posts以下の差分の有無を確認する
    • _posts以下に差分がある場合はjekyll-algoliaを実行する

スクリプトはindexing.sh - aloerina01.github.ioに実装していますので、よければ参考にどうぞ(shell力の低い実装ですが…)。

3. autocomplete.jsを使い検索窓を実装する

algoliaを使ってインクリメンタルサーチを実現できるライブラリがautocomplete.jsです。これはJekyllとは関係ないもので様々な環境に適用することができます。公式ドキュメントも手厚く、バックエンドはphp, ruby, JavaScript, python, C# に対応しており、フロントエンドはvanillaなJavaScript, Angular, jQuery 用のサンプルコードが用意されています。
このブログではvanillaJSでの利用方法にのっとりJSとCSSを読み込み、任意の箇所にDOMを追加しています。

HTML

<div class="aa-input-container" id="aa-input-container">
    <input type="search" id="aa-search-input" class="aa-input-search" placeholder="Search for players or teams..." name="search" autocomplete="off" />
    <svg class="aa-input-icon" viewBox="654 -372 1664 1664">
        <path d="M1806,332c0-123.3-43.8-228.8-131.5-316.5C1586.8-72.2,1481.3-116,1358-116s-228.8,43.8-316.5,131.5  C953.8,103.2,910,208.7,910,332s43.8,228.8,131.5,316.5C1129.2,736.2,1234.7,780,1358,780s228.8-43.8,316.5-131.5  C1762.2,560.8,1806,455.3,1806,332z M2318,1164c0,34.7-12.7,64.7-38,90s-55.3,38-90,38c-36,0-66-12.7-90-38l-343-342  c-119.3,82.7-252.3,124-399,124c-95.3,0-186.5-18.5-273.5-55.5s-162-87-225-150s-113-138-150-225S654,427.3,654,332  s18.5-186.5,55.5-273.5s87-162,150-225s138-113,225-150S1262.7-372,1358-372s186.5,18.5,273.5,55.5s162,87,225,150s113,138,150,225  S2062,236.7,2062,332c0,146.7-41.3,279.7-124,399l343,343C2305.7,1098.7,2318,1128.7,2318,1164z" />
    </svg>
</div>

<!-- 中略 -->

<script src="https://cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js"></script>
<script src="https://cdn.jsdelivr.net/autocomplete.js/0/autocomplete.min.js"></script>

JavaScript

const client = algoliasearch('YourApplicationID', 'YourSearchOnlyAPIKey');
const index = client.initIndex('YourIndex');
//initialize autocomplete on search input (ID selector must match)
autocomplete(
  '#aa-search-input',
  { hint: false },
  {
    source: autocomplete.sources.hits(index, {hitsPerPage: 5}),
    //value to be displayed in input control after user's suggestion selection
    displayKey: 'name',
    //hash of templates used when rendering dataset
    templates: {
      //'suggestion' templating function used to render a single suggestion
      suggestion: (suggestion) => return `<span>${suggestion._highlightResult.title.value}</span>`;
    }
  }
);

suggestion._highlightResultに検索結果が入ってきます。プロパティのtitleは自分がアップロードしたコンテンツが持つプロパティで、algoliaダッシュボードで確認できます。何をヒットさせるか、どんな優先度でヒットさせるか等をダッシュボードから変更することができます。

CSS

.aa-input-container {
  display: inline-block;
  position: relative;
}
.aa-input-search {
  width: 300px;
  border: 1px solid rgba(228, 228, 228, 0.6);
  padding: 12px 28px 12px 12px;
  box-sizing: border-box;
  -webkit-appearance: none;
  -moz-appearance: none;
  appearance: none; 
}
.aa-input-search::-webkit-search-decoration, .aa-input-search::-webkit-search-cancel-button, .aa-input-search::-webkit-search-results-button, .aa-input-search::-webkit-search-results-decoration {
  display: none;
}
.aa-input-icon {
  height: 16px;
  width: 16px;
  position: absolute;
  top: 50%;
  right: 16px;
  -webkit-transform: translateY(-50%);
          transform: translateY(-50%);
  fill: #e4e4e4;
}
.aa-dropdown-menu {
  background-color: #fff;
  border: 1px solid rgba(228, 228, 228, 0.6);
  min-width: 300px;
  margin-top: 10px;
  box-sizing: border-box;
}
.aa-suggestion {
  padding: 12px;
  cursor: pointer;
}
.aa-suggestion + .aa-suggestion {
    border-top: 1px solid rgba(228, 228, 228, 0.6);
}
.aa-suggestion:hover, .aa-suggestion.aa-cursor {
  background-color: rgba(241, 241, 241, 0.35); 
}

インクリメンタルサーチWidgetのシンプルなCSSです。実際にはこのCSSをカスタマイズして利用しています。

感想

algoliaはドキュメントがけっこうしっかり書かれている印象でした。機能が豊富なこととドキュメントがしっかりしてることで、かえって自分に最適な情報を探すのに苦労しましたが、見つけてしまえばアップロードまではすぐできました。

また、DocSearchの印象が強く「インクリメンタルな検索Widgetまでセットになったもの」を求めていたので、autocomplete.jsを見つけるまではいろいろな情報に振り回されました。jekyll-algoliaの公式ドキュメントではUIの実装にInstantSearch.jsを使うよう案内していて、情報迷路にハマりました…(ちなみにInstantSearch.jsは、簡単な検索窓だけでなく、検索結果によって画面全体が更新されるなどのリッチなコンテンツを実装するためのライブラリのようでした)。

とは言え、algoliaもautocomplete.jsも理解してしまえば不自由なく使える便利なものでした。日本語の情報が少なかったので、この記事が少しでも役に立てれば幸いです。