附加功能

PostgreSQL 9.4.4 中文手册
上一页 | 上一级 | 章 12. 全文检索 | 下一页

# 12.4. 附加功能

本节描述了连接文本搜索中有用的附加功能和操作符。

## 12.4.1. 操作文档

节第 12.3.1 节显示了原始文本文档如何转换成`tsvector`值。 PostgreSQL也提供用于操作已经在`tsvector`形式中的文档的函数和操作符。

``tsvector` || `tsvector``

  `tsvector`连接操作符返回一个连接词的向量，以及作为参数给定的2个向量的位置信息。 在连接期间重新获得位置和权重标签。出现在右边向量位置通过左边向量提到的最大位置相抵消， 因此这个结果几乎等同于2个原始文档字符串连接中执行`to_tsvector`的结果。（这个等价是不准确的， 因为任何从左边参数中删除的干扰词不会影响结果，然而，如果使用文本连接，它们影响右边参数词的位置）。

  使用级联中的向量形式而不是在应用`to_tsvector`之前连接文本的一个优势是， 你可以使用不同的配置解析文档的不同部分。同时，由于`setweight`函数标记所有相同方式给定向量的词汇， 解析文本是必要的，并且如果你想用不同的权重标记文档不同部分，连接前做`setweight`。

`setweight(`vector` `tsvector`, `weight` `"char"`) returns `tsvector``

  `setweight` 返回一个输入向量的拷贝，其中每一个位置用给定的`weight`, `A`, `B`, `C`或者 `D`之一进行标记。（`D`是缺省新向量，因此不显示在输出上。）当向量连接时，保留这些标签， 允许一个文档的不同部分的词通过不同相关函数加权。

  注意权重标签适用于位置，不是词汇。如果输入向量已经被剥夺了位置，则`setweight`不做任何事情。

`length(`vector` `tsvector`) returns `integer``

  返回存储在向量中的词的数量。

`strip(`vector` `tsvector`) returns `tsvector``

  返回一个向量，其中列出了给定向量的同一词，但它缺乏任何位置和权重信息。 虽然为相关性排序返回的向量比一个未拆分向量用处少，它通常会小得多。

## 12.4.2. 处理查询

节第 12.3.2 节显示了原始文本查询如何转换成`tsquery`值。 PostgreSQL也提供了函数和操作符用于处理已存在`tsquery`形式中的查询

``tsquery` && `tsquery``

  返回两个给定查询的与组合。

``tsquery` || `tsquery``

  返回两个给定查询的或组合。

`!! `tsquery``

  返回给定查询的反面（非）。

`numnode(`query` `tsquery`) returns `integer``

  返回在一个`tsquery`中节点的数目（词加操作符）。决定`query`是否有意义（返回> 0）， 或只包含干扰词（返回0），这个函数是很有用的。例子：

      SELECT numnode(plainto_tsquery('the any'));
      NOTICE:  query contains only stopword(s) or doesn't contain lexeme(s), ignored
       numnode
      ---------
             0

      SELECT numnode('foo & bar'::tsquery);
       numnode
      ---------
             3

`querytree(`query` `tsquery`) returns `text``

  返回可用于搜索索引的`tsquery`部分。此函数对检测未索引查询是有帮助的，例如那些只包含干扰词或否定术语。比如:

      SELECT querytree(to_tsquery('!defined'));
       querytree
      -----------

### 12.4.2.1. 查询重写

函数族`ts_rewrite`搜索一个特定的目标查询事件`tsquery`，和替换每个替代子查询。 实际上这个操作是一个子字符串替换的`tsquery`-特定版本。目标和替换组合可以被认为是一个查询重写规则。 一组这样的重写规则可以是一个强大的搜索帮助。例如，你可以使用同义词扩大搜索（例如，`new york`, `big apple`, `nyc`, `gotham`）或缩小搜索一些热点问题的直接用户。在这些特性和同义词词典之间功能上有一些重叠（节第 12.6.4 节）。然而， 你可以在不重建索引情况下即时修改重写规则，而更新词库需要重建索引才能有效。

`ts_rewrite (`query` `tsquery`, `target` `tsquery`, `substitute` `tsquery`) returns `tsquery``

  `ts_rewrite`的这种形式只适用于一个单一的重写规则：无论出现在`query`的什么地方，`target`通过`substitute`替换。比如：

      SELECT ts_rewrite('a & b'::tsquery, 'a'::tsquery, 'c'::tsquery);
       ts_rewrite
      ------------
       'b' & 'c'

`ts_rewrite (`query` `tsquery`, `select` `text`) returns `tsquery``

  `ts_rewrite`的这种形式接受起始`查询`和SQL `select`命令，这是作为一个文本字符串。 `select`必须产生两列`tsquery`类型。`select`结果的每一行，出现的第一个字段的值（目标） 都被当前的`query`值中的第二个字段值（替代）。比如：

  注意，当多个重写规则适用于这种方式时，应用的顺序非常重要； 因此在实践中你将需要源查询为`ORDER BY`一些排序关键字。

让我们考虑下现实生活中天文的例子。我们将使用表驱动的重写规则扩大查询`supernovae`：

    CREATE TABLE aliases (t tsquery primary key, s tsquery);
    INSERT INTO aliases VALUES(to_tsquery('supernovae'), to_tsquery('supernovae|sn'));

    SELECT ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases');
               ts_rewrite
    ---------------------------------
     'crab' & ( 'supernova' | 'sn' )

我们可以通过更新表改变重写规则：

    UPDATE aliases
    SET s = to_tsquery('supernovae|sn & !nebulae')
    WHERE t = to_tsquery('supernovae');

    SELECT ts_rewrite(to_tsquery('supernovae & crab'), 'SELECT * FROM aliases');
                     ts_rewrite
    ---------------------------------------------
     'crab' & ( 'supernova' | 'sn' & !'nebula' )

当有许多的重写规则的时候，重写比较缓慢，因为它检查可能匹配的每一个规则。 为过滤掉明显非候选规则，我们可以使用`tsquery`类型的包含操作符。在下面的例子中， 我们只选择那些可能与原始查询匹配的规则：

    SELECT ts_rewrite('a & b'::tsquery,
                      'SELECT t,s FROM aliases WHERE ''a & b''::tsquery @> t');
     ts_rewrite
    ------------
     'b' & 'c'

## 12.4.3. 自动更新的触发器

当使用单独的列存储文档的`tsvector`形式，当文档内容列变化时， 有必要建立一个触发器更新`tsvector`列。两个内置的触发器功能可用于此， 或者你可以自定义触发器。

    tsvector_update_trigger(tsvector_column_name, config_name, text_column_name [, ... ])
    tsvector_update_trigger_column(tsvector_column_name, config_column_name, text_column_name [, ... ])

这些触发器函数自动计算来自一个或多个文本字段的`tsvector`列，在`CREATE TRIGGER`命令指定的参数控制下。 使用的例子是：

    CREATE TABLE messages (
        title       text,
        body        text,
        tsv         tsvector
    );

    CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
    ON messages FOR EACH ROW EXECUTE PROCEDURE
    tsvector_update_trigger(tsv, 'pg_catalog.english', title, body);

    INSERT INTO messages VALUES('title here', 'the body text is here');

    SELECT * FROM messages;
       title    |         body          |            tsv
    ------------+-----------------------+----------------------------
     title here | the body text is here | 'bodi':4 'text':5 'titl':1

    SELECT title, body FROM messages WHERE tsv @@ to_tsquery('title & body');
       title    |         body
    ------------+-----------------------
     title here | the body text is here

创建触发器，在`title`或者`body`中的任何改变都会自动反映到`tsv`中，而不必担心它的应用。

第一个触发器参数必须是被更新的`tsvector`字段名。第二个参数指定要进行转换的文本搜索配置。 为`tsvector_update_trigger`，配置的名称仅仅是作为第二个触发器参数。它必须是如上所示的模式匹配， 因此触发器的行为在`search_path`中不会改变。为`tsvector_update_trigger_column`， 第二个触发器参数是另一个表列的名称，它的类型必须是`regconfig`。这允许每行选择进行配置。 剩余的参数（s）是文本列的名称（键入`text`, `varchar`或者`char`）。这些将在给定的顺序中提供文档。 空值将被忽略（但其他列仍将被索引）。

这些内置触发器的限制是它们一致对待所有输入列。为了处理不同列—比如， 为权重不同主体的标题—它有必要编写一个自定义触发器。 这是使用PL/pgSQL 作为触发器语言的一个例子：

    CREATE FUNCTION messages_trigger() RETURNS trigger AS $$
    begin
      new.tsv :=
         setweight(to_tsvector('pg_catalog.english', coalesce(new.title,'')), 'A') ||
         setweight(to_tsvector('pg_catalog.english', coalesce(new.body,'')), 'D');
      return new;
    end
    $$ LANGUAGE plpgsql;

    CREATE TRIGGER tsvectorupdate BEFORE INSERT OR UPDATE
        ON messages FOR EACH ROW EXECUTE PROCEDURE messages_trigger();

记住当在触发器内部创造`tsvector`值时，明确指定配置的名称是很重要的， 所以，该列的内容将通过改变`default_text_search_config`而不会受到影响。 如果不这样做可能会导致诸如重载转储之后搜索结果改变的问题。

## 12.4.4. 收集文献统计

函数`ts_stat`可用于检查你的配置和查找屏蔽候选词。

    ts_stat(sqlquery text, [ weights text, ]
            OUT word text, OUT ndoc integer,
            OUT nentry integer) returns setof record

`sqlquery`是一个包含返回单独`tsvector`列的SQL查询的文本值。 `ts_stat`执行查询并返回包含`tsvector`数据的各个不同的语义（词）的统计。返回的列：

- `word` `text` — 一个词的值

- `ndoc` `integer` —这个词出现的文档编号（`tsvector`s）

- `nentry` `integer` —这个词出现的总数

如果提供`weights` ，仅仅计算这些权重之一。

例如，在一个文档集合中查找十个最常用的单词：

    SELECT * FROM ts_stat('SELECT vector FROM apod')
    ORDER BY nentry DESC, ndoc DESC, word
    LIMIT 10;

同样的，但是只计算权重weight `A`或者`B`的单词：

    SELECT * FROM ts_stat('SELECT vector FROM apod', 'ab')
    ORDER BY nentry DESC, ndoc DESC, word
    LIMIT 10;

上一页 | 起始页 | 下一页
控制文本搜索 | 上一级 | 解析器