LiBz Tech Blog

LiBの開発者ブログ

Vue.js + Algoliaを使って、フロントエンド開発だけで検索機能を実現する

f:id:tkmiya34:20190808234517p:plain

はじめに

前回書いたvue-cli uiでVue.js開発環境を作る記事を書いたところ、同僚がそれを引き継いでvui-cli uiで立ち上げたアプリに「APIから取得したデータでユーザーの一覧を表示する」機能を追加した記事を書いてくれました。

tech.libinc.co.jp

tech.libinc.co.jp

今度はそれを更に改良して、Algoliaを使ってユーザーの全文検索機能を作ってみました。

ちなみにTOP画像がゴリラなのは、少し前までAlgoliaのことをAlgorillaと勘違いしていたからです。ウホウホ

Algoliaとは

www.algolia.com

AlgoliaはモバイルアプリやWebサービスに導入することで、全文検索エンジンが利用できるSaaSです。サービス内のコンテンツデータをAlgoliaサーバにアップロードすることで、API経由でコンテンツデータに対して全文検索を行うことが出来ます。

開発者に身近なところだと、Vue.js公式サイトのサイト内検索や、vue-cli uiでの依存パッケージの検索もAlgoliaが利用されています。

f:id:tkmiya34:20190808203830p:plainf:id:tkmiya34:20190808204155p:plain

サイト内に検索機能を提供するサービスとしてはGoogle Site Searchもありましたが、ロボットにコンテンツデータを収集させるGoogle Site Searchと違って、Algoliaは検索APIだけではなく更新系のAPIも揃っているので、動的なサイトでの検索エンジンとしても十分に機能しそうです。

また、開発者向けのドキュメントやコミュニティも活発な印象です。

メジャーな言語/フレームワーク向けのライブラリはだいたい揃っていています。

www.algolia.com

今回のブログ用のサンプルアプリも、ほとんど公式ドキュメントを見るだけで実装することが出来ました。

Algoliaの準備

アカウント登録

まずはアカウント登録からです。こちらから登録します。

氏名などを入力したら次にデータセンターを選択するのですが、ちゃんと日本にもデータセンターがあります! f:id:tkmiya34:20190808214249j:plain

www.globenewswire.com

調べてみたところ今年の5月から正式に日本展開を発表したみたいですね。検索エンジン自体が高速でもサーバ間までの物理的距離によってレスポンスが遅かったら本末転倒なので、これは嬉しいです。

全文検索機能としても日本語での検索機能を高めていくそうです。

データセンターを選択した後は、Algoliaを導入するプロジェクトの種類などアンケートに回答したら登録完了です。

Algoliaにコンテンツデータ追加

Algoliaで検索するコンテンツデータを入れてみましょう。

右メニューからindecesを選択するとガイドが表示されるので、それに沿ってindexを作成します。 今回のアプリでは前回のユーザー情報の一覧に検索機能を追加するのでindexの名前は user にします。

f:id:tkmiya34:20190808220016p:plain

これでindexは作成できましたが、まだレコードが入っていません。

レコードをインサートするには、WebGUIからマニュアル追加、ファイルアップロード、APIからの追加ができます。

実際のアプリケーションではバックエンドでコンテンツを追加したらAPIからレコードをインサートするというフローになるかと思いますが、今回は簡易的にファイルアップロードで追加します。ファイル形式にはJSON, CSV, TSVが使えるので、前回の記事でもユーザ情報の取得に使ったRandom User Generatorからユーザー情報をJSONデータで取得し、それをファイルアップロードします。 f:id:tkmiya34:20190808220346p:plain

Randam User GeneratorからJSONダウンロードするURLはこちら

https://randomuser.me/api/?inc=gender,name,picture&results=100

Random User GeneratorのJSONデータにはユーザ情報の配列だけではなく一部余計なメタデータも入っているので、そこは配列だけになるように適宜テキストファイルとして編集してください。

AlgoliaのGUIで検索してみる

コンテンツデータの追加にも成功したら準備は完了です。 検索機能はWebのindex管理画面でもGUIで試せるので、ちょっと弄ってみるといいでしょう。 f:id:tkmiya34:20190808223457p:plain

実装

では、ここからAlgoliaの検索機能を使ったVueアプリの実装に入ります。

algoliasearchをインストール

AlgoliaはJS向けのAPIクライアントを提供しています。公式ガイドが丁寧なので、基本的なインストール方法や使い方はすぐ理解できました。

npmでAPIクライアントのalgoliasearchをインストールします。

> npm install --save algoliasearch

User.vueへの実装

前回実装したUser.vueがこちら。

ページ読み込み時にRandom User Generatorからユーザーデータを取得してVueのdataに格納し、それをテンプレート内でループしてユーザ一覧を描画しています。

<template>
  <div class="user">
    <h1>This is a user page</h1>
    <v-app>
      <v-content>
        <div v-for="(user, i) in users"
          v-bind:key="i">
          <v-avatar>
            <img
              v-bind:src="user.picture.thumbnail"
              alt="John"
            >
          </v-avatar>
          <span>
            {{ user.name.first }}
          </span>
        </div>
      </v-content>
    </v-app>
  </div>
</template>

<script>
export default {
  name: 'user',
  data: function() {
    return {
      users: []
    };
  },
  created: function() {
    var self = this;
    axios.get('https://randomuser.me/api/?results=10')
      .then(function (response) {
        console.log(response);
        self.users = response.data.results;
      });
  }
}
</script>

これをユーザー情報をAlgoliaから取得するように改修していきます。

APIクライアントの実装 & 全件表示

ここではcreatedでAlgoliaのAPIクライアントを初期化し、methodsに定義した検索リクエストの処理を呼び出しています。

検索リクエスト送るコードはたったの3行です。とても簡単に検索が実装できてしまいました。

<script>
export default {
  name: 'user',
  data: function() {
    return {
      users: [],
      index: null
    };
  },
  created: function() {
    var self = this;
    var searchClient = algoliasearch(  // APIクライアントの初期化
      'APP_ID',
      'SECRET_KEY'
    )
    self.index = searchClient.initIndex('user');  // userインデックスの初期化
    this.searchUser()
  },
  methods: {
    searchUser: function () {
      var self = this;

      // ここでAlgoliaのAPIへ検索リクエストを投げています
      // searchメソッドの第一引数が検索文字列です。
      // 試しに "art" で検索してみます
      self.index.search("art", (err, { hits } = {}) => {
        // 検索結果をデータバインドしているusersに格納
        self.users = hits;
      });
    }
  }
}
</script>

ページを開いてみると、searchメソッドで指定した art が名前に入っているユーザだけが表示されていますね。

f:id:tkmiya34:20190808231317p:plain

検索フォームを実装する

  • テンプレートへの検索用テキストフィールドの追加して入力値を search_text としてデータバインドする
  • watchで search_text の中身を監視して、値が変化する毎にsearchUserメソッドを呼び出す
<template>
  <div class="user">
    <h1>This is a user page</h1>
    <v-app>
      <v-content>
        <v-form>
          <v-container grid-list-xl>
            <v-layout wrap>

              <v-flex xs12 sm6 md3>
                <v-text-field
                  label="Regular"
                  v-model='search_text'
                ></v-text-field>
              </v-flex>
            </v-layout>
          </v-container>
        </v-form>


        <div v-for="(user, i) in users"
          v-bind:key="i">
          <v-avatar>
            <img
              v-bind:src="user.picture.thumbnail"
              alt="John"
            >
          </v-avatar>
          <span>
            {{ user.name.first }}
          </span>
        </div>
      </v-content>
    </v-app>
  </div>
</template>

<script>
import algoliasearch from 'algoliasearch';

export default {
  name: 'user',
  data: function() {
    return {
      search_text: '',
      users: [],
      searchClient: algoliasearch(  // クライアント
        'APP_ID',
        'SECRET_KEY'
      ),
      index: null
    };
  },
  created: function() {
    var self = this;
    self.index = self.searchClient.initIndex('user');
    this.searchUser()
  },
  watch: {
    search_text: function () {
      this.searchUser()
    }
  },
  methods: {
    searchUser: function () {
      var self = this;
      self.index.search(self.search_text, (err, { hits } = {}) => {
        self.users = hits;
      });
    }
  }
}
</script>

これで検索用のテキストを入力すると、リアルタイムでユーザ情報が絞り込めるようになりました!

f:id:tkmiya34:20190808233850g:plain

テキスト検索だけのとてもシンプルな機能ですが、コードを書いたのはフロントエンドだけ、それもたった数十行のコードで実装できてしまいました。

終わりに

Algoliaを導入することでバックエンドでの複雑な検索クエリを実装する必要がなくなり、かつパフォーマンスネックになりやすい検索機能に最適化された外部サービスを使うことでレスポンススピードも改善しUXの向上も見込めるのではないでしょうか。

特にWebアプリやモバイルアプリでのプロトタイプ作成、サービス初期開発フェーズで導入すると開発スピードを加速させることができそうです。