搜索字符串中的单个单词

时间:2013-10-14 21:16:53

标签: postgresql search full-text-search

我知道全文搜索,但这只是针对单个单词的查询。我想选择包含以查询中的单词开头的单词的字符串。例如,如果我搜索:

appl

以下内容应该匹配:

a really nice application
apples are cool
appliances

因为所有这些字符串都包含以appl开头的单词。另外,如果我可以选择匹配的单词数量,并根据它进行排序,那就太好了。

如何在PostgreSQL中实现它?

2 个答案:

答案 0 :(得分:9)

SELECT * FROM some_table WHERE some_field LIKE 'appl%' OR some_field LIKE '% appl%';

至于计算匹配的单词数量,我认为在postgres中动态执行会太昂贵(尽管其他人可能知道的更好)。一种方法是通过编写一个函数来计算字符串中的出现次数,然后添加ORDER BY myFunction('appl', some_field)。但是,这种方法非常昂贵(即很慢),不推荐使用。

对于类似的东西,你应该使用单独的/免费的全文搜索引擎,如Sphinx Search(google it),这是专门针对那种事情。

另一种方法是使另一个表包含关键字以及每个字符串中这些关键字的出现次数。这意味着您需要存储您拥有的每个短语(例如really really nice application),并将关键字存储在另一个表格中(例如really, 2nice, 1application, 1)并关联该关键字表到您的全词表。这意味着在将字符串输入数据库并将它们存储在两个位置时,您必须将字符串分解为关键字。这是典型的空间与速度的权衡。

答案 1 :(得分:8)

与全文搜索匹配的前缀

几年后重新审视这个问题,让我感到震惊的是,FTS 支持前缀匹配。您的查询可以这样工作:

SELECT * FROM tbl
WHERE  to_tsvector('simple', string) @@ to_tsquery('simple', 'appl:*');

请注意:*中附加的tsquery。详细说明:

替代正则表达式

SELECT * FROM tbl
WHERE  string ~ '\mappl';

引用the manual here

  

\m ..仅匹配单词的开头

要按比赛计数排序,您可以使用regexp_matches()

SELECT tbl_id, count(*) AS matches
FROM  (
    SELECT tbl_id, regexp_matches(string, '\mappl', 'g')
    FROM   tbl
    WHERE  string ~ '\mappl'
    ) sub
GROUP  BY 1
ORDER  BY 2 DESC;

regexp_split_to_table()

SELECT tbl_id, string, count(*) - 1 AS matches
FROM  (
    SELECT tbl_id, string, regexp_split_to_table(string, '\mappl')
    FROM   tbl
    WHERE  string ~ '\mappl'
    ) sub
GROUP  BY 1, 2
ORDER  BY 3 DESC, 2, 1;

SQL Fiddle展示了这三个。

Postgres 9.3甚至为简单正则表达式提供索引支持,具有三元组GIN或GiST索引(quoting the release notes):

  

添加对pg_trgm中正则表达式搜索索引的支持   (Alexander Korotkov)

Depesz wrote a blog about the new feature.