搜索字符串中的单个单词

Posted

技术标签:

【中文标题】搜索字符串中的单个单词【英文标题】:Searching individual words in a string 【发布时间】:2013-10-22 13:30:44 【问题描述】:

我知道全文搜索,但这只会将您的查询与单个单词匹配。我想选择包含以我的查询中的单词开头的单词的字符串。例如,如果我搜索:

appl

以下内容应匹配:

a really nice application
apples are cool
appliances

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

如何在 PostgreSQL 中实现这一点?

【问题讨论】:

【参考方案1】:

全文搜索的前缀匹配

FTS 支持前缀匹配。您的查询是这样的:

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

注意tsquery 中附加的:*。这可以使用索引。 见:

Get partial match from GIN indexed TSVECTOR column

正则表达式替代

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 tbl_id
ORDER  BY matches 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;

db小提琴here旧sqlfiddle

Postgres 9.3 或更高版本具有索引支持,用于带有三元组 GIN 或 GiST 索引的简单正则表达式。 The release notes for Postgres 9.3:

在 pg_trgm 中添加对正则表达式搜索索引的支持 (亚历山大·科罗特科夫)

见:

PostgreSQL LIKE query performance variations

Depesz 写了一个blog about index support for regular expressions.

【讨论】:

SELECT * FROM tbl WHERE to_tsvector('simple', string) @@ to_tsquery('simple', 'appl:*');这适用于字符串,但不适用于数字 SELECT * FROM tbl WHERE to_tsvector('simple', string) @@ to_tsquery('simple', '111');这不起作用 @dev_sk:为我工作。 db小提琴here【参考方案2】:
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)并将该关键字表链接到您的完整短语表。这意味着您必须在将字符串输入数据库时​​将它们分解为关键字并将它们存储在两个位置。这是典型的空间与速度权衡。

【讨论】:

我现在正在阅读LIKE。如果我在搜索查询中有多个单词怎么办?如果我想搜索 appl goog 并匹配 Apple and Google are good companies 怎么办? SELECT * FROM some_table WHERE (some_field LIKE 'appl%' OR some_field LIKE '% appl%') AND (some_field LIKE 'goog%' OR some_field LIKE '% goog%'); 我想强调的是,这是一种骇人听闻的方式。例如,以下内容与 appl 搜索不匹配:"apples are my favorite!" exclaimed the boy. 因为在 appl 之前有一个 "。此外,您可能希望使用 ILIKE(用于不区分大小写的搜索)。

以上是关于搜索字符串中的单个单词的主要内容,如果未能解决你的问题,请参考以下文章

PHP分解字符串,但将引号中的单词视为单个单词

用同一字符串中的单个单词替换字符串的一部分

10 位或 6 位数字的正则表达式不应以“/”开头和结尾,也可以是字符串中的单个单词 [重复]

557. 反转字符串中的单词 III

Javascript在字符串中查找单词的索引(不是单词的一部分)

使用节点 js 搜索字符串 mongodb 中的任何单词