合併 TOKENLIST

本頁面說明如何在設定結構描述時,在搜尋索引中連結 TOKENLIST,或是在 Spanner 中執行全文搜尋時,在搜尋查詢中連結 TOKENLIST

在搜尋索引中合併 TOKENLIST

有時,您需要讓應用程式搜尋個別欄位。在其他情況下,應用程式需要搜尋所有欄位。舉例來說,在包含兩個字串欄的表格中,您可能會希望應用程式在兩個欄中搜尋,而不區分相符項目來自哪個欄。

在 Spanner 中,有兩種方法可以達成這項目標:

  1. 將字詞分開進行符記化,並連結產生的 TOKENLIST (建議)。
  2. 將字串連接起來,並將結果切割成符號

採用第二種方法時,會出現兩個問題:

  1. 如果您想個別為 TitleStudio 建立索引,除了在合併的 TOKENLIST 中為其建立索引外,還會將相同的文字切割成兩個字元。這會導致交易使用更多資源。
  2. 詞組搜尋會跨越兩個欄位。舉例來說,如果 @p 設為 "Blue Note",則會比對列中同時包含 Title="Big Blue Note" 和 Studio="Blue Note Studios" 的資料。

第一種方法可解決這些問題,因為如果個別和組合 TOKENLIST 都已編入索引,則片語只會比對一個欄位,而每個字串欄位只會剖析一次。雖然每個字串欄位只會剖析一次,但產生的 TOKENLIST 會分別儲存在索引中。

個別符記化字詞,並連結 TOKENLIST

以下範例會將每個字詞切割成子字串,並使用 TOKENLIST_CONCAT 連接 TOKENLIST

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Studio STRING(MAX),
  Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
  Studio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Studio)) HIDDEN,
  Combined_Tokens TOKENLIST AS (TOKENLIST_CONCAT([Title_Tokens, Studio_Tokens])) HIDDEN,
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(Combined_Tokens);

SELECT AlbumId FROM Albums WHERE SEARCH(Combined_Tokens, @p);

PostgreSQL

PostgreSQL 會使用 spanner.tokenlist_concat 進行連接。查詢參數 $1 已繫結至「Hatel Kaliphorn」。

CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  studio character varying,
  title_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
  studio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(studio)) VIRTUAL HIDDEN,
  combined_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenlist_concat(ARRAY[spanner.tokenize_fulltext(title), spanner.tokenize_fulltext(studio)])) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(combined_tokens);

SELECT albumid FROM albums WHERE spanner.search(combined_tokens, $1);

請注意,tokenlist_concat 不會呼叫 title_tokensstudio_tokens,而是會呼叫 spanner.tokenize_fulltext(title)spanner.tokenize_fulltext(studio)。這是因為 PostgreSQL 不支援參照位於其他產生欄中的產生欄。spanner.tokenlist_concat 需要呼叫剖析函式,而非直接參照符記清單欄。

TOKENLIST 串接作業也可以完全在查詢端實作。詳情請參閱「查詢端 TOKENLIST 連結」。

TOKENLIST_CONCAT 支援全文和子字串搜尋。Spanner 不允許您在同一個 TOKENLIST_CONCAT 呼叫中混用符記類型,例如 TOKENIZE_FULLTEXTTOKENIZE_SUBSTRING

在 GoogleSQL 中,您可以在未儲存的資料欄中變更文字 TOKENLIST 欄的定義,以便新增其他資料欄。如要為 TOKENLIST_CONCAT 新增額外欄時,這項功能就很實用。變更產生的資料欄運算式不會回填索引中的現有資料列。

連接字串並將結果切割成符元

以下範例會連接字串並將結果切割成符元:

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Studio STRING(MAX),
  Combined_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title || " " || Studio)) HIDDEN,
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(Combined_Tokens);

SELECT AlbumId FROM Albums WHERE SEARCH(Combined_Tokens, @p);

PostgreSQL

CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  studio character varying,
  combined_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title || ' ' || studio)) VIRTUAL HIDDEN,
PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(combined_tokens);

SELECT albumid FROM albums WHERE spanner.search(combined_tokens, $1);

查詢端 TOKENLIST 串連

將連接的 TOKENLIST 建立索引時,所需的儲存空間和寫入成本會增加。每個符記現在會儲存在磁碟上兩次:一次在原始 TOKENLIST 的發布清單中,另一次則在組合 TOKENLIST 的發布清單中。在查詢端串連 TOKENLIST 欄可避免這項費用,但查詢會使用更多運算資源。

如要連接多個 TOKENLIST,請在 SEARCH 查詢中使用 TOKENLIST_CONCAT 函式。在本節中,我們會使用以下結構定義範例:

GoogleSQL

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  Title STRING(MAX),
  Studio STRING(MAX),
  Title_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Title)) HIDDEN,
  Studio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(Studio)) HIDDEN,
) PRIMARY KEY(AlbumId);

CREATE SEARCH INDEX AlbumsIndex ON Albums(Title_Tokens, Studio_Tokens);

PostgreSQL

CREATE TABLE albums (
  albumid character varying NOT NULL,
  title character varying,
  studio character varying,
  title_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(title)) VIRTUAL HIDDEN,
  studio_tokens spanner.tokenlist GENERATED ALWAYS AS (spanner.tokenize_fulltext(studio)) VIRTUAL HIDDEN,
 PRIMARY KEY(albumid));

CREATE SEARCH INDEX albumsindex ON albums(title_tokens, studio_tokens);

以下查詢會搜尋 TitleStudio 資料欄中任何位置含有「blue」和「note」符號的行。這包括資料列在 Title 欄中同時包含「blue」和「note」、在 Studio 欄中同時包含「blue」和「note」、在 Title 欄中包含「blue」、在 Studio 欄中包含「note」,或相反的情況。

GoogleSQL

SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([AlbumTitle_Tokens, Studio_Tokens]), 'blue note')

PostgreSQL

本範例使用 spanner.search 搭配 spanner.tokenlist_concat

SELECT albumid
FROM albums
WHERE spanner.search(spanner.tokenlist_concat(ARRAY[albumtitle_tokens, studio_tokens]), 'blue note')

寫入端和查詢端 TOKENLIST 串連會產生相同的結果。這兩種方法的選擇取決於磁碟成本和查詢成本之間的權衡。

或者,應用程式可以搜尋多個 TOKENLIST 欄,並使用 OR 搭配 SEARCH 函式:

GoogleSQL

SEARCH(AlbumTitle_Tokens, 'Blue Note') OR SEARCH(Studio_Tokens, 'Blue Note')

PostgreSQL

spanner.search(albumtitle_tokens, 'Blue Note') OR spanner.search(studio_tokens, 'Blue Note')

不過,這會產生不同的語意。它不會比對 AlbumTitle_Tokens 有「blue」但沒有「note」,而 Studio_Tokens 有「note」但沒有「blue」的專輯。

後續步驟