更多複雜 Search API 查詢

Amy Unruh,2012 年 10 月
Google 開發人員關係

簡介

上一個課程介紹了定義、提交與處理搜尋查詢的基本概念。Search API 支援更複雜的查詢,包括在索引中指定開始查詢的點、應如何排序及格式化結果,以及應從查詢傳回有關文件的哪些資訊。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 傳回每頁最多三個結果。

以上範例也顯示使用了 offset 參數。偏移指定了開始傳回結果之前相符的文件數:

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

offsetlimit 參數有一個常見的用法,就是為查詢結果分頁。如要實作分頁功能,您需要知道查詢找到的相符項目總數,以及到目前為止已經傳回了多少。您可以從傳回的 SearchResults 物件取得該資訊:

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

Search API 也支援使用查詢游標。游標是指示開始查詢的位置點的另一種方法,可以讓您從上一個結果集的結尾處繼續搜尋。使用游標通常比使用偏移有效。但是,Search API 目前不像 Datastore API 一樣支援「反向游標」,這會使 Search API 更難以實作往前分頁功能。因此,應用程式範例使用了偏移,而不使用游標來分頁其查詢結果。您可以在這裡找到使用游標的範例。

片段處理

「欄位片段」可以讓您傳回欄位的縮減部分,而非其完整內容。傳回的片段將包含相符欄位的片段,相符的搜尋字詞會以粗體醒目顯示。在商品搜尋應用程式 (內含預設資料) 中,對查詢 stories 執行搜尋會在文件的 description 欄位中傳回三個相符結果。由於我們要求對 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')],
    ...)

這個運算式會通知 Search API 傳回 price 欄位值乘以 1.08 做為 adjusted_price 的值。Search API 提供各種內建的運算式函式,您可以在此類運算中使用此函式。例如,您可以像 'max(price, 9.99)' 這樣定義運算式。

QueryOptions 物件中包含 returned_expression 清單之後,您可在從搜尋查詢傳回的文件中存取該運算欄位,而且同樣是透過 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 的支援可以讓您進行「位置查詢」。 舉例來說,您可以尋找附近的商店或餐廳,或者附近的活動訊息串更新。

如要執行位置查詢,您需要三種資訊:

  • 含有緯度與經度座標的位置,藉以測量距離。
  • 搜尋半徑 (例如 45 公里)。
  • 用以測量距離的一組點。

前兩項通常由使用者提供,最後一項則來自編入索引的文件本身:在我們的商品搜尋應用程式範例中,這由商店的位置組成,而商店的位置則是取自我們在前面的開始使用課程中建構的商店位置文件。

為了搜尋靠近使用者的商店位置,應用程式範例會透過瀏覽器取得使用者位置,而使用者則會輸入要在特定範圍內搜尋的距離。距離會轉換成公尺,也就是 Search API 使用的距離單位。假設使用者的位置在 (-33.857, 151.215),而使用者將搜尋半徑設定為 45 公里之內。應用程式會建構類似以下這樣的查詢字串:

"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,這個屬性擁有足夠的特點,足以專門設立一個課程來講解,所以我們會在 下一個課程中討論這個屬性。如要瞭解未在本課程中說明的其他選項,請參閱 QueryOptions 說明文件

如要確認您是否真正瞭解課程內容,可以嘗試對本課程介紹的 QueryOptions 屬性進行試驗。例如,您可以將 config.py 檔案中的 DOC_LIMIT 變更為較大值。這就是做為 QueryOptions limit 引數傳送的值。

您也可以嘗試對 returned_expressions 功能進行試驗。returned_expressions 應該已在 _buildQuery() 中像以下這樣進行定義:

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

請到 ProductSearchHandler 類別中尋找 handlers.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,而不是實際的價格。就這樣,顯示的價格將會包含營業稅。搜尋結果中的「View product details」 (查看產品詳細資料) 連結仍將為您顯示實際的價格。(只有部署的應用程式才會填入 adjusted_price 欄位)。

下一個課程中,您將會瞭解如何按您想要的順序排序查詢搜尋的結果。

本頁內容對您是否有任何幫助?請提供意見:

傳送您對下列選項的寶貴意見...

這個網頁
App Engine 上的 Python