上一节列举的示例通过使用简单的常量字符串说明了全文匹配。本节将阐述如何搜索表数据,此操作可以选择使用索引。
可以在没有索引的情况下执行全文搜索。一个简单的查询可以打印 title
,其中每一行都包含单词 friend
,该单词位于其 body
域中,如下所示:
SELECT title FROM pgweb WHERE to_tsvector('english', body) @@ to_tsquery('english', 'friend');
这还将找出相关字词,例如 朋友
和 友好的
,因为所有这些都归结为同一标准词素。
上述查询指定要使用 english
配置来对字符串进行分析和规范化。或者我们也可以忽略配置参数
SELECT title FROM pgweb WHERE to_tsvector(body) @@ to_tsquery('friend');
此查询将使用由 default_text_search_config 设置的配置。
一个更复杂的示例是选择包含 create
和 table
的 title
或 body
中十个最新的文档
SELECT title FROM pgweb WHERE to_tsvector(title || ' ' || body) @@ to_tsquery('create & table') ORDER BY last_mod_date DESC LIMIT 10;
为 clarity 我们省略了 coalesce
函数调用,在两个字段之一中找到包含 NULL
的行时需要这些调用。
虽然这些查询可以在没有索引的情况下工作,但大多数应用程序会发现这种方式太慢,除了偶尔的临时搜索除外。实际使用文本搜索通常需要创建一个索引。
我们创建一个GIN索引(第 12.9 节)以加快文本搜索
CREATE INDEX pgweb_idx ON pgweb USING GIN (to_tsvector('english', body));
注意,使用了 to_tsvector
的双参数版本。只有指定配置名称的文本搜索函数才能在表达式索引(第 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 索引时这一点更为重要;请参阅第 12.9 节。)不过,表达式索引方法的设置更简单,所需的磁盘空间也更少,因为 tsvector
表示形式并未明确存储。