【问题标题】:Longest matching substring最长匹配子串
【发布时间】:2013-05-04 00:59:20
【问题描述】:

如何在 varchar 变量中搜索最长的匹配项?例如,表 GOB 有如下条目:

magic_word |  prize
===================
         sh|  $0.20
        sha|  $0.40
       shaz|  $0.60
      shaza|  $1.50

我想编写一个 plpgsql 函数,该函数将字符串作为输入(例如shazam),并返回具有最长匹配子字符串的 GOB 行上的“奖品”列。在显示的示例中,那将是带有magic_word shaza 的行上的$1.50

我能处理的所有函数格式,只是匹配位。我想不出一个优雅的解决方案。我猜这可能真的很容易,但我正在摸不着头脑。我不知道一开始的输入字符串,因为它将来自另一个表的查询结果。

有什么想法吗?

【问题讨论】:

  • brac 是否匹配 abrac?
  • 不,它必须从一开始就匹配。选择错误的例子,我很抱歉。我更改了这个词以减少混淆。

标签: postgresql plpgsql


【解决方案1】:

简单的解决方案

SELECT magic_word
FROM   gob
WHERE  'shazam' LIKE (magic_word || '%')
ORDER  BY magic_word DESC
LIMIT  1;

这很有效,因为最长的匹配排在最后 - 所以我对 DESC 进行排序并选择第一个匹配。

我从您的示例中假设您希望从字符串的开头匹配左锚定。如果您想匹配字符串中的任何位置(使用索引更昂贵且更难备份),请使用:

...
WHERE  'shazam' LIKE ('%' || magic_word || '%')
...

SQL Fiddle.

性能

查询不是sargable。如果您有其他信息(例如可以作为索引基础的最小长度)来减少要考虑的行数,这可能会有所帮助。它必须是让你在表格中占不到 5% 的标准才有效。因此,缩写(自然的最低选择)可能有用,也可能没有用。但是开头的两三个字母可能会有所帮助。

事实上,您可以反复优化它。类似的东西:
尝试使用 15 个字母的单词的部分索引+
如果找不到,请尝试 12 个字母+
如果找不到,请尝试 9 个字母+
...

我在 dba.SE 上的相关答案中概述的一个简单案例:

另一种方法是使用三元组索引。为此,您需要额外的模块 pg_trgm。通常,您会在具有 longer 字符串的表中使用短模式进行搜索。但是三元组也适用于您的反向方法,但有一些限制。显然,您无法使用三元组在较长的字符串中间匹配一个只有两个字符的字符串...测试极端情况。
这里有很多关于 SO 的答案以及更多信息。示例:

高级解决方案

考虑整个搜索字符串表在这个密切相关的问题下的解决方案。使用递归 CTE 实现:

【讨论】:

  • 你看到你知道你的东西,所以哪个可能更快:下面的嵌套 SELECT,还是这个?我可以测试它,但桌子的大小使差异可以忽略不计。但是,最终该表会明显变大,这样的性能问题可能会产生影响。
  • @BrenMcGuire:只要不涉及索引,最简单的形式就赢了,这应该是我的第一个查询。但测试>>猜测。提高性能的关键是索引的使用。
【解决方案2】:

怎么样

1

     select max(FOO.matchingValue)
     from
      (
        select magic_word as matchingValue
        from T
        where substr( "abracadabra", 1, length(magic_word)) = magic_word 
      )
      as FOO

2

select prize from
T
  join
  (
  select max(FOO.matchingValue) as MaxValue
     from
      (
         select magic_word as matchingValue
        from T
        where substr( "abracadabra", 1, length(magic_word)) = magic_word 
      )
      as FOO
) as BAR
on BAR.MaxValue = T.magic_word

【讨论】:

  • 如何从该结果集中检索cost 字段?
  • 只要按照同样的原则把上面的变成内联视图。我马上编辑。
  • 它的工作还不错,但它的某些方面对我来说是“非最佳的”。
  • 至于成本:大概在实际应用程序中,您会有另一个索引列,例如[CONTEST],可用于将最内层的候选 magic_words 集减少为易于管理的数字。最里面的候选集的集合是必须进行优化(如果有的话)的地方。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-06-04
  • 2022-06-10
  • 1970-01-01
  • 2012-03-02
  • 1970-01-01
  • 2019-08-29
  • 2021-09-01
相关资源
最近更新 更多