本页面介绍了 SEARCH
函数和增强型查询模式,它们分别是
用于执行全文搜索
查询。
查询搜索索引
Spanner 为搜索索引查询提供了 SEARCH
函数。SEARCH
函数需要两个参数:
- 搜索索引名称
- rquery
SEARCH
函数仅在定义搜索索引时有效。SEARCH
函数可与任意 SQL 结构组合,例如过滤器、
聚合或联接。
以下查询使用 SEARCH
函数返回包含
friday
或 monday
:
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
以及字词friday
或monday
。双引号表示词组搜索。例如,rquery
"big cat"
会匹配“I have a big cat”,但与“My cat is big”不匹配。AROUND
运算符匹配特定字词之间 相互交流。例如,rquerybig 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 OR
和AROUND
运算符区分大小写。竖线字符 (|
) 是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=>true
,
SEARCH
函数。例如,搜索查询 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 查询必须满足几个条件才能使用搜索索引。 如果不满足这些条件,查询会使用备用查询计划 还是在没有替代方案时失败
查询必须满足以下条件:
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 的搜索 索引 了解详情。
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);
应用可以定义二级索引,以便使用
AlbumName
按ReleaseTimestamp
排序:
CREATE INDEX AlbumsSecondaryIndex ON Albums(AlbumName, ReleaseTimestamp DESC);
等效的搜索索引如下所示(由于二级索引不支持全文搜索,因此此索引使用完全匹配的令牌化):
CREATE SEARCH INDEX AlbumsSearchIndex
ON Albums(AlbumName_Token)
ORDER BY ReleaseTimestamp DESC;
搜索索引的排序顺序必须符合以下规则:
- 仅使用
INT64
列进行排序 搜索索引的顺序。具有任意大小的列使用的数量过多 搜索索引上的资源,因为 Spanner 需要 每个令牌旁的文档 ID。具体而言,排序顺序列不能使用TIMESTAMP
类型,因为TIMESTAMP
使用纳秒精度, 超出了 64 位整数。 排序列不得为
NULL
。有两种方法可以满足 要求:- 将排序顺序列声明为
NOT NULL
。 - 将索引配置为排除 NULL 值。
- 将排序顺序列声明为
在实践中,时间戳通常用于确定排序顺序。常见 使用微秒(相对于 Unix epoch。
应用通常会先使用 已按降序排序。
索引选择
Spanner 通常会使用基于成本的建模方法为查询选择最有效的索引。不过,FORCE_INDEX
提示会明确指示
Spanner 使用特定搜索索引。例如,
下面展示了如何强制 Spanner 使用 AlbumsIndex
:
SELECT AlbumId
FROM Albums @{FORCE_INDEX=AlbumsIndex}
WHERE SEARCH(AlbumTitle_Tokens, @p1)
如果指定的搜索索引不符合条件, 查询会失败,即使存在其他符合条件的搜索索引也是如此。
搜索结果中的代码段
摘要是从给定字符串中提取的一小段文本, 让用户能大致了解搜索结果的内容以及 与用户查询的内容相关。
例如,Gmail 会使用摘要来指明电子邮件中 与搜索查询匹配:
让数据库生成代码段有诸多好处:
- 便利:无需实现逻辑即可生成代码段 。
- 效率:代码段可减小服务器的输出大小。
SNIPPET
函数会创建该代码段。它会返回
原始字符串值以及要突出显示的字符的位置。通过
然后,客户可以选择如何向最终用户显示摘要(例如,
使用突出显示或粗体文字)。SNIPPET
函数会从原始字符串中移除所有 HTML 标记。
例如,以下代码使用 SNIPPET
从 AlbumTitle
检索文本:
SELECT AlbumId, SNIPPET(AlbumTitle, "Fast Car")
FROM Albums
WHERE SEARCH(AlbumTitle_Tokens, "Fast Car")
后续步骤
- 了解如何对搜索结果进行排名。
- 了解如何执行子字符串搜索。
- 了解如何对搜索结果进行分页。
- 了解如何混合全文和非文本查询。
- 了解如何搜索多个列。