组合 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

以下示例会对每个字词进行标记化,并串联 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_CONCATSpanner 不允许您在同一 TOKENLIST_CONCAT 调用中混用令牌化类型,例如 TOKENIZE_FULLTEXTTOKENIZE_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 的发布列表中。在查询端串联 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);

以下查询会搜索 TitleStudio 列中任意位置包含“blue”和“note”标记的行。这包括 Title 列和 Studio 列中同时包含“blue”和“note”的行,以及 Title 列中包含“blue”且 Studio 列中包含“note”的行,或相反的情况。

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

写入端和查询端 TOKENLIST 串联会产生相同的结果。在二者之间进行选择时,需要权衡磁盘费用和查询费用。

或者,应用也可以搜索多个 TOKENLIST 列,并将 ORSEARCH 函数搭配使用:

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

不过,这具有不同的语义。它不会与 AlbumTitle_Tokens 包含“blue”但不包含“note”,Studio_Tokens 包含“note”但不包含“blue”的专辑匹配。

后续步骤