将以前缀结尾的短语与全文搜索匹配

时间:2011-05-27 17:13:28

标签: postgresql full-text-search pattern-matching tsvector

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

我在不使用字典的情况下创建了一个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 个答案:

答案 0 :(得分:5)

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匹配后表达与标题的正则表达式匹配,但你必须使用explain analyze来确保在tsquery之后而不是之前执行。

答案 1 :(得分:4)

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

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

<-> being the FOLLOWED BY operator.

它找到'foo Zend框架栏''Zend frames',但 'foo Zend没有框架栏“

引用release notes for Postgres 9.6:

  

可以使用new在tsquery输入中指定短语搜索查询   运营商<->< N >。前者意味着之前和之前的词义   在它必须按顺序出现在彼此之后。后者   意味着他们必须完全 N lexemes。

为获得最佳性能,请使用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:*');

答案 2 :(得分:3)

不是一个漂亮的解决方案,但它应该完成这项工作:

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) @@ ...
  5. 中使用它

答案 3 :(得分:2)

有一种方法可以使用trigrams和Gin / Gist索引在Postgres中完成。有一个简单的例子,但有一些粗糙的边缘,在Kristo Kaiv的这篇文章中:Substring Search