我正在寻找一种在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:*');
答案 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'));
这是如何运作的:
cast(plainto_tsquery('Zend Fram') as text)
:*
前缀匹配器附加到每个搜索词:regexp_replace(..., E'(\'\\w+\')', E'\\1:*', 'g')
to_tsquery(...)
SELECT title FROM table WHERE title_tsv(title) @@ ...
答案 3 :(得分:2)
有一种方法可以使用trigrams和Gin / Gist索引在Postgres中完成。有一个简单的例子,但有一些粗糙的边缘,在Kristo Kaiv的这篇文章中:Substring Search。