Search API 基本資訊

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

簡介

本課程涵蓋使用 Search API 的基本概念:為內容建立索引並在索引上進行查詢。在本課程中,您會學習以下操作方式:

  • 建立搜尋索引
  • 透過索引文件將內容新增到索引
  • 在已經建立索引的資料上進行簡易的全文搜尋查詢作業

目標

瞭解使用 App Engine Search API 的基礎概念。

必備條件

索引

App Engine 的 Search API 是透過 Index 物件運作。這個物件可讓您透過索引文件儲存資料、使用搜尋查詢擷取文件,以及修改與刪除文件。

每個索引都有一個「索引名稱」並可視需要使用「命名空間」。名稱是專門用來識別特定命名空間中的索引。這個名稱必須是能夠列印的可見 ASCII 字串,而且開頭不得為 !,此外也需要排除空格字元。您可以建立多個 Index 物件,但在同一個命名空間中,任何兩個具有相同索引名稱的物件會參照一樣的索引。

您可以使用命名空間與索引來管理文件。在商品搜尋應用程式範例中,所有產品文件都會放在一個索引中,而其他索引則包含商家位置的相關資訊。如果我們只想搜尋書籍,則可以依據產品類別來篩選查詢。

您可以在程式碼中指定索引名稱來建立 Index 物件:

from google.appengine.api import search
index = search.Index(name='productsearch1')

index = search.Index(name='yourindex', namespace='yournamespace')

第一次存取基礎文件索引時,如果該索引尚未存在,則系統會建立基礎文件索引,能讓您不需要明確地建立索引。

您可以刪除索引中的文件或刪除整個索引,詳情請參閱下一堂課:「深入瞭解 Python Search API」。

文件

「文件」會保留可搜尋的索引內容,並且是建構可索引資料所用的容器。從技術層面來看,Document 物件代表由文件 ID 識別的不重複「欄位」集合,您可以為欄位命名並輸入值。文件不像 Datastore 實體一樣具有 kinds

例如,在我們的應用程式範例中,產品類別為書籍和 HD 高畫質電視。商店能提供的產品選擇相當有限。應用程式範例中的每個產品文件一律包含下列核心欄位,這些欄位是由 docs.Product 類別變數定義:

  • CATEGORY (設為 bookshd_televisions)
  • PID (產品 ID)
  • PRODUCT_NAME
  • DESCRIPTION
  • PRICE
  • AVG_RATING
  • UPDATED (上次更新日期)
產品文件欄位
圖 1:產品文件欄位。

書籍和 HD 高畫質電視類別各自皆有一些額外欄位。書籍類別的其他欄位包含:

  • title
  • author
  • publisher
  • pages
  • isbn

HD 高畫質電視類別的其他欄位則包含:

  • brand
  • tv_type
  • size

應用程式本身會強制要求每個產品類型的文件保持一致的應用程式層級語意。也就是說,所有產品文件一律都會含有相同的核心欄位,所有書籍都會有一組相同的額外欄位,依此類推。然而,搜尋索引針對文件所用的欄位,並未硬性規定應維持一致的結構,因此沒有具體查詢「產品」文件的明確概念。

欄位類型

每個文件欄位都有專屬的「欄位類型」,其類型可以是下列定義在 Python 模組 search 中的任何一種:

  • TextField:純文字字串。
  • HtmlField:HTML 格式的文字。當建立結果程式碼片段及在文件計分時,Search API 會將這個標記納入考量,因此如果字串為 HTML 格式,請使用這個欄位類型。
  • AtomField:視為單一符記的字串。如果查詢只包含子字串,而非完整的欄位值,則不會進行比對。
  • NumberField:數字值 (整數或浮點)。
  • DateField:沒有時間元件的日期。
  • GeoField:由指定緯度和經度座標的 GeoPoint 物件表示的地理位置。

針對文字欄位 (TextFieldHtmlFieldAtomField),欄位值應為 Unicode 字串。

範例:建構產品文件欄位及建立文件

如要建構 Document 物件,您可以建立欄位清單並視需要定義文件 ID,接著將此資訊傳送到 Document constructor

應用程式範例針對產品文件使用 TextFieldAtomFieldNumberFieldDateField 的欄位類型。

定義產品文件欄位

核心產品欄位 (所有產品文件中均含有的欄位) 看起來如下所示,其中我們假設下列建構函式的值引數已設為適當的值:

from google.appengine.api import search
...
fields = [
      search.TextField(name=docs.Product.PID, value=pid), # the product id
      # The 'updated' field is set to the current date.
      search.DateField(name=docs.Product.UPDATED,
                       value=datetime.datetime.now().date()),
      search.TextField(name=docs.Product.PRODUCT_NAME, value=name),
      search.TextField(name=docs.Product.DESCRIPTION, value=description),
      # The category names are atomic
      search.AtomField(name=docs.Product.CATEGORY, value=category),
      # The average rating starts at 0 for a new product.
      search.NumberField(name=docs.Product.AVG_RATING, value=0.0),
      search.NumberField(name=docs.Product.PRICE, value=price) ]

請注意,類別欄位的類型會設為 AtomField。Atom 欄位適合用於項目要完全相符的類別;而文字欄位則適合用於標題或說明等字串。我們其中一個範例類別為 hd televisions。如果只搜尋 televisions,將無法獲得相符項目 (假設該字串並不包含在其他產品欄位中),但是如果我們搜尋完整的欄位字串 (hd televisions),即可比對到該類別欄位。

應用程式範例也包含個別產品類別專用的欄位。這些欄位也會加入欄位清單,視類別而定。舉例來說,電視類別會有 size (數字欄位)、brandtv_type (文字欄位) 等額外欄位。書籍類別則會有一組不同的欄位。

建立文件

如有欄位清單,則可以建立文件物件。我們會設定每個產品文件的文件 ID,做為那項產品預先定義的唯一識別碼:

d = search.Document(doc_id=product_id, fields=fields)

這項設計可為我們帶來一些好處 (在接下來課程中會討論相關內容),但如果沒有指定文件 ID,系統便會在文件加入索引時自動產生一個文件 ID。

範例:在商家位置文件中使用地理點

Search API 針對含有 GeoField 類型欄位的文件提供地理搜尋的支援功能。如果您的文件包含這類欄位,可以根據距離比較來查詢索引以找出相符項目。

位置是由儲存緯度與經度座標的 GeoPoint 類別定義。緯度指定赤道以南或以北的角距,以度為單位;經度指定本初子午線以東或以西的角距,也是以度為單位。例如,GeoPoint(-33.857, 151.215) 定義了雪梨歌劇院的位置。如要在文件中儲存地理點,則需要加入 GeoField 欄位並將 GeoPoint 物件設為欄位值。

以下說明在商品搜尋應用程式中,如何建構商家位置文件的欄位:

from google.appengine.api import search
...
geopoint = search.GeoPoint(latitude, longitude)
fields = [search.TextField(name=docs.Store.STORE_NAME, value=storename),
             search.TextField(name=docs.Store.STORE_ADDRESS, value=store_address),
             search.GeoField(name=docs.Store.STORE_LOCATION, value=geopoint)  ]

建立文件的索引

您必須先使用 Index 物件的 put() 方法將文件加入索引,才能查詢文件的內容。索引功能可讓您透過 Search API 的查詢語言和查詢選項來搜尋文件。

在建構文件時,您可以指定自己的文件 ID。文件 ID 必須是能夠列印的可見 ASCII 字串,而且開頭不得為 !,此外也需要排除空格字元。(本文稍後將會說明,如果您使用現有文件的 ID 來建立文件的索引,系統將會重新建立該現有文件的索引)。如果您沒有指定文件 ID,在文件加入索引後,系統會自動產生不重複的數字 ID。

您可以一次加入一個文件,或者以批次的方式加入文件清單,採用批次的做法會更有效率。以下說明如何根據欄位清單建構文件,並將文件加入索引中。

from google.appengine.api import search

# Here we do not specify a document ID, so one will be auto-generated on put.
d = search.Document(fields=fields)
try:
  add_result = search.Index(name=INDEX_NAME).put(d)
except search.Error:
  # ...

您應該找出並處理任何因 put() 而產生的例外狀況,這類狀況屬於 search.Error

如果您要指定文件 ID,請將文件 ID 傳送到 Document 建構函式,如下所示:

d = search.Document(doc_id=doc_id, fields=fields)

您可以透過 id 的屬性取得新增的文件 ID,該屬性是在 search.AddResult 物件的清單中,並從 put() 的作業傳回:

doc_id = add_result[0].id

基本搜尋查詢

將文件加入索引後,即可搜尋文件內容。您可以在索引中針對這些文件執行全文搜尋查詢作業。

提交搜尋查詢有兩種方法。最簡單的方式是將查詢字串傳送至 Index 物件的 search() 方法。或者,您可以建立 Query 物件並將該物件傳送至 search() 方法。建構查詢物件可讓您指定查詢、將結果排序,以及產生顯示搜尋結果的選項。

在本課程中,我們將會帶您瞭解如何使用這兩種方式建構簡單的查詢。提醒您,開發網路伺服器 (在本機上執行) 並不完全支援某些搜尋查詢,因此您將會需要使用已部署的應用程式來執行這些查詢。

使用查詢字串進行搜尋

「查詢字串」是任何可由 Search API 的查詢語言剖析的 Unicode 字串。建構查詢字串完畢後,請將該字串傳送至 Index.search() 方法。例如:

from google.appengine.api import search

# a query string like this comes from the client
query = "stories"
try:
  index = search.Index(INDEX_NAME)
  search_results = index.search(query)
  for doc in search_results:
    # process doc ..
except search.Error:
  # ...

使用查詢物件進行搜尋

相較於查詢字串的做法,Query 物件可讓您進一步掌控查詢選項。在本範例中,我們首先要建構 QueryOptions 物件。該物件的引數會指定查詢應傳回 doc_limit 數量的結果 (如果您查看商品搜尋應用程式程式碼,將會發現較複雜的 QueryOption 物件;我們會在接下來的深入瞭解 Python Search API 課程中查看這些物件)。我們下一步會使用查詢字串和 QueryOptions 物件來建構 Query 物件。然後按照上述查詢字串的做法,將 Query 物件傳送至 Index.search() 方法。

from google.appengine.api import search

# a query string like this comes from the client
querystring = “stories”
try:
  index = search.Index(INDEX_NAME)
  search_query = search.Query(
      query_string=querystring,
      options=search.QueryOptions(
          limit=doc_limit))
  search_results = index.search(search_query)
except search.Error:
  # ...

處理查詢結果

在您提交查詢之後,系統會使用可疊代的 SearchResults 物件,將相符的搜尋結果傳回應用程式。這個物件包含找到結果的數量、實際傳回結果的數量和選用的「查詢游標」物件。

傳回的文件可透過對 SearchResults 物件進行疊代作業來存取。傳回結果的數量等同物件 results 屬性的長度。number_found 屬性則是設定為已找到的匹配數。針對傳回物件進行疊代作業可提供傳回的文件,您可以任意處理傳回的文件。

try:
  search_results = index.search("stories")
  returned_count = len(search_results.results)
  number_found = search_results.number_found
  for doc in search_results:
    doc_id = doc.doc_id
    fields = doc.fields
    # etc.
except search.Error:
  # ...

摘要與回顧

在本課程中,我們概略瞭解了如何建立已編入索引的文件及查詢其中內容。如要確認您學到的內容,請在自己的簡易應用程式中嘗試完成這些步驟:

  • 建立 Index 物件。
  • 建立文件欄位清單 (例如使用 TextField 類型) 並使用該欄位清單建構 Document 物件。將文件加入索引。
  • 使用搜尋字串來搜尋索引,該字串由其中一個欄位值含有的字詞組成。您建立的文件是否做為相符項目傳回?

下一個課程中,我們將會深入瞭解 Search API 索引。

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

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

這個網頁
Python 2 適用的 App Engine 標準環境