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

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

appl

以下内容应匹配:

a really nice application
apples are cool
appliances

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

如何在 PostgreSQL 中实现这一点?

【问题讨论】:

    标签: postgresql search full-text-search


    【解决方案1】:

    全文搜索的前缀匹配

    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 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 中添加对正则表达式搜索索引的支持 (亚历山大·科罗特科夫)

    见:

    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(用于不区分大小写的搜索)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-09-15
    • 2011-12-27
    • 1970-01-01
    • 1970-01-01
    • 2021-10-06
    • 2016-04-26
    相关资源
    最近更新 更多