企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
# 12.2\. 表和索引 上一节中的例子说明使用简单常量字符串的全文匹配。本节显示如何搜索表中的数据,选择使用索引。 ## 12.2.1\. 搜索表 在不使用索引的情况下也是可以进行全文检索的,一个简单查询,显示出`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](#calibre_link-1138)使用配置设置。 复杂一点的例子:检索出最近的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`的行。 虽然这些查询在没有索引的情况下工作,大多数应用程序会发现这个方法太慢了,除了偶尔的特定搜索。 文本搜索的实际使用通常需要创建索引。 ## 12.2.2\. 创建索引 为了加速文本搜索,我们可以创建GIN索引([Section 12.9](#calibre_link-1129)): ``` CREATE INDEX pgweb_idx ON pgweb USING gin(to_tsvector('english', body)); ``` 注意,使用`to_tsvector`的2-参数版本。唯一的文本搜索功能指定可用于表达式索引的配置名称(节[Section 11.7](#calibre_link-959))。 这是因为索引的内容必须不受[default_text_search_config](#calibre_link-1138)的影响。如果他们受到影响,索引内容可能不一致, 因为不同的条目可能包含不同的文本搜索配置创建的`tsvector`,并且没有办法猜出是哪个。正确的转储和恢复 这样的一个索引是不可能的。 因为在上述索引中使用`to_tsvector`的2-参数版本,只有一个使用带有相同配置名称的`to_tsvector`的2-参数版本的查询参考, 它将使用该索引。也就是说,`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)); ``` 在`pgweb`表中`config_name`是一列。这允许在同一索引中混合配置,当记录的配置被用于每个索引条目。 这将是有用的,例如,如果文档集合中包含不同的语言文件。再次,意味着使用索引的查询必须措辞匹配, 例如,`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`的一个级联, 当其他是`NULL`的时候,使用`coalesce`确保一个字段仍然会被索引: ``` 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`形式时,有必要创建一个触发器以保持`tsvector`列当前任何时候`title`或者`body`的变化。 节[Section 12.4.3](#calibre_link-1114)解释了如何做。 单独列方法比一个表达式索引的优势是它没有必要明确地声明为充分利用索引查询中的文本搜索配置, 正如上面例子所示,查询依赖于`default_text_search_config`。另一个优势是搜索比较快速, 因为它没有必要重新进行`to_tsvector`调用来验证索引匹配(当使用GIST索引而不是GIN索引的时候, 这是非常重要的,参见节[Section 12.9](#calibre_link-1129))。表达式索引方法更容易建立,然而,它需要较少的磁盘空间, 因为`tsvector`形式没有明确存储。