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」等字串)。「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
:實際傳回的每份文件會計為一次作業;如果沒有傳回文件,也會計為一次作業。Index.Delete
:要求中的每份文件會計為一次作業;如果要求為空,也會計為一次作業。
系統設下了查詢總處理量的配額,如此一來,單一使用者就無法獨佔搜尋服務。由於查詢可以同時執行,因此在實際的每一分鐘裡,每個應用程式所能執行的查詢最多只能耗用 100 分鐘的執行時間。如果您正在執行許多短查詢,可能不會達到這個限制。當您超出配額時,在到達下一個時間配量而使您的配額復原之前,後續查詢將會失敗。配額不會在一分鐘的配量中嚴格執行;系統會使用經過變化的漏桶演算法,控制以五秒鐘為單位遞增的搜尋頻寬。
如要進一步瞭解配額,請參閱配額頁面。如果應用程式嘗試超出這些額度,系統會傳回配額不足的錯誤。
請注意,雖然上述限制均以分鐘為計算單位,不過主控台中顯示的是各項限制的每日總額。客戶如有選用白銀級、爍金級或白金級支援服務,可與支援代表聯絡,申請提高總處理量限制。
Search API 計價方式
超出免費配額的用量會產生下列費用:
資源 | 費用 |
---|---|
總儲存空間 (文件與索引) | 每月每 GB $0.18 美元 |
查詢 | 每 10 萬筆查詢 $ 0.50 美元 |
將可供搜尋的文件編入索引 | 每 GB $2.00 美元 |
如要進一步瞭解定價資訊,請參閱定價頁面。