Search API 為內含結構化資料的文件提供索引模型。您可以搜尋索引,並整理及顯示搜尋結果。這個 API 可支援對字串欄位進行全文比對。文件與索引皆儲存在單獨的永久存放區中,且存放區已針對搜尋作業進行最佳化。Search API 可將任意數量的文件編入索引。對於需要擷取龐大結果集的應用程式而言,App Engine Datastore 可能更適合。如要查看 search
套件的內容,請參閱search
套件參考資料。
總覽
Search API 有四大基礎概念:文件、索引、查詢與結果。
文件
文件是具有唯一識別碼的物件,也具有包含使用者資料的欄位清單。每個欄位都有名稱與類型。欄位分為多種類型,以欄位所包含的值種類來識別其類型:
- Atom 欄位 - 不可分割的字元字串。
- 文字欄位 - 可逐字搜尋的純文字字串。
- HTML 欄位 - 包含 HTML 標記代碼的字串,只有標記代碼之外的文字可以搜尋。
- 數字欄位 - 浮點數。
- 時間欄位 -
time.Time
值,以毫秒精確度儲存。 - 地理點欄位 - 具有緯度與經度座標的資料物件。
文件的大小上限為 1 MB。
索引
索引儲存的文件可用於擷取。您可以按照文件 ID 來擷取單一文件、擷取具有連續 ID 的一系列文件,或是擷取索引中的所有文件。您也可以將特定欄位及其值指定為查詢字串,透過搜尋索引來擷取符合這些條件的文件。您可以將文件群組放進獨立的索引中,藉此管理文件群組。
索引中的文件數,或您能夠使用的索引數,兩者皆無限制。根據預設,單一索引中所有文件的總大小限制在 10 GB 以內。具有 App Engine 管理員角色的使用者,可以從 Google Cloud 主控台的 App Engine Search 頁面提交要求,將大小上限提升至 200 GB。
查詢
如要搜尋索引,您可以建構內含查詢字串,並可能含有其他某些選項的查詢。查詢字串可以指定一或多個文件欄位的值條件。搜尋索引時,您只會取得索引中欄位符合查詢條件的文件。
最簡單的查詢 (有時候也稱為「全域搜尋」) 是僅包含欄位值的字串。以下搜尋使用的字串會搜尋內含「rose」與「water」字詞的文件:
以下搜尋會搜尋日期欄位中包含「1776 年 7 月 4 日」這個日期,或文字欄位中包含「1776-07-04」字串的文件:
查詢字串也可以更具體一點,其中可包含一或多個條件,每個條件都有一個欄位名稱,以及對於欄位值的限制。條件的確切格式取決於欄位的類型。例如,假設有一個文字欄位名為「Product」,有一個數字欄位名為「Price」,以下就是對這兩個條件執行查詢的字串:
「查詢選項」顧名思義為非必要選項。這些選項提供下列各種功能:
- 控制在搜尋結果中傳回的文件數量。
- 指定要在結果中包含哪些文件欄位。預設值是包含原始文件中的所有欄位。您可以指定結果只包含一個欄位子集 (原始文件不受影響)。
- 將結果排序。
- 使用
FieldExpressions
為文件建立「計算欄位」,並使用程式碼片段建立縮寫文字欄位。 - 僅傳回每項查詢的部分相符文件 (使用偏移與游標),藉此支援搜尋結果分頁功能。
如要記錄已執行的查詢,建議在應用程式中記錄查詢字串。
搜尋結果
Search
呼叫會傳回 Iterator
值,該值可用於傳回完整的一組相符文件。
其他訓練材料
除了本說明文件以外,您還可以在 Google 開發人員學院閱讀有關 Search API 的兩部分訓練課程。 (儘管該課程使用的是 Python API,您仍可能會發現對於「搜尋」概念的額外討論很有幫助。)
文件與欄位
文件由 Go 結構表示,構成「欄位」的清單。文件也可由實作FieldLoadSaver
介面的任何類型表示。
文件 ID
索引中的每個文件都必須具有專屬的文件 ID,或是 docID
。
從索引中擷取文件時可以使用 ID,而不用執行搜尋。根據預設,Search API 會在文件建立時自動產生 docID
。您也可以在建立文件時自行指定 docID
。docID
只能包含可見、可列印的 ASCII 字元 (從 33 到 126 (含首尾) 的 ASCII 碼),且不得超過 500 個字元。文件 ID 不得以驚嘆號 (「!」) 開頭,且不得以雙底線 (「__」) 開頭或結尾。
儘管建立容易理解且具有意義的專屬文件 ID 很方便,但您仍不可在搜尋中加入 docID
。請考量以下情況:您有一個索引內含代表零件的文件,並使用零件的序號做為 docID
。針對任何單一零件擷取文件會很有效率,但您無法連同其他欄位值 (例如購買日期) 一併搜尋某個範圍內的序號。只要將序號儲存到 Atom 欄位中即可解決這個問題。
文件欄位
文件包含的欄位具有「名稱」、「類型」以及該類型的單一「值」。兩個以上的欄位名稱可以相同,但類型不能相同。例如,您可以使用「年齡」名稱定義兩個欄位:其中一個是文字類型 (值為「二十二」),而另一個是數字類型 (值為「22」)。
欄位名稱
欄位名稱會區分大小寫,並且只能包含 ASCII 字元。名稱必須以字母為開頭,可包含字母、數字或底線。欄位名稱長度不得超過 500 個字元。
多值欄位
欄位只能包含一個值,且必須符合欄位的類型。欄位名稱可以重複。文件可以有相同名稱及相同類型的多個欄位,這是表示多值欄位的一種方式。(但是,相同名稱的日期與數字欄位不得重複。)文件也可以包含相同名稱及「不同」欄位類型的多個欄位。
欄位類型
總共有三種欄位可用於儲存字元字串;我們將這些欄位統稱為「字串欄位」:
- 文字欄位:長度上限為 1024**2 個字元的字串。
- HTML 欄位:長度上限為 1024**2 個字元的 HTML 格式字串。
- Atom 欄位:長度上限為 500 個字元的字串。
此外,還有三種欄位類型可用於儲存非文字資料:
- 數字欄位:介於 -2,147,483,647 及 2,147,483,647 之間的雙精度浮點值。
- 時間欄位 -
time.Time
值,以毫秒精確度儲存。 - 地理點欄位:地球上由緯度與經度座標表示的點。
字串欄位類型包括 Go 的內建 string
類型,以及 search
套件的 HTML
和 Atom
類型。數字欄位以 Go 的內建 float64
型別表示,時間欄位使用 time.Time
型別,地理點欄位則使用 appengine
套件的 GeoPoint
型別。
字串與時間欄位的特殊處理方式
將含有時間、文字或 HTML 欄位的文件加入索引時,會出現某些特殊處理方式。事先瞭解「運作原理」,然後有效使用 Search API,這樣對您很有幫助。
代碼化字串欄位
將 HTML 或文字欄位編入索引時,就會「代碼化」這些欄位的內容。字串會在出現空格或特殊字元 (標點符號、井字號、反斜線等) 的位置分割為代碼。索引將包含每個代碼的項目。如此一來,您可以搜尋僅包含欄位值一部分的關鍵字與詞組。舉例來說,在搜尋「dark」時,會將文件與包含「it was a dark and stormy night」字串的文字欄位進行比對;在搜尋「time」時,則會將文件與包含「this is a real-time system」字串的文字欄位進行比對。
在 HTML 欄位中,標記代碼內的文字並不會代碼化,因此 HTML 欄位中包含 it was a <strong>dark</strong> night
的文件將會符合「night」的搜尋,但不符合「strong」的搜尋。如果您想要搜尋標記文字,請將標記文字儲存在文字欄位中。
Atom 欄位不會代碼化。具有 Atom 欄位且欄位值為「bad weather」的文件,將僅符合對「bad weather」完整字串進行的搜尋,而不符合單獨對「bad」或「weather」進行的搜尋。
代碼化規則
底線 (_) 與連接符號 (&) 字元不會將字詞分割成代碼。
以下這些空白字元一律會將字詞分割成代碼:空格、回車字元、換行字元、水平定位點、垂直定位點、換頁字元與 NULL。
這些字元會被視為標點符號,並且會將字詞分割為代碼:
! " % ( ) * , - | / [ ] ] ^ ` : = > ? @ { } ~ $ 下表中的字元「通常」會將字詞分割成代碼,但根據這些字元出現時所在的前後文,各字元的處理方式可能不同:
字元 規則 <
在 HTML 欄位中,「小於」符號表示忽略 HTML 標記的開頭。 +
如果一或多個「加號」的字串出現在字詞的結尾,則會將這些字串當成字詞的一部分來處理 (C++)。 #
如果「井字號」前面加上 a、b、c、d、e、f、g、j 或 x (a# - g# 是音樂記號;j# 與 x# 是程式設計語言,c# 既是音樂記號也是程式設計語言),則會將井字號當成字詞的一部分來處理。如果某一字詞「前面加上」了「#」(#google),則會將其當成主題標記,井字號會變成該字詞的一部分。 '
如果單引號位於字母「s」之前,而「s」後面跟著空格,例如「John's hat」,就會將單引號當成字母處理。 .
如果小數點出現在數字之間,則屬於數字的一部分 (即小數點)。如果在縮寫 (A.B.C) 中使用,則也可以是字詞的一部分。 -
如果在縮寫字中使用破折號 (I-B-M),則破折號也是字詞的一部分。 除了字母與數字 (「A-Z」、「a-z」、「0-9」) 以外的其他所有 7 位元字元都會當成標點符號處理,並將字詞分割成代碼。
其他任何字元都會當成 UTF-8 字元剖析。
縮寫字
代碼化作業使用特殊規則來辨識縮寫字 (如「I.B.M.」、"a-b-c" 或 "C I A")。縮寫字是由單一字母字元組成的字串,每個字元之間都加上相同的分隔字元。有效的分隔字元有句號、破折號或任意數量的空格。當縮寫字進行代碼化時,會移除字串內的分隔字元,因此上述範例字串會變成「ibm」、「abc」和「cia」,原始文字則會保留在文件欄位中。
處理縮寫字時,請注意以下幾點:
- 縮寫字不得包含超過 21 個字母。包含超過 21 個字母的有效縮寫字字串將會分割成一系列縮寫字,每一系列縮寫字內含不超過 21 個字母。
- 如果縮寫字中的字母由空格分隔,所有字母的大小寫都必須相同。由句號與破折號構成的縮寫字可以使用大小寫混合的字母。
- 搜尋縮寫字時,可以輸入標準格式的縮寫字 (不含分隔符號的字串),或在字母之間用破折號或縮寫點 (但並非同時使用兩者) 分隔的縮寫字。因此,搜尋「I-B-M」、「I.B.M」或「IBM」字詞時,都可能擷取出「I.B.M」這樣的文字。
時間欄位準確率
在文件中建立時間欄位時,可將欄位值設定為
time.Time
。
為建立索引及搜尋時間欄位,系統會忽略任何時間元件,並將日期轉換為自 1970 年 1 月 1 日起算的天數 (世界標準時間)。也就是說,即使時間欄位可以包含精確的時間值,日期查詢也只能以 yyyy-mm-dd
形式指定時間欄位值。這也表示並未明確定義日期相同的時間欄位排序順序。time.Time
類型可以表示精確到奈秒的時間,Search API 還是只能以毫秒的精確度儲存時間。
其他文件屬性
文件的「排名」是一個正整數,可確定搜尋傳回的預設文件順序。根據預設,排名會在建立文件時設定為從 2011 年 1 月 1 日開始的秒數。您可以在建立文件時明確設定排名。為多份文件指派相同的排名並不明智,您絕對不可為 10,000 份以上的文件指派相同的排名。
如果您指定排序選項,則可使用排名做為排序鍵值。請注意,在排序運算式或欄位運算式中使用排名時,會以 _rank
表示。如要進一步瞭解如何設定排名,請參閱 DocumentMetadata
參考資料。
Field
結構的語言屬性指定了編碼欄位時使用的語言。
從文件連結至其他資源
您可以使用文件的 docID
及其他欄位做為連結,連至應用程式中的其他資源。舉例來說,如果您使用 Blobstore,則可將 docID
或 Atom 欄位的值設定為資料的 BlobKey,以建立文件與特定 Blob 之間的關聯。
建立文件
以下程式碼範例顯示如何建立文件物件。User
類型指定了文件結構,User
值會以一般的方式建構。
使用索引
將文件放入索引
將文件放入索引時,會將文件複製到永久儲存空間,文件的每個欄位都會根據文件名稱、類型與 docID
編入索引。
以下程式碼範例顯示如何存取索引,以及如何將文件放入索引。
將文件放入索引,且索引已包含相同 docID
的文件時,新文件會取代舊文件。系統不會提出任何警告。您可以在建立或將文件新增至索引之前,呼叫
Index.Get
,檢查特定 docID
是否已存在。
Put
方法會傳回 docID
。如果您本身並未指定 docID
,則可檢查結果來探索產生的 docID
:
請注意,建立 Index
類型的執行個體並不會保證永久索引確實存在。在您第一次使用 put
方法將文件加入永久索引時,就會建立永久索引。
更新文件
當您將文件加入索引之後,就無法變更文件。您無法新增或移除欄位,也無法變更欄位的值。但是,您可以用 docID
相同的新文件取代舊文件。
按 docID 擷取文件
使用 Index.Get
方法,依 docID
從索引中擷取文件:
按文件內容搜尋文件
如要從索引中擷取文件,您可以建構查詢字串並呼叫 Index.Search
。
Search
會傳回迭代器,以遞減排名產生相符的文件。
刪除索引
每個索引都包含索引文件和索引結構定義。如要刪除索引,請先刪除索引中的所有文件,然後再刪除索引結構定義。
您可以將想要刪除的文件 docID
指定給 Index.Delete
方法,藉此從索引中刪除文件。
如果需要刪除大量搜尋索引項目,這個方法可能需要很長時間。如要解決這個問題,請嘗試下列方法:
- 刪除專案及其依附元件。
- 要求提高配額,加快刪除速度。
最終一致性
在索引中放置、更新或刪除文件時,變更會傳播至多個資料中心。這通常很快就會發生,但花費的時間各異。Search API 可以保證最終一致性。這表示在某些情況下,搜尋或擷取一或多份文件可能會傳回不會反映最近變更的結果。
索引結構定義
每個索引都有一個結構定義,其中顯示該索引所含文件中出現的所有欄位名稱和欄位類型。您無法自行定義結構定義。 結構定義會以動態方式維護,並於文件新增至索引時更新。一個簡單的結構定義可能如下所示,採用類似 JSON 的格式:
{'comment': ['TEXT'], 'date': ['DATE'], 'author': ['TEXT'], 'count': ['NUMBER']}
字典中的每個鍵值都是文件欄位的名稱。鍵值是與該欄位名稱搭配使用的欄位類型清單。如果您將相同的欄位名稱用於不同的欄位類型,結構定義將會為欄位名稱列出一個以上的欄位類型,如下所示:
{'ambiguous-integer': ['TEXT', 'NUMBER', 'ATOM']}
欄位出現在結構定義中之後,就再也無法移除。即使索引不再包含具有特定欄位名稱的任何文件,也沒有辦法刪除該欄位。
結構定義不會以物件程式設計的方式定義「類別」。只要與 Search API 有關,每份文件就不會重複,且索引可以包含不同種類的文件。如果您要將欄位清單相同的物件集合當成類別的執行個體處理,那就必須在您的程式碼中強制執行這樣的概念。例如,您可以確保具有同一組欄位的所有文件都保存在各自的索引中。索引結構定義可以視為類別定義,而索引中的每份文件都會是類別的執行個體。
在 Google Cloud 控制台中查看索引
在 Google Cloud 控制台中,您可以查看應用程式索引及該索引所含文件的相關資訊。 按一下索引名稱,即會顯示索引包含的文件。您可以看到該索引的所有已定義的結構定義欄位;如果文件中有一個欄位使用該名稱,您就會看見欄位的值。您也可以直接從主控台對索引資料發出查詢。
Search API 配額
Search API 提供多項免費配額:
資源或 API 呼叫 | 免費配額 |
---|---|
總儲存空間 (文件與索引) | 0.25 GB |
查詢 | 每日 1000 次查詢 |
新增文件至索引 | 每日 0.01 GB |
為確保服務可靠性,Search API 有下列限制。這些限制同時適用於免費與付費應用程式:
資源 | 安全配額 |
---|---|
配額使用量上限 | 每分鐘的匯總查詢執行時間上限為 100 分鐘 |
新增或刪除的文件數量上限 | 每分鐘 15,000 個 |
每個索引的大小上限 (允許的索引數不限) | 10 GB |
根據呼叫類型而定,API 使用量會以不同的方式計算:
Index.Search
:每次 API 呼叫都會計為單次查詢;執行時間等於呼叫的延遲時間。Index.Put
:將文件新增至索引時,每份文件的大小與文件數量都會計入索引配額。- 其他所有 Search API 呼叫都會根據呼叫涉及的作業數量計算:
Index.Get
:實際傳回的每份文件會計為 1 次作業,如果沒有傳回文件也會計為 1 次作業。Index.Delete
:要求中的每份文件會計為 1 次作業,如果要求為空也會計為 1 次作業。
系統設下了查詢總處理量的配額,如此一來,單一使用者就無法獨佔搜尋服務。由於查詢可以同時執行,因此在實際的每一分鐘裡,每個應用程式所能執行的查詢最多只能耗用 100 分鐘的執行時間。如果您正在執行許多短查詢,可能不會達到這個限制。當您超出配額時,在到達下一個時間配量而使您的配額復原之前,後續查詢將會失敗。配額不會在一分鐘的配量中嚴格執行;系統會使用經過變化的漏桶演算法,控制以五秒鐘為單位遞增的搜尋頻寬。
如要進一步瞭解配額,請參閱配額頁面。如果應用程式嘗試超出這些額度,系統會傳回配額不足的錯誤。
請注意,雖然上述限制均以分鐘為計算單位,不過主控台中顯示的是各項限制的每日總額。客戶如有選用白銀級、爍金級或白金級支援服務,可與支援代表聯絡,申請提高總處理量限制。
Search API 計價方式
超出免費配額的用量會產生下列費用:
資源 | 費用 |
---|---|
總儲存空間 (文件與索引) | 每月每 GB $0.18 美元 |
查詢 | 每 10 萬筆查詢 $ 0.50 美元 |
將可供搜尋的文件編入索引 | 每 GB $2.00 美元 |
如要進一步瞭解定價資訊,請參閱定價頁面。