Algoliaのドキュメントに Solutions という章があって、実装ガイド的になっておりまして、Algolia Advent Calendar 2020でもPredictive Query Suggestionsなどを紹介しましたが、今回はeコマース向けのフィルタリング機能について解説していきたいと思います。
Algoliaのeコマース向けフィルタリング機能
インターネットショッピングで、フィルタを使った絞り込みはよく使われるUXパターンですが、Algoliaのツールや機能、例えば、InstantSearchライブラリや、Indexの属性にFacetを定義したり、refinement widgetの活用、そして自然言語理解やパーソナライゼーションを活用すれば、best-in-classなフィルタリング体験を実現することができます。より良いユーザー体験の提供とフィルタリングをよりダイナミックにしていくために以下の機能を是非ご利用ください。
Auto-selected facets
ユーザーによるクエリが、ファセットの文字列を一致した場合に、検索結果を自動的にフィルタリングする
実装の方法
以下の2ステップで実装
- AlgoliaのRuleで自動的にフィルタリング: ダッシュボードもしくはAPIを使う
- 自動的にrefinementを選択するようなコードを追加する
クエリ文字列の中からファセットの値を抽出
ダッシュボードを使った設定方法
例えばマーケットプレイにおけるショップ名での絞り込みの場合は、Manual EditorのCreate Rulesで、Containsに該当のfacet(ここではshop_name)を設定する。
ファセットを選択すると自動的に {facet:shop_name}
のように文字列が補完されます。
次にConsequenceで Filter / Boost Matching Attributes を選択して、ショップ名でのフィルタリングを選択します。
必要であれば、このルールの説明を加えたり、期間を設定したり、レプリカにも設定を適用するかといったことがこちらで可能です。
Saveボタンを忘れずに。
フロントエンド側で自動的にrefinementを選択する
以下はInstantSearchを使う例ですが、上記のRuleの情報をconfigure widgetを使って簡単に取得することができるため、それを併せて画面上のrefinementも自動的に選択させます。
search.addWidgets([
// ...
configure({
explain: ['params.rules'],
}),
]);
こうしておくと、検索結果にどのショップ名が選択されたのかが含まれます。
{
"explain": {
"params": {
"rules": {
"facetFilters": ["shop_name:楽天ブックス"]
}
}
}
}
これを使って自動的に選択させるには、InstantSearchのrefinementListウィジェットの中でshop_name
で絞り込みを行うように以下のような実装をします。
search.addWidgets([
refinementList({
// ...
transformItems(items) {
const facetFilters =
(search.helper.lastResults.explain &&
search.helper.lastResults.explain.params.rules.facetFilters) ||
[];
return items.map((item) => ({
...item,
isRefined:
item.isRefined ||
facetFilters.includes(`shop_name:${item.value}`),
}));
},
}),
]);
こうすることで、入力された文字列が絞り込み用のFacetの値と一致した場合に、自動的にそれが選択されて絞り込まれているユーザー体験が構築できます。
Dynamic faces positioning
ユーザーのクエリに関連するFacetを優先的に表示する
実装方法
Facetのポジションを動的に変更するためにRulesを使います。Ruleの結果としてクライアントに返ってくる customData
というオブジェクトでFacetの順序を変更します。
クライアント側での並び替えにはカスタムウィジェットを作っていきます。
ルールの作成
ダッシュボードのルールから、今回は試しに 牛肉
と入力されたら、カテゴリーよりもショップ名が上にくるようにしたいと思います。
まずは Conditions。
続いて Consequence は Return Custom Dataを選択。これによってファセットの順番が書かれたJSONが返ります。
{
"facetPositions": [
{
"name": "categories.lvl0",
"position": 2
},
{
"name": "shop_name",
"position": 1
}
]
}
こうすることで、デフォルトでは 1. カテゴリ → 2. ショップ名 であるものが、「牛肉」とクエリに入力された場合は順序が逆になります。
フロント側でファセットの順序を変更
カスタムウィジェットを作っていきます。ここでは renderメソッドのみを使い、そこでは renderOptions
パラメーターを受け取ります。
まず、内部的に3つの変数を定義します。resultsはクエリによる検索結果、userDataはRuleのcustomDataで定義したもの、そして、facetsContainerは絞り込みフィルターのDOM要素になります。
search.addWidget({
render(renderOptions) {
const results = renderOptions.results;
const userData = results.userData;
const facetsContainer = document.querySelector("#facets-container");
ここからは、上記の変数を使ったJavaScriptのコーディングになります。
まずは、順番をデフォルトに戻してから、userDataが空かどうかをチェックして、空だったらreturnします。userDataが空ではない場合は、その中からファセットの位置に関するものを取得します。もし、空だったり、ファセットの位置が取得できなかった場合はreturnします。最後に、取得したファセットの位置に関する情報を元にDOMの内容を変更します。
//Revert to default order of facets
Array.from(facetsContainer.children).forEach((node, index) => {
node.style.order = index + 1;
});
if (!userData) return null;
//Update order of facets per query
const customFacetsData = userData.find(
(data) => data.facetPositions && Array.isArray(data.facetPositions)
);
if (!customFacetsData) return null;
customFacetsData.facetPositions.forEach((facet) => {
const element = document.getElementById(facet.name);
if (element) {
element.style.order = facet.position - 1;
}
});
});
これが動作すると、最終的には以下のようにカテゴリがショップ名よりも上ですが、「牛肉」と検索バーに入力するとショップ名が上にきます
- 検索ボックスは空: カテゴリがショップ名より上
- 検索ボックスに「牛肉」と入力: ショップ名がカテゴリより上にくる
いかがでしょうか?おそらく、Webサイトを運営されている方は、このようなやりたいことが沢山あるのではないかと思うのですが、開発工数との兼ね合いなどによって試してみることも難しかったりするのかなと思います。
Algoliaを使う場合は、Dashboardを活用すれば、クエリやファセット選択によってフロント側に柔軟にデータを返すことができ、InstantSearchを使えば、クライアント側の小さな変更でダイナミックな動作を実現できることがご理解いただけたのではないかと思います。
eコマースのフィルタリングに関しては、Recommended filtersとVisual facetsという2つの方法がまだありますので、次回は その2 として、そちらの内容をご紹介したいと思います。
コメント