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

its*_*e69 9 postgresql full-text-search pattern-matching tsvector

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

我没有使用字典就创建了一个tsvector属性.现在,像...这样的查询

SELECT title
FROM table
WHERE title_tsv @@ plainto_tsquery('ph:*');  
Run Code Online (Sandbox Code Playgroud)

...将返回所有标题,如'Physics','PHP'等.但是,如何创建一个返回所有标题的查询,其中标题以'Zend Fram'开头(应该返回例如'Zend Framework')?

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

SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend')
AND   title_tsv @@ to_tsquery('fram:*');
Run Code Online (Sandbox Code Playgroud)

然而,这似乎有点尴尬.

所以,问题是:有没有办法用以下方法制定上面给出的查询:

SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend fram:*');
Run Code Online (Sandbox Code Playgroud)

Set*_*son 6

SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend') and
title_tsv @@ to_tsquery('fram:*')  
Run Code Online (Sandbox Code Playgroud)

相当于:

SELECT title
FROM table
WHERE title_tsv @@ to_tsquery('zend & fram:*')
Run Code Online (Sandbox Code Playgroud)

但当然发现"Zend也没有框架".

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


mga*_*mba 6

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

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

它可以像这样使用:

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'));
Run Code Online (Sandbox Code Playgroud)

这是如何工作的:

  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) @@ ...


Erw*_*ter 5

Postgres 9.6引入了用于全文搜索的短语搜索功能。所以这现在工作:

SELECT title
FROM  tbl
WHERE title_tsv @@ to_tsquery('zend <-> fram:*');
Run Code Online (Sandbox Code Playgroud)

<-> 是FOLLOWED BY运算符。

它找到“ foo Zend framework bar”“ Zendframes”,但找不到 “ 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);
Run Code Online (Sandbox Code Playgroud)

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

CREATE INDEX tbl_title_tsv_idx ON tbl USING GIN (to_tsvector('english', title));
Run Code Online (Sandbox Code Playgroud)

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

...
WHERE to_tsvector('english', title) @@ to_tsquery('english', 'zend <-> fram:*');
Run Code Online (Sandbox Code Playgroud)