【问题标题】:Fuzzy Matching Duplicates in JavaJava中的模糊匹配重复项
【发布时间】:2014-07-14 05:31:00
【问题描述】:

我有一个List<String[]> 的 Java 客户记录(来自数据库)。我通过手动观察数据知道 25%+ 是重复的。

虽然重复的内容远非准确。有时它们有不同的邮编,但名称和地址相同。其他时候地址完全丢失,等等......

经过一天的研究;我仍然很困惑如何开始解决这个问题?

我应该在谷歌上搜索哪些“术语”来描述这个领域(从 Java 角度解决这个问题)?而且我不认为有fuzzymatch.jar 可以让这一切变得简单吗?

【问题讨论】:

  • 编辑距离算法,例如 Levenshtein 距离或 Hamming 距离以及可能的推导。
  • Lucerne 和 solr 是用 java 和功能工具编写的,用于模糊匹配等。
  • Levenshtein 只能处理字符串?不是一组字符串?

标签: java pattern-matching fuzzy-search


【解决方案1】:

我以前做过类似的系统来匹配地点信息和人员信息。这些是具有许多特征的复杂对象,要弄清楚两个不同的对象是描述同一个地方还是一个人是很棘手的。做到这一点的方法是将其分解为基本要素。

您可以做以下几件事:

0) 如果这是一次性的,则将数据加载到 openrefine 并以交互方式修复问题。最大程度地解决您的问题,最小程度地显示您可能匹配的位置。

1) 有几种方法可以比较字符串。基本上,它们在产生否定匹配和错误匹配方面的可靠性不同。否定匹配是当它不应该匹配时匹配。正匹配是它应该匹配并且确实匹配。字符串 equals 不会产生负匹配,但会由于细微的变化而错过很多潜在的匹配。带有小因素的莱文斯坦稍好一些。 Ngrams 产生了很多匹配,但其中很多是错误的。还有一些算法,看看例如openrefine 代码可以找到各种比较和聚类字符串的方法。 Lucene 在它的分析器框架中实现了很多这样的东西,但是如果你对它的设计不是很熟悉的话,它就有点像野兽了。

2) 将比较东西的过程与决定是否匹配的过程分开。我过去所做的是使用简单的数字分数来限定我的比较,例如该字段完全匹配 (100) 但该字段是部分匹配 (75) 并且该字段根本不匹配。合格比较的结果向量,例如(100, 75,0,25) 可以与定义完美或部分匹配标准的参考向量进行比较。例如,如果名字、姓氏和街道匹配,则无论其余字段如何,这两条记录都是相同的。或者,如果电话号码和姓氏匹配,那也是有效匹配。您可以将此类完美匹配编码为向量,然后简单地将其与您的比较向量进行比较,以确定它是匹配、不匹配还是部分匹配。这是机器学习所做的手动版本,它是提取特征向量,然后建立一个概率模型,其中向量从参考数据中表示什么。手动完成,可以解决简单的问题。

3) 使用您知道匹配或不匹配的测试用例构建参考数据集,并根据该参考集评估您的算法。这样,当您进行调整时,您将知道何时改进或使事情变得更糟,例如进入莱文斯坦或其他的因素。

【讨论】:

    【解决方案2】:

    Jilles 的回答很棒,而且来自经验。我还不得不清理大而凌乱的表格,遗憾的是当时我对我的选择知之甚少(我最终使用了 Excel 和很多自动过滤器)。希望我知道 OpenRefine。

    但是,如果您到了必须编写自定义代码来执行此操作的地步,我想提出一个建议:列总是相同的,对吗?例如,第一个字符串始终是键,第二个是名字,第六个是邮政编码,第十个是传真号码,等等?

    假设没有不合理的字段数量,我将从一个自定义 Record 类型开始,该类型将每个 DB 字段作为成员而不是数组中的位置。类似的东西

    class CustomerRow {
        public final String id;
        public final String firstName;
        // ...
    
        public CustomerRow(String[] data) {
            id = data[0];
            // ...
    }
    

    如果您知道总是想过滤掉垃圾值,您还可以在构造函数中包含一些验证代码。

    (请注意,您基本上是在执行 ORM 会自动执行的操作,但开始使用 ORM 可能比编写 Record 类型需要更多的工作。)

    然后你会实现一些Comparator<CustomerRow>s,它们只查看特定字段,或者用模糊术语定义相等(编辑距离算法会派上用场),或者进行特殊排序。

    Java 对对象使用稳定的排序,因此可以按例如名称、地址、密钥,您只需进行每种排序,但以相反的顺序选择比较器。

    此外,如果您可以访问实际数据库,并且它是一个真正的关系数据库,我建议您尽可能将一些搜索作为查询进行。如果您需要在 Java 对象和 DB 之间来回切换,那么使用 ORM 最终可能是一个不错的选择。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 1970-01-01
      • 2018-04-26
      • 2011-01-18
      • 2015-04-26
      • 1970-01-01
      相关资源
      最近更新 更多