查询概览

本页面介绍了 SEARCH 函数和增强型查询模式,它们分别是 用于执行全文搜索 查询。

查询搜索索引

Spanner 为搜索索引查询提供了 SEARCH 函数。SEARCH 函数需要两个参数:

  • 搜索索引名称
  • rquery

SEARCH 函数仅在定义搜索索引时有效。SEARCH 函数可与任意 SQL 结构组合,例如过滤器、 聚合或联接。

以下查询使用 SEARCH 函数返回包含 fridaymonday

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'friday OR monday')

rquery 语言

SEARCH 函数的第二个参数是网域专用语言 (DSL) 名为 rquery 的查询。Rquery 使用的语言与互联网用户的语言类似, 习惯于在 google.com 上使用:

  • 多个字词意味着 AND。例如,“Big Time”等同于 big AND time
  • OR 运算表示两个项之间的析取,例如 big OR time。语句 SEARCH(tl, 'big time OR fast car') 相当于:

    SEARCH(tl, 'big')
    AND (SEARCH(tl, 'time')
         OR SEARCH(tl, 'fast'))
    AND SEARCH(tl, 'cat');
    

    OR 仅适用于两个相邻的字词。例如,搜索 表达式 happy friday OR monday 搜索符合以下条件的所有文档: 字词 happy 以及字词 fridaymonday

  • 双引号表示词组搜索。例如,rquery "big cat" 会匹配“I have a big cat”,但与“My cat is big”不匹配。

  • AROUND 运算符匹配特定字词之间 相互交流。例如,rquery big AROUND cat 与“big, white, and ”,但与“大狗坐在小猫旁边”不匹配。 默认设置是匹配最多间隔五个位置的字词。接收者 调整距离,向 AROUND 运算符传递一个实参。 Spanner 支持两种 AROUND 语法:

    • big AROUND(10) cat
    • big AROUND 10 cat
  • AROUND 运算符在词组中用作短语时,可以匹配符合以下条件的字词: 彼此在一定的距离内,且按相同的顺序(即 默认为五个词元)。例如,字符串 big AROUND cat 与 “big white and foffy cat”,而不是“cat was big”。

  • 单个词法单元的否定以短划线 (-) 表示。例如 -dog 会匹配不包含字词 dog 的所有文档。

  • 标点符号通常会被忽略。例如,“大时间!”等同于 “Big Time”。

  • 搜索不区分大小写。例如,“Big Time”与“big time”相匹配。

  • The ORAROUND 运算符区分大小写。竖线字符 (|) 是 OR 的快捷方式。

rquery 语言的工作原理

rquery 语言遵循的规则与 纯文本标记生成器 。包括细分 亚洲语言。

许多应用程序为用户提供了在 搜索框。集成此类最终用户查询的最简单方法是将 SEARCH 函数。

下表介绍了各种 rquery 字符串的含义:

rquery 说明
Big Cat 匹配同时包含“big”和“cat”这两个字词的文档。
cat OR dog 匹配包含至少一个字词“cat”的文档和“dog”
-cat 匹配所有不包含字词“cat”的文档。
"big dog" -"big cat" 匹配包含两个相邻字词“big”的文档和“dog” 但不包含相邻的“big”和“cat”。例如,下面的查询 与“I have a big dog and a small cat”匹配,但不匹配“I have 一只大狗和一只大猫”。
cat|dog 这个指令与“cat OR dog”相同。
and OR or 匹配包含字词“and”的文档或字词“或” (OR 运算符必须大写)

增强型查询模式

除了完全基于词元的全文搜索外,Spanner 支持名为 enhance_query 的更丰富的模式。启用后,此模式会扩展 搜索查询以添加更多词元变体。这些改写提高了搜索次数 召回率。

要启用此选项,请设置可选参数 enhance_query=>trueSEARCH 函数。例如,搜索查询 hotl cal 与专辑匹配 Hotel California

SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'hotl cal', enhance_query=>true)

enhance_query 模式是一个查询时选项。而不会影响标记化。 无论是否使用 enhance_query,您都可以使用相同的搜索索引。

Google 一直在不断改进查询增强算法。作为 因此,使用 enhance_query == true 的查询产生的结果可能会略有不同 结果随时间的变化情况...

启用 enhance_query 模式后,可能会增加字词数量 SEARCH 函数所查找的值,可能会导致 延迟时间

例如,以下查询使用三秒超时,如果 enhance_query不可用:

@{require_enhance_query=true, enhance_query_timeout_ms=3000}
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'cat', enhance_query=>true)

SQL 查询要求

SQL 查询必须满足几个条件才能使用搜索索引。 如果不满足这些条件,查询会使用备用查询计划 还是在没有替代方案时失败

查询必须满足以下条件:

  • SEARCHSEARCH_SUBSTRING 函数需要搜索索引。Spanner 不支持在查询 基表或二级索引。查询依据
  • 分区索引 必须在 查询的 WHERE 子句。

    例如,如果搜索索引定义为 PARTITION BY x, y,则查询必须在 x = <parameter or constant> AND y = <parameter or constant>WHERE 子句中包含析取运算。该搜索索引 查询优化器会考虑的结果。

  • SEARCHSEARCH_SUBSTRING 引用的所有 TOKENLIST 列 运算符必须在同一搜索索引中编入索引。

    以下面的表和索引定义为例:

    CREATE TABLE Albums (
        AlbumId STRING(MAX) NOT NULL,
        AlbumTitle STRING(MAX),
        AlbumStudio STRING(MAX),
        AlbumTitle_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumTitle)) HIDDEN,
        AlbumStudio_Tokens TOKENLIST AS (TOKENIZE_FULLTEXT(AlbumStudio)) HIDDEN
      ) PRIMARY KEY(AlbumId);
    
      CREATE SEARCH INDEX AlbumsTitleIndex ON Albums(AlbumTitle_Tokens);
      CREATE SEARCH INDEX AlbumsStudioIndex ON Albums(AlbumStudio_Tokens);
    

    以下查询会失败,因为没有单个搜索索引同时对 AlbumTitle_TokensAlbumStudio_Tokens 进行编制索引:

    SELECT AlbumId
    FROM Albums
    WHERE SEARCH(AlbumTitle_Tokens, @p1) AND SEARCH(AlbumStudio_Tokens, @p2)
    
  • 如果排序顺序列可以为 Null,则架构和查询都必须 排除排序顺序列为 NULL 的行。请参阅 搜索索引排序顺序 了解详情。

  • 如果搜索索引按 NULL 过滤,则查询必须包含相同的 索引中使用的 NULL 过滤表达式。请参阅过滤 NULL 的搜索 索引 了解详情。

  • DML、分区 DML 和分区 DML 不支持搜索索引 查询 。

  • 搜索索引通常用于 只读事务。 如果应用要求允许过时的结果,我们建议运行搜索 过时时长不少于 10 秒的查询。如需了解详情,请参阅读取过时数据。这是 特别适用于扇出到多个 Paxos 的大型搜索查询 群组。

    以下国家/地区不推荐使用搜索索引: 读写事务。 执行期间,搜索查询会锁定整个索引分区;以 那么读写事务中的搜索查询频率较高可能会导致 锁定冲突,从而导致延迟时间急剧增加。默认情况下,搜索索引 将在读写事务中自动选中如果查询被强制 在读写事务中使用搜索索引会默认失败。这个 可以替换为 @{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE} 语句级提示(但是 查询仍然容易发生锁冲突)。

在满足索引条件后,查询优化器会尝试 加快非文本查询条件(例如 Rating > 4)。如果搜索索引 未包含相应的 TOKENLIST 列,则条件不符合 加速并保持残差状态

查询参数

rquery 和其他参数(如 OFFSET)可指定为字面量或 查询参数。 我们建议使用查询参数,而不是字符串字面量。参数化 查询具有更好的查询 缓存命中率,这导致 并降低整体 CPU 使用率。

例如,不要使用如下查询:

SELECT AlbumId FROM Albums WHERE SEARCH(AlbumTitle_Tokens, 'cat')

请使用以下语法:

SELECT AlbumId FROM Albums WHERE SEARCH(AlbumTitle_Tokens, @p)

Spanner 会对不同的 SQL 文本运行查询优化器。越少, 应用使用的不同 SQL 文本,查询 。

搜索索引排序顺序

搜索索引的排列顺序行为与次要操作不同 索引

例如,请参考下表:

CREATE TABLE Albums (
  AlbumId STRING(MAX) NOT NULL,
  ReleaseTimestamp INT64 NOT NULL,
  AlbumName STRING(MAX),
  AlbumName_Token TOKENLIST AS (TOKEN(AlbumName)) HIDDEN
) PRIMARY KEY(AlbumId);

应用可以定义二级索引,以便使用 AlbumNameReleaseTimestamp排序:

CREATE INDEX AlbumsSecondaryIndex ON Albums(AlbumName, ReleaseTimestamp DESC);

等效的搜索索引如下所示(由于二级索引不支持全文搜索,因此此索引使用完全匹配的令牌化):

CREATE SEARCH INDEX AlbumsSearchIndex
ON Albums(AlbumName_Token)
ORDER BY ReleaseTimestamp DESC;

搜索索引的排序顺序必须符合以下规则:

  1. 仅使用 INT64 列进行排序 搜索索引的顺序。具有任意大小的列使用的数量过多 搜索索引上的资源,因为 Spanner 需要 每个令牌旁的文档 ID。具体而言,排序顺序列不能使用 TIMESTAMP 类型,因为 TIMESTAMP 使用纳秒精度, 超出了 64 位整数。
  2. 排序列不得为 NULL。有两种方法可以满足 要求:

    1. 将排序顺序列声明为 NOT NULL
    2. 将索引配置为排除 NULL 值

在实践中,时间戳通常用于确定排序顺序。常见 使用微秒(相对于 Unix epoch

应用通常会先使用 已按降序排序。

索引选择

Spanner 通常会使用基于成本的建模方法为查询选择最有效的索引。不过,FORCE_INDEX 提示会明确指示 Spanner 使用特定搜索索引。例如, 下面展示了如何强制 Spanner 使用 AlbumsIndex

SELECT AlbumId
FROM Albums @{FORCE_INDEX=AlbumsIndex}
WHERE SEARCH(AlbumTitle_Tokens, @p1)

如果指定的搜索索引不符合条件, 查询会失败,即使存在其他符合条件的搜索索引也是如此。

搜索结果中的代码段

摘要是从给定字符串中提取的一小段文本, 让用户能大致了解搜索结果的内容以及 与用户查询的内容相关。

例如,Gmail 会使用摘要来指明电子邮件中 与搜索查询匹配:

摘要列表

让数据库生成代码段有诸多好处:

  1. 便利:无需实现逻辑即可生成代码段 。
  2. 效率:代码段可减小服务器的输出大小。

SNIPPET 函数会创建该代码段。它会返回 原始字符串值以及要突出显示的字符的位置。通过 然后,客户可以选择如何向最终用户显示摘要(例如, 使用突出显示或粗体文字)。SNIPPET 函数会从原始字符串中移除所有 HTML 标记。

例如,以下代码使用 SNIPPETAlbumTitle 检索文本:

SELECT AlbumId, SNIPPET(AlbumTitle, "Fast Car")
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "Fast Car")

后续步骤