より複雑な Search API クエリ

2012 年 10 月、Amy Unruh
Google Developer Relations

はじめに

前のクラスでは、検索クエリの定義、送信、処理の基本について説明しました。Search API では、インデックス内のクエリの開始点の指定、検索結果の並べ替え方法と形式、クエリによって返されるドキュメントに関する情報など、各種の指定を含め、より複雑なクエリがサポートされています。Geosearch(ロケーション ベースのクエリ)もサポートされています。

このレッスンでは、これらの機能のいくつかについて詳細に学習します。次のコンセプトについて説明します。

  • 複雑なクエリの結果を定義し処理する
  • クエリによって返されるドキュメント フィールドを制御する
  • オフセットと制限によってクエリの開始点と返される結果数を設定する
  • ロケーション ベースのクエリ(Geosearch)を作成して使用する

このレッスンで説明されている機能や、その他の機能について詳しくは、Search API のドキュメントをご覧ください。

目標

複雑な Search API 検索クエリの方法を学習する

前提条件

このクラスに先行するクラス: Python Search API スタートガイド

次の内容も必要になります。

クエリ オプション

Query クラスのコンストラクタは、オプションの QueryOptions オブジェクトを引数として受け付けるため、広範なオプションの構成が可能です。

search_query = search.Query(
    query_string=query.strip(),
    options=search.QueryOptions(...)
    )

サンプルの商品検索アプリケーションで使用される、以下の QueryOptions 構成について考えてみましょう。

search_query = search.Query(
    query_string=query.strip(),
    options=search.QueryOptions(
        limit=doc_limit,
        offset=offsetval,
        sort_options=sortopts,
        snippeted_fields=[docs.Product.DESCRIPTION],
        returned_expressions=[search.FieldExpression(name='adjusted_price',
            expression='max(price, 14.99)')],
        returned_fields = [docs.Product.PID, docs.Product.DESCRIPTION,
          docs.Product.CATEGORY, docs.Product.AVG_RATING,
          docs.Product.PRICE, docs.Product.PRODUCT_NAME]
        ))

ここでは、オフセット(クエリの開始点)と制限(返される結果の最大数)、並べ替えオプション(次のレッスンを参照)、スニペット フィールドの一覧、返される式(計算済み)の一覧、返されるフィールドの一覧が指定されています。 各オプションの機能を見てみましょう。

クエリのオフセット、制限、カーソル

クエリによって返される結果数を制御するには、QueryOptions コンストラクタlimit パラメータを使用します。サンプルの商品検索アプリケーションでは、limit を使用して、ページあたり最大 3 つの結果を返しています。

上記の例では、offset パラメータの使用方法も示しています。オフセットでは、結果を返すまでにスキップする一致ドキュメントの数を指定します。

search.QueryOptions(
    limit=doc_limit,
    offset=offsetval,
    ...)

offset および limit パラメータの一般的な用途としては、クエリ結果のページ分けが挙げられます。ページ分けを実装するには、クエリによって検出された一致の合計数と、それまでに返された数が必要になります。その情報は、返された SearchResults オブジェクトによって得られます。

number_found = search_results.number_found
returned_count = len(search_results.results)

Search API ではクエリカーソルを使用できます。カーソルは、クエリの開始点を示すための別の方法として使用できます。前の結果セットの終了点から検索を続行できます。一般的に、カーソルはオフセットよりも効率的です。ただし、現在 Search API では Datastore API のような「リバース カーソル」がサポートされていないため、逆方向のページ分けが困難になっています。そのためサンプル アプリケーションでは、カーソルではなくオフセットを使用して、クエリ結果のページ設定を行っています。カーソルを使用した例についてはこちらをご覧ください。

スニペット

スニペット フィールドを使用することで、フィールド全体ではなく、省略された一部だけを返すことが可能になります。返されるスニペットには、一致があったフィールドのフラグメントが含まれ、一致した検索単語が太字で示されます。製品検索アプリケーション(デフォルト データ)では、クエリ stories による検索でドキュメントの description フィールドに 3 つの一致が返されます。description のスニペット化をリクエストしたため、結果のスニペット式では「stories」という単語がハイライトされています。

一致した単語がハイライトされたスニペット フィールド
図 1: 一致した単語がハイライトされたスニペット フィールド

スニペットを指定するには、対象となるフィールド名のイテラブルを指定します。上記の QueryOptions コンストラクタでは、DESCRIPTION フィールドのスニペットがリクエストされています。

search.QueryOptions(
  snippeted_fields=[docs.Product.DESCRIPTION],
  ...)

クエリ結果を処理する際に、返されたドキュメントの expressions プロパティを介して生成されたスニペットにアクセスします。

for doc in search_results:
  ...
  for expr in doc.expressions:  # iterate over the computed fields
    if expr.name == docs.Product.DESCRIPTION:
      description_snippet = expr.value
      break
  # ... do something with the document ...

expressions プロパティには、クエリでリクエストされた式の結果である計算済みフィールドの一覧が保持されます。上記のコードでは、DESCRIPTION フィールドに対して生成されたスニペットを取得します。docスコア付きドキュメントです。スコア付きドキュメントは検索から返されます。ドキュメント コンテンツに加えて、ドキュメント スコアや計算済みフィールド(以下を参照)などの他の情報も含まれています。

返される式と式関数

returned_expression クエリ オプションでは、ドキュメント フィールドに基づいて、計算済みフィールドを定義できます。このフィールドは、検索結果でスコア付きドキュメントの一部として返されます。

8% の消費税を含む各製品の価格を計算して表示する場合、名前が adjusted_price で、値が文字列 price * 1.08 であるフィールド式を作成します。

search.QueryOptions(
    returned_expressions=[search.FieldExpression(name='adjusted_price',
        expression='price * 1.08')],
    ...)

この式は、adjusted_price の値として price フィールドの 1.08 倍の値を返すことを Search API に示します。Search API には、そのような式で使用できる多様な式関数が組み込まれています。たとえば 'max(price, 9.99)' のような式を定義できます。

returned_expression リストを QueryOptions オブジェクトに含めることで、検索クエリによって返されたドキュメント内の計算済みフィールドに expressions プロパティを介してアクセスできます。

for doc in search_results:
  ...
  for expr in doc.expressions:  # iterate over the computed fields
    if expr.name == docs.Product.DESCRIPTION:  # get the description snippet
      description_snippet = expr.value
    elif expr.name == 'adjusted_price':  # get the adjusted price
      price = expr.value
  # ... do something with the document ...

返されるフィールド

QueryOptions コンストラクタは returned_fields パラメータを受け付けます。このパラメータにより、使用するドキュメント フィールドだけをリクエストすることで、クエリの効率を向上させることができます。たとえば、先に示した QueryOptions オブジェクトは、前回更新日を除くすべての「コア」製品フィールドをリクエストします。前回更新日は結果の概要に表示されないように指定しています。また、book ドキュメントの publisherhd_television ドキュメントの tv_type など、カテゴリ固有のフィールドもリクエストしません。

search.QueryOptions(
    returned_fields = [docs.Product.PID, docs.Product.DESCRIPTION,
        docs.Product.CATEGORY, docs.Product.AVG_RATING,
        docs.Product.PRICE, docs.Product.PRODUCT_NAME]
    ...)

returned_fields 引数は、検索結果で返されるフィールド名に対するイテラブルである必要があります。インデックスに追加されたドキュメントに他のフィールドを含めることができる場合でも、検索結果で返されたドキュメントには、指定されたフィールドだけが含まれます。

ロケーション ベースのクエリ(Geosearch)

Search API では Geosearch がサポートされているため、ロケーション ベースのクエリが可能です。 それにより、たとえば近隣の店舗やレストラン、またはアクティビティ ストリームの更新を検索できます。

ロケーション ベースのクエリを実行するには、次の 3 つの情報が必要です。

  • 距離を測定する基準になる、緯度と経度の座標であるロケーション
  • 検索範囲となる半径(45 km など)
  • 距離を測定するポイントのセット

最初の 2 つの項目は、多くの場合ユーザーが提供します。3 番目の情報は、インデックスに追加されたドキュメント自体から取得します。このサンプルの製品検索アプリケーションでは、前のスタートガイドクラスで作成した店舗ロケーション ドキュメントから取得したロケーションで構成されています。

ユーザーの近くにある店舗のロケーションを検索するために、サンプル アプリケーションではブラウザを介してユーザーのロケーションを取得し、ユーザーは検索範囲の距離を入力します。距離は、Search API で距離の単位として使用されるメートルに変換されます。ユーザーのロケーションが(-33.857, 151.215)で、検索半径が 45 km であるとします。アプリケーションでは次のようなクエリ文字列が作成されます。

"distance(store_location, geopoint(-33.857, 151.215)) < 45000"

これが Index.search メソッドに渡されます。

from google.appengine.api import search
...
    # a query string like this comes from the client
    query = "distance(store_location, geopoint(-33.857, 151.215)) &lt; 45000"
    try:
      index = search.Index(config.STORE_INDEX_NAME)
      search_results = index.search(query)
     for doc in search_results:
        # process doc ...
    except search.Error:
      # ...

まとめと確認

このレッスンでは、QueryOptions オブジェクトを使用して検索クエリを指定する方法と、有用な QueryOptions プロパティとして limitoffsetsnippeted_fieldsreturned_expressionreturned_fields を確認しました。Geosearch クエリを構築する方法も説明しました。

重要な QueryOptions プロパティである sort_options は、1 つのレッスンとして取り上げるだけの機能を備えています。それについて次のレッスンで説明します。このレッスンで取り上げていないオプションについては、QueryOptions ドキュメントをご覧ください。

理解度を確認するために、ここで説明した QueryOptions プロパティを試してみてください。たとえば、config.py ファイルの DOC_LIMIT を大きな値に変更します。この値は QueryOptions limit 引数として渡されます。

また、returned_expressions 機能を試してみましょう。returned_expressions_buildQuery() ですでに次のように定義されているはずです。

search.FieldExpression(name='adjusted_price',
    expression='price * 1.08')

クラス ProductSearchHandlerhandlers.py の行を見ると、次のようになっています。

# uncomment to use 'adjusted price', which should be
# defined in returned_expressions in _buildQuery() below, as the
# displayed price.

以降の行のコメントを解除します。

# elif expr.name == 'adjusted_price':
  # price = expr.value

アプリケーションを再デプロイすると、検索結果に実際の価格ではなく adjusted_price が表示されます。表示される価格には消費税が含まれています。検索結果の商品の詳細を表示リンクでは、実際の価格が表示されます(adjusted_price フィールドは、デプロイされたアプリケーションについてのみ値が入力されます)。

次のレッスンでは、クエリの検索結果を任意に並べ替える方法を学習します。

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...