このページでは、検索インデックスでスキーマを設定するときに、または Spanner で全文検索を実行するときに検索クエリで TOKENLIST
を連結する方法について説明します。
検索インデックス内の TOKENLIST を結合する
アプリケーションで個別のフィールドを検索することが必要な場合もあります。一方で、アプリケーションはすべてのフィールドを検索する必要があります。たとえば、2 つの文字列列を含むテーブルで、一致がどの列から取得されたかを区別せずに、両方の列を検索するようにアプリケーションを設定できます。
Spanner では、これを実現する方法は 2 つあります。
2 つ目のアプローチには、次の 2 つの問題があります。
Title
またはStudio
を個別にインデックスに登録する場合、TOKENLIST
に結合してインデックスに登録するだけでなく、同じテキストが 2 回トークン化されます。これにより、トランザクションでより多くのリソースが使用されます。- フレーズ検索は両方のフィールドにわたって行われます。たとえば、
@p
が"Blue Note"
に設定されている場合、Title
="Big Blue Note" とStudio
="Blue Note Studios" の両方を含む行が照合されます。
最初の方法では、フレーズが 1 つのフィールドにのみ一致し、個別および結合された TOKENLIST
の両方がインデックスに登録されている場合に、各文字列フィールドが 1 回のみトークン化されるため、これらの問題は解決されます。各文字列フィールドは 1 回だけトークン化されますが、生成された TOKENLIST はインデックスに個別に保存されます。
単語を個別にトークン化し、TOKENLIST
値を連結する
次の例では、各単語をトークン化し、TOKENLIST
値を連結します。
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);
TOKENLIST
の連結は、クエリ側で完全に実装することもできます。詳細については、クエリサイドの TOKENLIST
の連結をご覧ください。
TOKENLIST_CONCAT
は、全文検索と部分文字列検索の両方でサポートされています。Spanner では、同じ TOKENLIST_CONCAT
呼び出しでトークン化タイプ(TOKENIZE_FULLTEXT
や TOKENIZE_SUBSTRING
など)を混在させることはできません。
テキスト TOKENLIST
列の定義は保存されていない列で変更することができ、列を追加することができます。これは、TOKENLIST_CONCAT
に列を追加する場合に便利です。生成された列の式を変更しても、インデックス内の既存の行はバックフィルされません。
文字列を連結して結果をトークン化する
次の例では、文字列を連結して結果をトークン化します。
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);
クエリ側の TOKENLIST
連結
連結された TOKENLIST
にインデックスを付けると、ストレージと書き込みのコストが増加します。各トークンは、元の TOKENLIST
の投稿リストと、結合された TOKENLIST
の投稿リストの 2 か所にディスクに保存されます。TOKENLIST
列のクエリサイドの連結ではこの費用を回避できますが、クエリで使用するコンピューティング リソースが増加します。
複数の TOKENLIST
を連結するには、SEARCH
クエリで TOKENLIST_CONCAT
関数を使用します。このセクションでは、次のサンプル スキーマを使用します。
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);
次のクエリは、Title
列と Studio
列の任意の場所にあるトークン「blue」と「note」を含む行を検索します。この検索結果では、Title
列に「blue」と「note」の両方、Studio
列に「blue」と「note」の両方、Title
列に「blue」、Studio
列に「note」、またはその逆が含まれます。
SELECT AlbumId
FROM Albums
WHERE SEARCH(TOKENLIST_CONCAT([AlbumTitle_Tokens, Studio_Tokens]), 'blue note')
書き込み側とクエリ側の TOKENLIST
の連結は同じ結果になります。2 つのうちどちらを選択するかは、ディスク費用とクエリ費用の間のトレードオフとなります。
または、アプリケーションで複数の TOKENLIST
列を検索し、SEARCH
関数とともに OR
を使用することもできます。
SEARCH(AlbumTitle_Tokens, 'Blue Note') OR SEARCH(Studio_Tokens, 'Blue Note')
ただし、これには異なるセマンティクスが存在します。AlbumTitle_Tokens
に「blue」が含まれていて「note」が含まれていない場合、さらに、Studio_Tokens
に「note」が含まれていて「blue」が含まれていない場合は、アルバムは一致しません。