ZOZOTOWNの検索サジェスト機能改善の取り組み紹介

ogp

こんにちは。検索基盤部の倉澤です。

ZOZOTOWNには、ユーザーが検索クエリを入力した際に、入力の続きを補完したキーワードを提示するサジェスト機能があります。この機能は一般に「Query Auto Completion」と呼ばれ、素早くユーザーの検索を完了させることを目的としています。

検索基盤部では、ZOZOTOWNの商品検索だけではなくサジェスト機能の改善にも取り組んでいます。今回は近年実施したサジェスト機能の改善事例を紹介します。2年程前にまとめたサジェスト改善事例の記事も併せてご覧ください。

techblog.zozo.com

目次

改善事例を紹介する前にサジェスト機能のシステム概要を紹介します。

システム概要

システム概要をインデキシングフェーズと検索フェーズに分けて簡単に説明します。

システム概要の図

インデキシングフェーズ

インデキシングフェーズでは、サジェスト候補のキーワード生成、Elasticsearchへのインデックス生成、エイリアスの更新をするバッチジョブを定期的に実行しています。実行基盤にはGoogle Kubernetes Engineを採用し、CronJobによりバッチジョブをスケジューリングしています。

サジェスト候補となるキーワードは、ユーザーの検索クエリのログから生成しています。検索クエリのログはGoogle BigQueryに日々格納しており、インデキシングフェーズではGoogle BigQueryから過去数日分の検索ログを取得しサジェスト候補のキーワードを生成しています。

また、Google BigQueryから取得する検索クエリのログには、1つも商品が表示されなかった検索クエリ(0件ヒットクエリ)も含まれています。ユーザーに0件ヒットクエリを提示することは再検索の手間を発生させ、ユーザーの離脱に繋がってしまう可能性があります。そのため、サジェスト候補を生成する際には0件ヒットクエリを除外しています。

Elasticsearchでのクエリとドキュメントのマッチングに用いられるスコアはデフォルトでBM25をベースに計算されます。私たちはデフォルトのスコアを利用せず、過去のサジェスト候補へのクリック率やクリック後の商品購入率などを利用しスコア計算しています。

検索フェーズ

検索フェーズでは、ユーザーから入力されたクエリを受け取り、ZOZOTOWNの検索機能を提供するAPIにてElasticsearchのクエリを生成します。Elasticsearchの検索クエリでは、入力されたクエリと表示されるサジェスト候補の対応をわかりやすくするためprefix matchを用いています。Elasticsearchにリクエストを送信するとサジェスト候補のキーワードが返されます。

また、サジェスト候補クリック後の商品検索ロジックについてはZOZOTOWN検索の精度改善の取り組み紹介の記事で説明しています。

techblog.zozo.com

改善事例

ユーザーインタフェースやサジェスト候補のキーワードに対する改善例をいくつか紹介します。各事例に対する課題やアプローチ方法を簡単にまとめた表が以下になります。

カテゴリー 事例 概要 課題 アプローチ方法
ユーザーインタフェース サジェスト候補のハイライト 検索クエリに対するサジェスト候補のハイライト箇所について 各サジェスト候補を比較する際の視覚的負荷 検索クエリとサジェスト候補の差分箇所をハイライト
ユーザーインタフェース サジェスト機能の視覚的な奥行き 検索クエリ入力時のサジェスト機能の見せ方について サジェスト機能以外のコンテンツによる検索行動への影響 ページ背景を暗くし奥行きをつける事によるサジェスト機能の強調
サジェスト候補のキーワード生成 ブランド名やショップ名の表記揺れ 検索クエリとサジェスト候補のキーワード間に発生する表記揺れについて 表記揺れしたブランド名やショップ名がサジェスト候補に表示される サジェスト候補のキーワードに対する読み仮名の取得やElasticsearchのクエリ改修
サジェスト候補のキーワード生成 検索クエリの読み仮名と異なるサジェスト候補のキーワード 日本語検索クエリの読みに対して表示すべきサジェスト候補について 日本語検索クエリの読み仮名と異なるサジェスト候補のキーワードが表示される インデキシング時や検索時に適用されるnormalizerの修正

ユーザーインタフェース

検索基盤部では、Baymard Institute社が提供する検索体験のガイドラインレポートを改善方針として活用していました。

Baymard Institute社のガイドラインレポートは有償ですが、オートコンプリート機能にまつわるレポート「9 UX Best Practice Design Patterns for Autocomplete Suggestions(Only 19% Get Everything Right)」は無償で公開されているので、こちらを交えて改善例を紹介します。

サジェスト候補のハイライト

ガイドラインレポートによると、ユーザーが入力したクエリとサジェスト候補のキーワードの差分を強調することで各候補との比較が容易になり、ユーザーの視覚的な負担を低減できるとされています。

良い例と悪い例のイメージ図は以下の通りです。

ハイライト

サジェスト機能の視覚的な奥行き

ガイドラインレポートによると、ウェブサイト・アプリ内に配置されている数多くのコンテンツはユーザーがサジェスト機能へ集中する妨げになる可能性があるとされています。

そのため私たちは、他のコンテンツとの間に境界線を設けるだけではなく、ユーザーが検索窓に入力している間はページの背景を暗くし視覚的な奥行きを付けることでサジェスト機能を強調しました。

良い例と悪い例のイメージ図は以下の通りです。

視覚的奥行き

ZOZOTOWNのサジェスト機能では、以下のようにサジェスト候補のハイライトや視覚的な奥行きを持たせたユーザーインタフェースが実現されています。

ユーザーインタフェースの改善

サジェスト候補のキーワード

インデキシングするドキュメントやElasticsearchの検索クエリに対する改善例を紹介します。

ブランド名やショップ名の表記揺れ

ユーザーが入力したクエリに含まれる語とサジェスト候補のキーワードに含まれる語との間に発生する表記揺れにより、適切なサジェスト候補が取得できないという問題がありました。例えば、ユーザーが検索窓に「ゾゾタウン」と入力した場合、「ZOZOTOWN」から始まるサジェスト候補がヒットしませんでした。

この事象は特にブランドやショップに関するキーワードにおいて多く発生していたため、私たちはブランドやショップの読み仮名のデータを利用して対処しました。

サジェスト候補のキーワードの読み仮名をドキュメントの"furigana"フィールドとして追加しました。検索クエリにブランド名やショップ名の読み仮名が入力された場合、"furigana"フィールドによりドキュメントをヒットさせます。

インデキシング時にブランド名やショップ名に対する読み仮名を管理している辞書データを参照し、"furigana"フィールドへブランド名やショップ名の読み仮名を追加しています。

以下が改善後のドキュメントの一例です。"suggest_candidate"フィールドがサジェスト候補のキーワードです。

{
  "suggest_candidate": "ZOZOTOWN限定",
  "furigana": "ゾゾタウンゲンテイ" ,
  ...
}

以下が"furigana"フィールドを用いたElasticsearchの検索クエリの一部です。検索クエリ「ゾゾタウン」が上記のドキュメントへヒットするようになりました。

{
  "query": {
    "bool": {
      "should": [
        {
          "prefix": {
            "suggest_candidate": "ゾゾタウン"
          }
        },
        {
          "prefix": {
            "furigana": "ゾゾタウン"
          }
        }
      ]
    }
  }
}

検索クエリ「ゾゾタウン」を入力し「ZOZOTOWN」を含むサジェスト候補が表示されていることがわかります。

検索クエリ「ゾゾタウン」の例

冒頭で述べたようにユーザーの検索クエリのログを用いてサジェスト候補を生成しています。そのため、サジェスト候補のキーワード生成時にブランド名やショップ名の表記が揺れている問題がありました。

例えば、正式なブランド表記は「ZOZOTOWN」だがサジェスト候補のキーワードとして「zozotown」が定義されてしまうことです。

この事象はブランド名やショップ名に対する別称や読み仮名を管理している辞書によって解決しました。サジェスト候補のキーワード生成時に行っている大まかな処理内容は以下の通りです。

  1. 検索クエリをターム分割
  2. ターム毎に辞書を参照
  3. 参照したタームを正式なブランド名やショップ名に変換

検索クエリの読み仮名と異なるサジェスト候補のキーワード

ユーザーから日本語の検索クエリ、例えば「あい」が入力された場合に「Airplane」(エアプレーン)など日本語の読み仮名と異なるサジェスト候補が表示されてしまう課題がありました。日本語の場合、読み仮名にマッチするドキュメントをヒットさせるのが自然と考えたため、この課題に取り組みました。

一方、ローマ字の検索クエリ、例えば「ai」が入力された場合に「アイシャドウ」など入力されたローマ字表記と異なるサジェスト候補が表示されていました。しかし、PCからキーボードを操作する際に意図せずローマ字表記となってしまうケースが考えられたため、日本語入力のみ対応する方針を取りました。

なぜ検索クエリ「あい」に対してドキュメント「Airplane」がヒットしていたのかを説明します。

  • ドキュメント「Airplane」のインデキシング時に独自定義しているnormalizerにより最終的にローマ字変換され「ai」として登録される
  • 入力されたクエリ「あい」も最終的にローマ字変換され「ai」となる
  • 「ai」に対して「airplane」がprefix matchする

normalizerによる変換処理を模式的に表しました。

入力 正規化 ローマ字変換
検索クエリ あい あい ai
ドキュメント Airplane airplane airplane

ローマ字変換を削除することで検索クエリ「あい」はドキュメント「Airplane」にヒットしなくなります。

一方、ローマ字変換を削除すると検索クエリ「ai」に対してドキュメント「アイシャドウ」はヒットしなくなります。

そのため、サジェスト候補のキーワードの振り仮名をローマ字変換した値をドキュメントの"furigana_romaji"フィールドとして追加しました。こうすることでローマ字の検索クエリに対して、"furigana_romaji"フィールドを用いてマッチさせることができ、今まで通りドキュメントをヒットさせています。

以下が"furigana_romaji"フィールドを追加したドキュメントの一例です。

{
  "suggest_candidate": "アイシャドウ",
  "furigana": "あいしゃどう" ,
  "furigana_romaji": "aishadou",
  ...
}

以下が"furigana_romaji"フィールドを用いたElasticsearchの検索クエリの一部です。

{
  "query": {
    "bool": {
      "should": [
        {
          "prefix": {
            "suggest_candidate": "ai"
          }
        },
        {
          "prefix": {
            "furigana": "ai"
          }
        },
        {
          "prefix": {
            "furigana_romaji": "ai"
          }
        }
      ]
    }
  }
}

以下の通り、検索クエリ「ai」に対して今まで通り「アイシャドウ」が表示されています。具体的なブランド名や商品名には加工処理をしています。

検索クエリ「ai」の例

今後の展望

今回は主にユーザーインタフェースやサジェスト候補のキーワードを精度高く表示する改善例を中心に紹介しました。今後については以下のような視点でもサジェスト機能をさらに改善していきたいと考えています。

スペル修正

ユーザーから入力されたクエリにスペルミスがあった場合、ユーザーが意図したサジェスト候補は返されずユーザー側でクエリを修正する必要があります。ユーザーにより早く探している商品に辿り着いてもらうため、ユーザーの検索意図を理解し入力されたクエリにスペルミスがあった場合でも意図した結果を返すように改善していきたいと考えています。

ドキュメントの生成ロジック

冒頭で述べたように現状サジェスト候補のドキュメントは過去のユーザー検索ログから生成しておりますが、検索頻度が低いクエリにヒットするようなドキュメントは生成しておりません。より多くの検索クエリに対応できるようにサジェスト候補の生成ロジックの改善に取り組んでいきたいと考えています。

おわりに

ZOZOでは検索エンジニア・MLエンジニアを募集しています。今回紹介した検索技術に興味ある方はもちろん、幅広い分野で一緒に研究や開発を進めていけるメンバーも募集しています。

ご興味のある方は、以下のリンクからぜひご応募ください!

hrmos.co hrmos.co

カテゴリー