在前一节中的示例演示了使用简单常数字符串进行全文匹配。本节展示如何搜索表数据,以及可选择地使用索引。
即使没有索引,也可以执行全文搜索。下面这个简单查询会输出每一行的title,其中对应的body字段包含单词friend:
SELECT title
FROM pgweb
WHERE to_tsvector('english', body) @@ to_tsquery('english', 'friend');
这还会找到相关词,例如friends和friendly,因为这些词都会被约简为同一个正规化词位。
上述查询指定使用 english 配置来解析并正规化字符串。我们也可以省略配置参数:
SELECT title
FROM pgweb
WHERE to_tsvector(body) @@ to_tsquery('friend');
该查询将使用由 default_text_search_config 设置的配置。
更复杂一点的例子,是选出最近的 10 个文档,它们的 title 或 body 中同时包含 create 和 table:
SELECT title
FROM pgweb
WHERE to_tsvector(title || ' ' || body) @@ to_tsquery('create & table')
ORDER BY last_mod_date DESC
LIMIT 10;
为简洁起见,这里省略了 coalesce 调用;如果希望在这两个字段之一为 NULL 时,另一字段仍能参与搜索,就需要加上它。
虽然这些查询在没有索引的情况下也能工作,但除偶尔的临时搜索外,大多数应用都会觉得这种方式太慢。文本搜索在实际使用中通常都需要建立索引。
我们可以创建一个GIN索引(Section 12.9)来加速文本搜索:
CREATE INDEX pgweb_idx ON pgweb USING GIN(to_tsvector('english', body));
注意这里使用的是to_tsvector的双参数版本。只有显式指定配置名称的文本搜索函数,才能用于表达式索引(Section 11.7)。这是因为索引内容必须不受default_text_search_config的影响。否则,索引内容就可能不一致,因为不同的索引项可能包含使用不同文本搜索配置创建的tsvector,而且无法判断各自使用了哪一种配置。这样的索引也不可能被正确地转储和恢复。
由于上面的索引使用了 to_tsvector 的双参数版本,因此只有同样使用相同配置名的双参数版 to_tsvector 查询,才能使用该索引。也就是说,WHERE to_tsvector('english', body) @@ 'a & b' 可以使用该索引,而 WHERE to_tsvector(body) @@ 'a & b' 则不能。这样可以保证索引只会和创建索引项时所用的同一配置配合使用。
还可以建立更复杂的表达式索引,其中配置名由另一个列指定,例如:
CREATE INDEX pgweb_idx ON pgweb USING GIN(to_tsvector(config_name, body));
这里 config_name 是 pgweb 表中的一个列。这样就允许在同一个索引中混合使用不同配置,同时记录每个索引项使用的是哪一种配置。例如,如果文档集合中包含不同语言的文档,这就会很有用。同样,打算使用该索引的查询也必须写成对应的形式,例如 WHERE to_tsvector(config_name, body) @@ 'a & b'。
索引甚至可以连接列:
CREATE INDEX pgweb_idx ON pgweb USING GIN(to_tsvector('english', title || ' ' || body));
另一种方法是创建一个单独的tsvector列来保存to_tsvector的输出。若要让该列与其源数据自动保持同步,可以使用存储生成列。下面的示例把title和body串接起来,并用coalesce保证其中一个字段为NULL时,另一个字段仍然可以被建立索引:
ALTER TABLE pgweb
ADD COLUMN textsearchable_index_col tsvector
GENERATED ALWAYS AS (to_tsvector('english', coalesce(title, '') || ' ' || coalesce(body, ''))) STORED;
然后我们创建一个GIN索引来加速搜索:
CREATE INDEX textsearch_idx ON pgweb USING GIN(textsearchable_index_col);
现在我们准备好执行一个快速的全文搜索了:
SELECT title
FROM pgweb
WHERE textsearchable_index_col @@ to_tsquery('create & table')
ORDER BY last_mod_date DESC
LIMIT 10;
与表达式索引相比,单独列方法的一个优点是,为了利用索引,查询中不必显式指定文本搜索配置。正如上面的例子所示,查询可以依赖default_text_search_config。另一个优点是搜索会更快,因为它不必重新执行to_tsvector调用来验证索引匹配(使用 GiST 索引时这一点比使用 GIN 索引时更重要;见Section 12.9)。不过,表达式索引方法更容易设置,而且占用更少磁盘空间,因为tsvector表示并没有被显式存储。
如果您发现文档中有不正确的内容、与您使用特定功能的经验不符或需要进一步说明,请使用此表单来报告文档问题。