我知道全文搜索,但这只是针对单个单词的查询。我想选择包含以查询中的单词开头的单词的字符串。例如,如果我搜索:
appl
以下内容应该匹配:
a really nice application
apples are cool
appliances
因为所有这些字符串都包含以appl
开头的单词。另外,如果我可以选择匹配的单词数量,并根据它进行排序,那就太好了。
如何在PostgreSQL中实现它?
答案 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, 2
,nice, 1
,application, 1
)并关联该关键字表到您的全词表。这意味着在将字符串输入数据库并将它们存储在两个位置时,您必须将字符串分解为关键字。这是典型的空间与速度的权衡。
答案 1 :(得分:8)
几年后重新审视这个问题,让我感到震惊的是,FTS 支持前缀匹配。您的查询可以这样工作:
SELECT * FROM tbl
WHERE to_tsvector('simple', string) @@ to_tsquery('simple', 'appl:*');
请注意:*
中附加的tsquery
。详细说明:
SELECT * FROM tbl
WHERE string ~ '\mappl';
\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;
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)