検索のベスト プラクティス

このドキュメントでは、Search API のベスト プラクティスについて説明します。ここでは、クエリ文字列を単一引用符('')で囲んで示しています。'field:"some text" some-value' のように、二重引用符で囲まれた複数語のフレーズを含むクエリを見分けやすくするためです。

Index.put() と Index.delete() を一括で呼び出す

ドキュメントのインデックスを追加または削除するときは、ドキュメントを一度に 200 個まで渡すことができます。この方法を使用すれば、一度に 1 つずつ処理するよりもはるかに効率的です。

ドキュメントをランクに基づいて事前に並べ替える

デフォルトでは、検索結果はランクの降順に並べ替えられます。各ドキュメントのランクは、Search API のデフォルトの設定では 2011 年 1 月 1 日からの秒数に設定されます。これにより、新しいドキュメントから先に返されるようになっています。ただし、ドキュメントを追加された順に並べ替える必要がなければ、ランクを別の目的に使用することもできます。たとえば不動産のアプリケーションであれば、顧客が最も知りたい情報は価格であるため、ランクを住宅価格に設定してデフォルトで並べ替えると効率的です。

価格が安い順と高い順のように、並べ替え順序を複数使用する場合は、それぞれの順序に対するインデックスを個別に作成できます。たとえば、一方のインデックスを rank = price、もう一方を rank = MAXINT-price(ランクは正の値でなければならないため)のように設定します。

ランクを並べ替えキーとして使用すると検索のパフォーマンスが向上します。他の並べ替えキーを使用する場合は、並べ替えオプションを使用して、検索結果に含まれるドキュメントの数を 10,000 個までに制限する必要があります。この場合、並べ替えの対象となるドキュメントは、ランクに基づく並べ替え順序で決まります。詳しくは、並べ替えオプションの説明をご覧ください。

ブール値のデータには Atom フィールドを使用する

ブール値のデータを数値フィールドに保存するのはきわめて非効果的です。代わりに Atom フィールドを使用し、定数(True / False、yes / no、0 / 1)を割り当てます。

否定よりも肯定を使用する

料理の種類が定義されていないレストランを識別する特別な語句を設定してあれば、そのレストランを除外する場合に、'NOT cuisine:undefined' をクエリとして使用できます。ただし、このクエリの評価は、料理の種類がわかっているレストランを探す場合に比べて、課金対象のオペレーションという意味でも、実行時間という意味でもコスト高になります。cuisine という 1 つのフィールドではなく、cuisine および cuisine_known(後者は Atom フィールド)という 2 つのフィールドを使用できます。料理が定義されているレストランでは、最初のフィールドに実際の料理を、2 番目のフィールドに "yes" を設定します。料理がわからないレストランの場合は、cuisine を ""(空の文字列)に設定し、cuisine_known"no" に設定します。このようにすれば、料理の種類がわかっているレストランを 'cuisine_known:yes' というクエリで探すことができ、否定を使用するよりもはるかに高速になります。

分離よりも結合を使用する

「OR」を使用した分離は、課金対象のオペレーションという意味でも、実行時間という意味でもコスト高になります。'cuisine:Japanese OR cuisine:Korean' で検索するとします。より大きな料理のカテゴリを使用してドキュメントにインデックスを付けることもできます。この場合は、'cuisine:Asian' とするとクエリがシンプルになります。

クエリから同意反復を排除する

トロントにあるすべてのレストランを検索するとします。ドキュメントに city という名前のフィールドが 1 つしかない場合、クエリ 'city:toronto AND NOT city:montreal' を使用すれば、'city:toronto' と同じ結果になります。都市名が "toronto" に設定されると、"montreal" には設定できないためです。この場合、検索する語句が 1 つだけであるため、2 番目のクエリの方がはるかに高速になります。最初のクエリでは、city が「toronto」に設定されたドキュメントのリストを取得してから、city が「montreal」でないすべての都市のリストを取得し、最後にそれらの 2 つのリストの共通部分を特定する必要があるため、3 段階の処理が必要になります。

範囲を絞り込んでから並べ替える

世界中のレストランの情報が格納されたアプリケーションで、現在のユーザーに対して近くのレストランを表示するとします。この方法の 1 つとして、ユーザーの所在地からの距離に基づいて該当するドキュメントを並べ替える方法が考えられます。しかし、1,000,000 件のレストランがある場合、'cuisine:japanese' のようなクエリを実行して、距離による並べ替え(geopoint(x, y), restaurant_loc)を実行すると、時間がかかります。このような場合は、クエリにフィルタを追加することで、該当するドキュメントを絞り込んでから並べ替えを行うと効果的です。1 つの解決策として、国、州、都市のような地理的なカテゴリを作成する方法があります。都市や州はユーザーの所在地から推測できます。その場合、クエリは 'cuisine:japanese AND city:<user-city>' になります。1,000,000 個のドキュメントを並べ替える必要はなくなるはずです。

並べ替えが最小限で済むように限定されたカテゴリを使用する

ランクを使用してレストランを価格帯で並べ替える場合、price_0_10price_11_20price_21_30price_31_40price_41_lots のような価格帯を格納する price_range というフィールドを作成します。このようにすると、並べ替えをまったく行わずに、費用が $21~$40 のすべてのレストランを 'price_range:price_21_30 OR price_range:price_31_40' というクエリで検索できます。多くの場合、適切なカテゴリは不明確ですが、この手法を使用すれば、'... AND price>25 AND price<35' のような高コストのクエリで検索結果を選別しなくても、多数のドキュメントを除外できます。

一致のスコア付けは必要がない限り行わない

スコア付けはドキュメントがクエリにどの程度一致するかを示すのに使用されます。ただし、スコアで並べ替える予定がなければ、検索が遅くなるだけなのでスコア付けはリクエストしないでください。