
こんにちは! 検索開発のグループ長をしている牧野です。
今期、レストラン検索ではフリーワード検索の精度改善を大きな目標にして取り組みました。 今回はその過程で得られたナレッジ、特に「検索結果の分析手法」についてシェアしたいと思います。
はじめに
現在、私たちは検索エンジンとして Elasticsearch を利用しています。 フリーワード検索はユーザーが入力したワードにマッチした店舗を返す「キーワード検索」の仕組みを採用しています。
フリーワード検索を開発・運用していると以下のような課題に直面します。
- 「なぜこのキーワードで、このお店がヒットするのか?」
- 「なぜ関係の薄そうなお店が、上位に表示されてしまうのか?」
そこで今回は、検索挙動を可視化し、フリーワード検索を改善するための3つのAPI(Analyze, Explain, Term Vectors)をご紹介します。
どう検索されているかを把握する3つの方法
フリーワード検索の改善において、以下の3つのAPIを使い分けています。
Analyze API:入力されたワードが「どう分解されているか」を知る
Explain API:特定のドキュメントが「なぜヒットするのか」を知る
Term Vectors API:ドキュメントが「どう登録されているか」を知る
それぞれの活用方法を具体的に見ていきます。
1. Analyze API:どう分解されているか
Analyze API は、テキストがAnalyzerによってどのようにトークン化(分割)されるかをテストするためのAPIです。
例えば、「隠れ家個室」というワード。 これが「隠れ家 / 個室」と切れるのか、「隠れ家個室」という一語として扱われるのかで、検索結果は大きく変わります。 意図しない検索漏れが発生している場合、多くはこのトークナイズに原因があります。
POST /{インデックス名}/_analyze { "analyzer": "kuromoji_analyzer", // 自社で定義しているAnalyzerを指定 "text": "隠れ家個室" }
Get tokens from text analysis | Elasticsearch API documentation
見るポイント
レスポンスの tokens 配列を確認し、不要な分割がされていないか、確認します。
活用のポイント
ユーザー辞書やシノニム辞書がどのように影響しているかを確認する用途でも利用できます。
POST /{インデックス名}/_analyze { "char_filter": [ "normalize" ], "tokenizer": { "type": "kuromoji_tokenizer", "user_dictionary_rules": [ "関西国際空港,関西国際空港,関西国際空港,カスタム名詞" ] }, "filter": [ "kuromoji_baseform", { "type": "synonym_graph", "synonyms": ["関西国際空港,関西空港"] } ], "text": "関西国際空港" }
※本記事内の設定値や辞書データは解説用のサンプルであり、実際の環境とは異なります
2. Explain API:スコアの根拠を知る
Explain API は、特定のドキュメント(店舗)に対して、あるクエリがマッチした理由、そしてスコア計算の内訳を詳細に説明してくれるAPIです。
「検索にはヒットしている。でも、なぜあの人気店よりも、このお店が上位に来るのか?」 この疑問に答えるには、Elasticsearchが計算しているスコアの内訳を見る必要があります。
活用例: 「焼肉」で検索した際、ID:12345 の店舗がなぜそのスコアになったのかを調査する場合。
POST /{インデックス名}/_explain/{確認したいドキュメントのID} { "query": { "match": { "description": "焼肉" } // 自社で定義しているクエリを指定 } }
Explain a document match result | Elasticsearch API documentation
見るポイント
レスポンスは非常に長いJSONになりますが、重要なのは以下の要素です。
TF (Term Frequency): その単語がドキュメント内に何回登場したか
IDF (Inverse Document Frequency): その単語はどれくらいレアか。
特定のフィールドの重み付けが強すぎる場合などは、この結果を見ることでわかります。
3. Term Vectors API:インデックスのデータを知る
Term Vectors API は、ドキュメントがどのようにインデックスに登録されているかを知ることができます。 「格納された実データ」の確認に使います。また、その単語がインデックス全体でどれくらい出現するか(頻度)も確認できます。
POST /{インデックス名}/_termvectors/{確認したいドキュメントのID} { "fields": ["restaurant_name"], //確認したいフィールド "positions": true, "offsets": true }
Get term vector information | Elasticsearch API documentation
見るポイント
terms: 実際にインデックスに格納されている単語リスト。
doc_freq: その単語が含まれるドキュメント数。この数値が高い(ありふれた単語である)場合、検索スコアへの寄与度は低くなります。
まとめ
検索エンジンのフリーワード検索は複雑な処理をしており、ときに開発者が意図しない結果になることがあります。
それでもElasticsearchはブラックボックスではありません。
解析するツールが提供されているので、それらを駆使してぜひ改善してほしいと思います。
