12.2. 表和索引

上一节中的示例说明了使用简单常量字符串进行的全文匹配。本节说明如何搜索表数据(可选地使用索引)。

12 .2.1. 搜索表

无需索引即可进行全文搜索。一个简单的查询来打印在其body字段中包含单词friend的每一行的title是:

SELECT title
FROM pgweb
WHERE to_tsvector('english', body) @@ to_tsquery('english', 'friend');

这还将找到相关的词,例如friendsfriendly,因为所有这些词都被简化为相同的标准化词素。

上面的查询指定english配置将用于解析和规范化字符串。或者,我们可以省略配置参数:

SELECT title
FROM pgweb
WHERE to_tsvector(body) @@ to_tsquery('friend');

该查询将使用default_text_search_config设置的配置。

一个更复杂的示例是选择titlebody中包含createtable的十个最新文档:

SELECT title
FROM pgweb
WHERE to_tsvector(title || ' ' || body) @@ to_tsquery('create & table')
ORDER BY last_mod_date DESC
LIMIT 10;

为了清楚起见,我们省略了coalesce函数调用,这将需要查找两个字段之一中包含NULL的行。

12 .2.2. 创建索引

我们可以创建一个 GIN 索引(Section 12.9)以加快文本搜索:

CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector('english', body));

请注意,使用了to_tsvector的 2 参数版本。表达式索引(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_namepgweb表中的列。这允许在同一索引中混合使用配置,同时记录每个索引条目所使用的配置。例如,如果文档集合包含不同语言的文档,这将很有用。同样,要使用索引的查询必须用词组匹配,例如WHERE to_tsvector(config_name, body) @@ 'a & b'

索引甚至可以连接列:

CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector('english', title || ' ' || body));

另一种方法是创建一个单独的tsvector列以保存to_tsvector的输出。此示例是titlebody的串联,使用coalesce来确保当另一个字段为NULL时仍对其中一个字段进行索引:

ALTER TABLE pgweb ADD COLUMN textsearchable_index_col tsvector;
UPDATE pgweb SET textsearchable_index_col =
     to_tsvector('english', coalesce(title,'') || ' ' || coalesce(body,''));

然后,我们创建一个 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;

当使用单独的列存储tsvector表示形式时,有必要创建一个触发器,以在titlebody更改时使tsvector列保持最新。 Section 12.4.3说明了如何执行此操作。

分离列方法相对于表达式索引的一个优点是,不必为了使用索引而在查询中显式指定文本搜索配置。如上面的示例所示,查询可以取决于default_text_search_config。另一个优点是搜索将更快,因为不需要重做to_tsvector调用以验证索引匹配。 (这在使用 GiST 索引时比在 GIN 索引中更为重要;请参阅Section 12.9。)expression-index 方法更易于设置,并且由于tsvector表示形式没有显式存储,因此它需要更少的磁盘空间。