优化编辑距离算法

2023-12-11

我有一个存储过程,它使用编辑距离来确定最接近用户键入内容的结果。唯一真正影响速度的是在选择距离最小的记录之前计算所有记录的 Levenshtein 距离的函数(我通过将 0 代替对 Levenshtein 函数的调用来验证这一点)。该表有 150 万条记录,因此即使是最轻微的调整也可能会缩短几秒钟。现在整个过程持续了10多分钟。这是我正在使用的方法:

ALTER function dbo.Levenshtein
( 
    @Source nvarchar(200), 
    @Target nvarchar(200) 
) 
RETURNS int
AS
BEGIN
DECLARE @Source_len int, @Target_len int, @i int, @j int, @Source_char nchar, @Dist int, @Dist_temp int, @Distv0 varbinary(8000), @Distv1 varbinary(8000)

SELECT @Source_len = LEN(@Source), @Target_len = LEN(@Target), @Distv1 = 0x0000, @j = 1, @i = 1, @Dist = 0

WHILE @j <= @Target_len
BEGIN
    SELECT @Distv1 = @Distv1 + CAST(@j AS binary(2)), @j = @j + 1
END

WHILE @i <= @Source_len
BEGIN
    SELECT @Source_char = SUBSTRING(@Source, @i, 1), @Dist = @i, @Distv0 = CAST(@i AS binary(2)), @j = 1

WHILE @j <= @Target_len
BEGIN
    SET @Dist = @Dist + 1
    SET @Dist_temp = CAST(SUBSTRING(@Distv1, @j+@j-1, 2) AS int) +
                  CASE WHEN @Source_char = SUBSTRING(@Target, @j, 1) THEN 0 ELSE 1 END

    IF @Dist > @Dist_temp
    BEGIN
        SET @Dist = @Dist_temp
    END

    SET @Dist_temp = CAST(SUBSTRING(@Distv1, @j+@j+1, 2) AS int)+1

    IF @Dist > @Dist_temp SET @Dist = @Dist_temp
    BEGIN
        SELECT @Distv0 = @Distv0 + CAST(@Dist AS binary(2)), @j = @j + 1
    END
END

SELECT @Distv1 = @Distv0, @i = @i + 1
END

RETURN @Dist
END

我应该从这里去哪里?


我过去这样做的方法是将“数据库”(实际上是用于拼写纠正器的单词词典)存储为特里树。

然后我使用分支定界例程来查找最近的匹配条目。对于小距离,所花费的时间与距离呈指数关系。对于长距离,它与字典的大小成线性关系,就像您现在看到的那样。

分支定界基本上是 trie 的深度优先树遍历,但有错误预算。在每个节点,您跟踪当前的编辑距离,如果超出预算,则修剪树的该分支。

首先,您以零预算进行步行。这只会找到完全匹配的结果。如果你没有找到匹配的,那么你就以 1 的预算走过去。这将在距离 1 处找到匹配项。如果找不到任何匹配项,则以预算 2 进行匹配,依此类推。这听起来效率很低,但由于每次步行比前一次花费的时间要多得多,因此时间主要由您最后一次步行决定。

添加:代码概要(请原谅我的 C):

// dumb version of trie node, indexed by letter. You can improve.
typedef struct tnodeTag {
  tnodeTag* p[128];
} tnode;

tnode* top; // the top of the trie

void walk(tnode* p, char* s, int budget){
  int i;
  if (*s == 0){
    if (p == NULL){
      // print the current trie path
    }
  }
  else if (budget >= 0){
    // try deleting this letter
    walk(p, s+1, budget-1);
    // try swapping two adjacent letters
    if (s[1]){
      swap(s[0], s[1]);
      walk(p, s, budget-1);
      swap(s[0], s[1]);
    }
    if (p){
      for (i = 0; i < 128; i++){
        // try exact match
        if (i == *s) walk(p->p[i], s+1, budget);
        // try replacing this character
        if (i != *s) walk(p->p[i], s+1, budget-1);
        // try inserting this letter
        walk(p->p[i], s, budget-1);
      }
    }
  }
}

基本上,您可以通过跳过字母并在同一节点搜索来模拟删除该字母。您可以通过降序排列 trie 而不前进 s 来模拟插入字母。您可以通过表现得好像字母匹配来模拟替换字母,即使事实并非如此。当你掌握了它的窍门后,你可以添加其他可能的不匹配,例如用 O 替换 0,用 L 或 I 替换 1 - 像这样的愚蠢的东西。

您可能想要添加一个字符数组参数来表示您在 trie 中找到的当前单词。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

优化编辑距离算法 的相关文章

  • 如何用 numpy 在 Cython 中表示 inf 或 -inf ?

    我正在用 cython 逐个元素构建一个数组 我想存储常量np inf or 1 np inf 在某些条目中 然而 这将需要返回 Python 进行查找的开销inf 有没有libc math相当于这个常数 或者其他一些可以轻松使用的值 相当
  • 使用 :first 优化 jQuery 选择器

    我有过这样的感觉 class first 运行速度比 class 所以任何时候我都知道只有一个 class在子集中 我已经使用了它 Does first使查询运行得更快 还是没有必要 这实际上取决于浏览器 first http api jq
  • 为什么空切片有 24 个字节?

    我想了解创建空切片时会发生什么make int 0 我执行此代码进行测试 emptySlice make int 0 fmt Println len emptySlice fmt Println cap emptySlice fmt Pri
  • 了解 Tensorflow 中的 while 循环

    我正在使用用于 Tensorflow 的 Python API https www tensorflow org api docs python 我正在努力实施罗森布罗克函数 https www sfu ca ssurjano rosen
  • 我可以让 C++ 编译器在编译时实例化对象吗?

    我正在编写一些代码 其中包含大量相当简单的对象 我希望它们在编译时创建 我认为编译器能够做到这一点 但我无法弄清楚如何做到 In C我可以执行以下操作 include
  • 是否已经有一些基于 std::vector 的 set/map 实现?

    对于小型集合或地图 通常使用排序向量而不是基于树的向量要快得多set map 特别是对于 5 10 个元素的情况 LLVM 有一些类本着这种精神 http llvm org docs ProgrammersManual html ds se
  • Python 中快速、小型且重复的矩阵乘法

    我正在寻找一种使用 Python Cython Numpy 快速将许多 4x4 矩阵相乘的方法 任何人都可以给出任何建议吗 为了展示我当前的尝试 我有一个需要计算的算法 A 1 A 2 A 3 A N 哪里每个 A i A j Python
  • 取消的分支与常规分支有何不同?

    特别是对于 SPARC Assembly 取消的分支与常规分支有何不同 我一直认为 当我需要填充分支指令的 nop 延迟槽时 需要取消分支指令 但是 我认为我在这一部分上是不正确的 因为您可以在不取消分支的情况下填充 nop 如果不采用分支
  • 让 GHC 生成“带进位加法 (ADC)”指令

    下面的代码将表示 192 位数字的两个未装箱字三元组添加到新的未装箱字三元组中 并且还返回任何溢出 LANGUAGE MagicHash LANGUAGE UnboxedTuples import GHC Prim plusWord2 Wo
  • gcc总是做这种优化吗? (公共子表达式消除)

    作为示例 假设表达式sys gt pot atoms item gt P kind mass在循环内求值 循环只改变item 因此表达式可以简化为atoms item gt P kind mass通过将变量定义为atoms sys gt p
  • 为什么 hibernate 在 SAVE 之前执行 SELECT?

    为什么 hibernate 在保存对象之前要进行选择 我在互联网上找不到有用的信息 这是每次保存之前的正常行为吗 我发现这个话题 选择 hibernateTemplate save 的查询运行 https stackoverflow com
  • VB.NET 是否优化字符串文字的串联?

    如同this https stackoverflow com questions 288794 does c optimize the concatenation of string literals问题 但对于 VB NET 来说 因为我
  • 使用 lpSolve 优化 R 团队名单

    我是 R 新手 有一个想要解决的特定幻想运动队优化问题 我见过其他帖子使用 lpSolve 来解决类似的问题 但我似乎无法理解代码 下面的示例数据表 每个球员都在一个球队中 扮演着特定的角色 有薪水 并且每场比赛都有平均得分 我需要的限制是
  • 将嵌套循环计算转换为 Numpy 以加速

    我的Python程序的一部分包含以下代码段 其中一个新的网格 是根据旧网格中找到的数据计算的 网格是二维浮点数列表 该代码使用了三个 for 循环 for t in xrange 0 t step for h in xrange 1 hei
  • 优化正则表达式来解析中文拼音[关闭]

    这个问题不太可能对任何未来的访客有帮助 它只与一个较小的地理区域 一个特定的时间点或一个非常狭窄的情况相关 通常不适用于全世界的互联网受众 为了帮助使这个问题更广泛地适用 访问帮助中心 help reopen questions 我有一个有
  • 找到一系列间隔的最有效分组

    我有一个应用程序 其中有一系列不重叠的固定宽度间隔 每个间隔都有一个给定的键 每个间隔具有相同的宽度 并且可以存在连续的间隔 本质上 我想以最小化单独间隔的数量的方式对间隔和键进行分组 这可以通过合并具有相同键的连续间隔或查找匹配间隔并将它
  • URL路径相似度/字符串相似度算法

    我的问题是我需要比较 URL 路径并推断它们是否相似 下面我提供了要处理的示例数据 GROUP 1 robots txt GROUP 2 bot html GROUP 3 phpMyAdmin 2 5 6 rc1 scripts setup
  • Rust 编程竞赛中最快的惯用 I/O 例程?

    我的问题已部分得到解答 因此我根据从评论和其他实验中学到的知识对其进行了修改 总之 我想要一个用于编程竞赛的快速 I O 例程 其中使用单个文件解决问题 无需外部包 它应该从一个以空格分隔的标记序列中读取BufRead 标准输入或文件 标记
  • 执行时间为零的循环

    是否有可能有一个执行时间为零的循环 我认为即使是空循环也应该有执行时间 因为存在与之相关的开销 是的 根据假设规则编译器只有义务模拟代码的可观察行为 因此 如果您有一个没有任何可观察行为的循环 那么它可以完全优化 因此实际上执行时间为零 E
  • 模块化算术和 NTT(有限域 DFT)优化

    我想使用 NTT 进行快速平方 参见快速大数平方计算 https stackoverflow com q 18465326 2521214 但即使对于非常大的数字 结果也很慢 超过 12000 位 所以我的问题是 有没有办法优化我的 NTT

随机推荐