本页介绍了 SEARCH
函数和增强型查询模式,它们用于对 Spanner 表执行全文搜索查询。
查询搜索索引
Spanner 提供了 SEARCH
函数,供搜索索引查询使用。示例用例是,用户在搜索框中输入文本,应用将用户输入的内容直接发送到 SEARCH
函数。然后,“SEARCH”函数会使用搜索索引查找该文本。
SEARCH
函数需要两个参数:
- 搜索索引名称
- 搜索查询
SEARCH
函数仅在定义搜索索引后才会起作用。SEARCH
函数可与任何任意 SQL 结构(例如过滤器、汇总或联接)结合使用。
SEARCH
函数不能与事务查询一起使用。
以下查询使用 SEARCH
函数返回标题中包含 friday
或 monday
的所有专辑:
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'friday OR monday')
搜索查询
搜索查询默认使用原始搜索查询语法。您可以使用 dialect
实参指定其他语法。
rquery 方言
默认方言为原始搜索查询。Spanner 使用一种称为 rquery 的特定领域语言 (DSL)。
在将输入搜索查询拆分为不同的字词时,rquery 语言遵循与纯文本分词器相同的规则。这包括亚洲语言细分。
如需了解如何使用 rquery,请参阅 rquery 语法。
字词方言
词语方言类似于 rquery,但更简单。它不使用任何特殊运算符。例如,系统会将 OR
视为搜索字词,而不是析取运算符。系统会将双引号视为标点符号,而不是字词搜索,并将其忽略。
对于词方言,AND
会隐式应用于所有字词,并且在匹配期间是必需的。在将输入的搜索查询拆分为字词时,它遵循与纯文本分词器相同的规则。
如需了解如何使用 words 方言,请参阅 words 语法。
words_phrase 方言
words_phrase 方言不使用任何特殊运算符,并且所有字词都被视为词组,这意味着字词必须相邻且按指定顺序排列。
与 rquery 一样,在将输入搜索查询拆分为字词时,words_phrase 方言遵循与纯文本分词器相同的规则。
如需了解如何使用 words_phrase 方言,请参阅词组语法。
增强型查询模式
Spanner 提供两种全文搜索模式:一种是基于令牌的基本搜索,另一种是名为 enhance_query
的更高级别的搜索。启用后,enhance_query
会扩展搜索查询,以包含相关字词和同义词,从而提高找到相关结果的可能性。
如需启用此选项,请在 SEARCH
函数中设置可选参数 enhance_query=>true
。例如,搜索查询 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
函数要查找的字词数量可能会增加,这可能会略微增加延迟时间。
例如,以下查询使用 3 秒的超时设置,如果 enhance_query
不可用,则会失败:
@{require_enhance_query=true, enhance_query_timeout_ms=3000}
SELECT AlbumId
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, 'fast car', enhance_query=>true)
如需详细了解如何使用 enhance_query
选项,请参阅 SEARCH 函数。
SQL 查询要求
SQL 查询必须满足多项条件才能使用搜索索引。如果不满足这些条件,则查询会使用备选查询计划,如果没有备选计划,则会失败。
查询必须满足以下条件:
SEARCH
和SEARCH_SUBSTRING
函数需要搜索索引。Spanner 不支持对基表或二级索引进行查询时使用这些函数。分区索引中的所有分区列都必须由查询的
WHERE
子句中的等式条件所约束。例如,如果搜索索引定义为
PARTITION BY x, y
,则查询必须在x = <parameter or constant> AND y = <parameter or constant>
的WHERE
子句中包含析取运算。如果缺少此类条件,查询优化器将不会考虑该搜索索引。SEARCH
和SEARCH_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_Tokens
和AlbumStudio_Tokens
进行编制索引:SELECT AlbumId FROM Albums WHERE SEARCH(AlbumTitle_Tokens, @p1) AND SEARCH(AlbumStudio_Tokens, @p2)
如果排序顺序列可为 null,则架构和查询都必须排除排序顺序列为 null 的行。如需了解详情,请参阅搜索索引排序顺序。
如果搜索索引采用了 NULL 过滤,则查询必须包含与索引中使用的 NULL 过滤表达式相同的表达式。如需了解详情,请参阅已过滤 null 的搜索索引。
搜索索引和搜索函数通常用于只读事务。如果应用要求允许使用过时结果,我们建议运行搜索查询时,过时时长应至少为 10 秒。如需了解详情,请参阅读取过时数据。这对于分散到多个 Paxos 组的大型搜索查询特别有用。
不建议在读写事务中使用搜索索引和搜索函数。在执行期间,搜索查询会锁定整个索引分区;因此,读写事务中的搜索查询速率过高可能会导致锁争用,进而导致延迟时间激增。默认情况下,系统不会在读写事务中自动选择搜索索引。如果在读写事务中强制使用搜索索引,查询默认会失败。如果查询包含任何搜索函数,也会失败。可以使用
@{ALLOW_SEARCH_INDEXES_IN_TRANSACTION=TRUE}
语句级提示来覆盖此行为(但查询仍容易发生锁争用)。
满足索引使用条件后,查询优化器会尝试加速非文本查询条件(例如 Rating > 4
)。如果搜索索引不包含适当的 TOKENLIST
列,则该条件不会加速,并保持为残留条件。
查询参数
搜索查询参数可以指定为字面量或查询参数。当参数允许使用查询参数值时,我们建议您使用查询参数进行全文搜索,而不是使用字符串字面量。
索引选择
Spanner 通常会使用基于成本的建模方法为查询选择最有效的索引。不过,FORCE_INDEX
提示会明确指示 Spanner 使用特定的搜索索引。例如,以下代码展示了如何强制 Spanner 使用 AlbumsIndex
:
SELECT AlbumId
FROM Albums @{FORCE_INDEX=AlbumsIndex}
WHERE SEARCH(AlbumTitle_Tokens, "fifth symphony")
如果指定的搜索索引不符合条件,则查询会失败,即使有其他符合条件的搜索索引也是如此。
搜索结果中的摘要
摘要是从给定字符串中提取的一段文本,可让用户大致了解搜索结果的内容以及该结果与其查询相关的原因。
例如,Gmail 会使用摘要来指明电子邮件中与搜索查询匹配的部分:
让数据库生成摘要有以下几个好处:
- 便捷:您无需实现逻辑即可根据搜索查询生成摘要。
- 效率:代码段可缩减服务器的输出大小。
SNIPPET
函数会创建该代码段。它会返回原始字符串值的相关部分,以及要突出显示的字符的位置。然后,客户端可以选择如何向最终用户显示摘要(例如,使用突出显示或粗体文本)。SNIPPET
函数会从原始字符串中移除所有 HTML 标记。
例如,以下代码使用 SNIPPET
从 AlbumTitle
检索文本:
SELECT AlbumId, SNIPPET(AlbumTitle, "Fast Car")
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "Fast Car")
后续步骤
- 了解如何对搜索结果进行排名。
- 了解如何执行子字符串搜索。
- 了解如何对搜索结果进行分页。
- 了解如何混合使用全文查询和非文本查询。
- 了解如何搜索多个列。