10

我正在寻找一种方法来模拟SELECT * FROM table WHERE attr LIKE '%text%'在 PostgreSQL 中使用 tsvector 之类的东西。

我在不使用字典的情况下创建了一个 tsvector 属性。现在,像...这样的查询

SELECT title
FROM table
WHERE title_tsv @@ plainto_tsquery('ph:*');  

...将返回所有标题,如“Physics”、“PHP”等。但是我如何创建一个查询来返回标题以“Zend Fram”开头的所有记录(例如应该返回“Zend Framework”)?

当然,我可以使用类似的东西:

SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend')
AND   title_tsv @@ to_tsquery('fram:*');

不过,这似乎有点尴尬。

因此,问题是:有没有一种方法可以使用以下内容来制定上面给出的查询:

SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend fram:*');
4

4 回答 4

8
SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend') and
title_tsv @@ to_tsquery('fram:*')  

相当于:

SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend & fram:*')

但当然也发现“Zend 没有框架”。

您当然可以在 tsquery 匹配之后表达与 title 的正则表达式匹配,但是您必须使用 explain analyze 来确保在 tsquery 之后而不是之前执行。

于 2011-05-27T17:26:28.827 回答
6

不是一个很好的解决方案,但它应该可以完成工作:

psql=# SELECT regexp_replace(cast(plainto_tsquery('Zend Fram') as text), E'(\'\\w+\')', E'\\1:*', 'g') ;
   regexp_replace    
---------------------
 'zend':* & 'fram':*
(1 row)

它可以像这样使用:

psql=# SELECT title FROM table WHERE title_tsv(title) @@ to_tsquery(regexp_replace(cast(plainto_tsquery('Zend Fram') as text), E'(\'\\w+\')', E'\\1:*', 'g'));

这是如何工作的:

  1. 将普通的 tsquery 转换为字符串:cast(plainto_tsquery('Zend Fram') as text)
  2. 使用正则表达式将:*前缀匹配器附加到每个搜索词:regexp_replace(..., E'(\'\\w+\')', E'\\1:*', 'g')
  3. 将其转换回非普通 tsquery。to_tsquery(...)
  4. 并在搜索表达式中使用它SELECT title FROM table WHERE title_tsv(title) @@ ...
于 2015-12-11T19:09:26.697 回答
6

Postgres 9.6为全文搜索引入了短语搜索功能。所以这现在有效:

SELECT title
FROM  tbl
WHERE title_tsv @@ to_tsquery('zend <-> fram:*');

<->是 FOLLOWED BY 运算符。

它找到'foo Zend framework bar''Zend frames',但没有找到 'foo Zend has no framework bar'

引用Postgres 9.6 的发行说明:

可以使用新的运算符<->和在 tsquery 输入中指定短语搜索查询。前者意味着它之前和之后的词位必须以该顺序彼此相邻。后者意味着它们必须是完全分开的词位。<N>N

为了获得最佳性能支持使用 GIN 索引的查询:

CREATE INDEX tbl_title_tsv_idx ON tbl USING GIN (title_tsv);

或者根本不存储title_tsv在表中(使其膨胀并使写入复杂化)。您可以改用表达式索引:

CREATE INDEX tbl_title_tsv_idx ON tbl USING GIN (to_tsvector('english', title));

您需要指定文本搜索配置(通常是特定于语言的)以使表达式不可变。并相应地调整查询:

...
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'zend <-> fram:*');
于 2016-12-13T02:21:52.713 回答
3

在 Postgres 中有一种使用trigrams和 Gin/Gist 索引的方法。在 Kristo Kaiv 的这篇文章中,有一个简单的例子,但有一些粗糙的边缘:子字符串搜索

于 2011-05-29T07:43:06.520 回答