首页 > 解决方案 > 以良好的性能在 PL/SQL 中获取相似的字符串

问题描述

我的 Oracle 数据库 (12c) 中有一个大表,我有很多需要相互比较的字符串。我想看看哪些字符串是相似的。

例子:

你好世界波士顿在美国

德国柏林你好世界

应该被检测为类似的字符串,而

你好世界巴黎在法国

你好底特律一个不错的城市

不应被检测为相似。如何在 Oracle PL/SQL 中高效准确地执行此操作?

标签: oracleplsql

解决方案


您应该使用在性能和效率之间取得良好平衡的 Dice-Coefficient。它会给你一个数字,代表两个字符串的相似程度。您可以为所有字符串运行此函数,将它们相互比较,然后选择具有大系数的字符串(这些将非常相似)。


-- Dice-Coefficient in Oracle PL/SQL
-- http://en.wikipedia.org/wiki/Dice%27s_coefficient
-- http://en.wikipedia.org/wiki/S%C3%B8rensen_similarity_index
-------------------------------------------------------------------------------
FUNCTION DICE_COEFF(p_str1 IN VARCHAR2, p_str2 IN VARCHAR2) RETURN NUMBER DETERMINISTIC IS
    co_substr_len CONSTANT NUMBER := 2;

    TYPE ty_varchar_assoc IS TABLE OF VARCHAR2(100) INDEX BY VARCHAR2(100);

    v_x     ty_varchar_assoc;
    v_y     ty_varchar_assoc;
    v_inter ty_varchar_assoc;
    v_part  VARCHAR2(10);
BEGIN

    -- building set X
    FOR i IN 1 .. length(p_str1) - co_substr_len + 1 LOOP
      v_part := substr(p_str1, i, co_substr_len);
      v_x(v_part) := v_part;
    END LOOP;

    -- building set Y
    FOR i IN 1 .. length(p_str2) - co_substr_len + 1 LOOP
      v_part := substr(p_str2, i, co_substr_len);
      v_y(v_part) := v_part;

      IF v_x.exists(v_part) THEN
        v_inter(v_part) := v_part; -- build intersect            
      END IF;
    END LOOP;

    RETURN 2 * v_inter.count /(v_x.count + v_y.count);

END DICE_COEFF;

推荐阅读