AlgoliaのAutocomplete.jsを使って複数のインデックスに対する検索結果を表示する

Algoliaをご紹介させていただく際に、お客様にデモ的にお見せして、”実装しようと思えば出来るけど、自分でやろうと思ったら面倒ですよね…”と言うような会話をすることが多いのですが、その中の一つが、我々が『Federated Search』と呼んでいる、1つの検索窓から同時に複数のインデックスにクエリを投げて、その両方をイイ感じに画面に表示する、というもの。
例えば、Twitchの場合、下記のようにカテゴリ、ライブ、チャンネル、ビデオにアクセス。
Screen Shot 2019-07-23 at 10.45.57//embedr.flickr.com/assets/client-code.js
Algoliaのドキュメントとしては、 How to Display Results from Multiple Indices with Autocomplete.js ココにまとまっていますので、是非ご覧ください。今回はこれに沿ってやっていきます。

プレーヤーとチームのデータ

今回はNBAのPlayerとTeamをそれぞれ別のインデックスとしてデータ投入します。それぞれのデータはalgoliaのGithubレポジトリ上に置いてあるものを使います
– プレーヤー: https://github.com/algolia/datasets/blob/master/basketball/nba-players.json
– チーム: https://github.com/algolia/datasets/blob/master/basketball/nba-team.json

インデックスの設定

Ruby Clientを使ってやっていきます。
– Players

require 'rubygems'
require 'algoliasearch'
Algolia.init(application_id:'xx', api_key:'xxx')
index = Algolia::Index.new('players')
index.set_settings(
  searchableAttributes: [
    'name',
    'team'
  ],
  customRanking: [
    'desc(points)'
  ]
)

– Teams

require 'rubygems'
require 'algoliasearch'
Algolia.init(application_id:'xx', api_key:'xxx')
index = Algolia::Index.new('teams')
index.set_settings(
  searchableAttributes: [
    'name',
    'location'
  ],
  customRanking: [
    'asc(score)'
  ]
)

Index作成後にDashboardで確認。
Screen Shot 2019-07-23 at 11.02.42//embedr.flickr.com/assets/client-code.js

インデックスにデータを投入

先日金沢で仲良くなった加藤さん(@PharaohKJ)がやってるPodcast(Tsundokanai Radio)でEffective Rubyの話を聴いてたら、”あー、俺、よく分かってねーで、イイ感じなノリでRuby書いてきたんだな…”とか思いながら、
Screen Shot 2019-07-23 at 11.33.43//embedr.flickr.com/assets/client-code.js
それっぽく、この2つのインデックスにGithubからダウンロードしてきたデータを投入していきます。

require 'rubygems'
require 'algoliasearch'
Algolia.init(application_id:'xx', api_key:'xxx')
players = Algolia::Index.new('players')
teams = Algolia::Index.new('teams')
[players, teams].each{|index|
  batch = JSON.parse(File.read(index.name + ".json"))
  index.add_objects(batch)
}

データが投入できたことを確認。
Screen Shot 2019-07-23 at 11.43.36//embedr.flickr.com/assets/client-code.js

HTML

必要なJavascriptおよびCSSを読み込んで、画面表示用のマークアップ。まんまコピペで。

<html>
<head>
<!-- Include stylesheet -->
<link href="app.css" rel=stylesheet />
</head>
<body>
<!-- HTML Markup -->
<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" />
</div>
<!-- Include AlgoliaSearch JS Client and autocomplete.js library -->
https://cdn.jsdelivr.net/algoliasearch/3/algoliasearch.min.js
https://cdn.jsdelivr.net/autocomplete.js/0/autocomplete.min.js
http://app.js
</body> </html>

JavaScript

Algoliaの実装としてはメインな部分ですが、非常に直感的かな、と。

const client = algoliasearch("xx", "xxx");
const players = client.initIndex('players');
const teams = client.initIndex('teams');
autocomplete('#aa-search-input', {}, [
    {
      source: autocomplete.sources.hits(players, { hitsPerPage: 3 }),
      displayKey: 'name',
      templates: {
        header: '<div class="aa-suggestions-category">Players</div>',
        suggestion({_highlightResult}) {
          return `<span>${_highlightResult.name.value}</span><span>${_highlightResult.team.value}</span>`;
        }
      }
    },
    {
      source: autocomplete.sources.hits(teams, { hitsPerPage: 3 }),
      displayKey: 'name',
      templates: {
        header: '<div class="aa-suggestions-category">Teams</div>',
        suggestion({_highlightResult}) {
          return `<span>${_highlightResult.name.value}</span><span>${_highlightResult.location.value}</span>`;
        }
      }
    }
]);

CSS

まんまコピペでw

.aa-input-container {
  display: inline-block;
  position: relative;
}
.aa-input-search {
  width: 300px;
  padding: 12px 28px 12px 12px;
  border: 1px solid #e4e4e4;
  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;
  pointer-events: none;
}
.aa-dropdown-menu {
  background-color: #fff;
  border: 1px solid rgba(228, 228, 228, 0.6);
  width: 300px;
  margin-top: 10px;
  box-sizing: border-box;
}
.aa-suggestion {
  padding: 6px 12px;
  cursor: pointer;
}
.aa-suggestions-category {
  border-bottom: 1px solid rgba(228, 228, 228, 0.6);
  border-top: 1px solid rgba(228, 228, 228, 0.6);
  padding: 6px 12px;
}
.aa-dropdown-menu > div {
  display: inline-block;
  width: 100%;
  vertical-align: top;
}
.aa-empty {
  padding: 6px 12px;
}

プレーヤーとチームを同時に表示

“r”と一文字入力しただけで↓。直感的なコーディングでサクっといういうUIが構築できるのはとても便利ですね!
Screen_Shot_2019-07-23_at_11_56_42//embedr.flickr.com/assets/client-code.js

タイトルとURLをコピーしました