如何优化Levenshtein距离计算

时间:2013-01-31 00:34:42

标签: mysql levenshtein-distance

Table a有大约8,000行,table b大约有250,000行。如果没有levenshtein函数,查询只需不到2秒。使用此功能大约需要25分钟。

SELECT
      *
   FROM
      library a,
      classifications b
   WHERE  
      a.`release_year` = b.`year`
      AND a.`id` IS NULL
      AND levenshtein_ratio(a.title, b.title) > 82

3 个答案:

答案 0 :(得分:1)

我假设levenshtein_ratio是您编写的函数(或者可能包含在其他地方)。如果是这样,数据库服务器将无法在使用索引的正常意义上优化它。所以这意味着它只需要为其他连接条件产生的每条记录调用它。使用内部联接,这可能是一个非常大的数字与这些表大小(最大8000 * 250000 = 20亿)。您可以使用以下方法检查需要调用的总次数:

SELECT
      count(*)
   FROM
      library a,
      classifications b
   WHERE  
      a.`release_year` = b.`year`
      AND a.`id` IS NULL

这解释了为什么它很慢(不是真正回答如何优化它的问题)。要对其进行优化,您可能需要在连接条件中添加其他限制因子,以减少对用户定义函数的调用次数。

答案 1 :(得分:1)

您提供的信息太少,无法真正帮助您。

1)我的第一个猜测是尝试创建其他WHERE条件,以减少要扫描的行数。

2)如果那是不可能的......鉴于表库和分类中的标题是已知的,一个想法是创建一个表,其中所有数据都已经计算如下:

TABLE levenshtein_ratio
id_table_library
id_table_classifications
precalculated_levenshtein_ratio

因此您将使用此查询填充表格:

insert into levenshtein_ratio select a.id, b.id, levenshtein_ratio(a.title, b.title) from library, classifications

然后你的查询将是:

    SELECT
          *
       FROM
          library a LEFT JOIN 
          classifications b ON a.`release_year` = b.`year`

LEFT JOIN levenshtein_ratio c ON c.id_table_library = a.id AND c.id_table_classifications = b.id
       WHERE  
          a.`id` IS NULL
          AND precalculated_levenshtein_ratio > 82

此查询可能不会超过原来的2秒。

此解决方案的问题在于表a和b中的数据可能会发生变化,因此您需要创建一个触发器以使其保持更新。

答案 2 :(得分:0)

更改您的查询以使用正确的连接(语法自1996年以来一直存在)。

此外,您的所有levensrein条件都可能会进入连接条件,这会给您带来性能优势:

SELECT *
FROM library a
JOIN classifications b
    ON a.`release_year` = b.`year`
    AND levenshtein_ratio(a.title, b.title) > 82
WHERE a.`id` IS NULL

另外,请确保b.year上有索引:

create index b_year on b(year);
相关问题