2011-05-27 68 views
6

我正在寻找一种方法来在PostgreSQL中使用tsvector来模拟SELECT * FROM table WHERE attr LIKE '%text%'之类的内容。使用全文搜索匹配以前缀结尾的短语

我已经创建了tsvector属性而不使用字典。现在,查询像...

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

...返回所有的游戏,比如“物理”,“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:*'); 

回答

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分析,以确保tsquery,而不是之前之后正在执行。

2

有一个办法做到这一点Postgres里使用trigrams和杜松子酒/要点索引。有一个简单的例子,但有一些粗糙的边缘,在Kristo Kaiv的这篇文章中:Substring Search

1

不漂亮的解决方案,但它应该做的工作:

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

的Postgres 9.6介绍了全文搜索短语搜索功能。所以,这个工程现在:

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

<-> being the FOLLOWED BY operator.

它发现'富Zend框架栏''的Zend框架',但'富Zend的无边框条'

引述release notes for 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:*');