代码之家  ›  专栏  ›  技术社区  ›  wcm

数据比较

  •  5
  • wcm  · 技术社区  · 18 年前

    我们定期收到来自外部来源的数据文件,这些文件要求我们与此表进行匹配。不幸的是,数据略有不同,因为它来自完全不同的系统。例如,我们有“东大街123号”和“东大街123号”。另一个示例是“Acme,LLC”,文件中包含“Acme Inc.”。另一个是,我们有“Ed Smith”,他们有“Edward Smith”

    我们有一个遗留系统,它使用一些相当复杂的CPU密集型方法来处理这些匹配。一些涉及纯SQL,另一些涉及Access数据库中的VBA代码。目前的系统很好,但并不完善,而且很麻烦,很难维护

    这里的管理层希望扩大其使用范围。继承系统支持的开发人员希望用需要较少维护的更灵活的解决方案来取代它。

    7 回复  |  直到 10 年前
        1
  •  4
  •   torial    18 年前

    下面是我为几乎相同的堆栈编写的东西(我们需要标准化硬件的制造商名称,并且有各种各样的变化)。这是客户端(确切地说是VB.Net)--并使用Levenshtein距离算法(为获得更好的结果而修改):

        Public Shared Function FindMostSimilarString(ByVal toFind As String, ByVal ParamArray stringList() As String) As String
            Dim bestMatch As String = ""
            Dim bestDistance As Integer = 1000 'Almost anything should be better than that!
    
            For Each matchCandidate As String In stringList
                Dim candidateDistance As Integer = LevenshteinDistance(toFind, matchCandidate)
                If candidateDistance < bestDistance Then
                    bestMatch = matchCandidate
                    bestDistance = candidateDistance
                End If
            Next
    
            Return bestMatch
        End Function
    
        'This will be used to determine how similar strings are.  Modified from the link below...
        'Fxn from: http://ca0v.terapad.com/index.cfm?fa=contentNews.newsDetails&newsID=37030&from=list
        Public Shared Function LevenshteinDistance(ByVal s As String, ByVal t As String) As Integer
            Dim sLength As Integer = s.Length ' length of s
            Dim tLength As Integer = t.Length ' length of t
            Dim lvCost As Integer ' cost
            Dim lvDistance As Integer = 0
            Dim zeroCostCount As Integer = 0
    
            Try
                ' Step 1
                If tLength = 0 Then
                    Return sLength
                ElseIf sLength = 0 Then
                    Return tLength
                End If
    
                Dim lvMatrixSize As Integer = (1 + sLength) * (1 + tLength)
                Dim poBuffer() As Integer = New Integer(0 To lvMatrixSize - 1) {}
    
                ' fill first row
                For lvIndex As Integer = 0 To sLength
                    poBuffer(lvIndex) = lvIndex
                Next
    
                'fill first column
                For lvIndex As Integer = 1 To tLength
                    poBuffer(lvIndex * (sLength + 1)) = lvIndex
                Next
    
                For lvRowIndex As Integer = 0 To sLength - 1
                    Dim s_i As Char = s(lvRowIndex)
                    For lvColIndex As Integer = 0 To tLength - 1
                        If s_i = t(lvColIndex) Then
                            lvCost = 0
                            zeroCostCount += 1
                        Else
                            lvCost = 1
                        End If
                        ' Step 6
                        Dim lvTopLeftIndex As Integer = lvColIndex * (sLength + 1) + lvRowIndex
                        Dim lvTopLeft As Integer = poBuffer(lvTopLeftIndex)
                        Dim lvTop As Integer = poBuffer(lvTopLeftIndex + 1)
                        Dim lvLeft As Integer = poBuffer(lvTopLeftIndex + (sLength + 1))
                        lvDistance = Math.Min(lvTopLeft + lvCost, Math.Min(lvLeft, lvTop) + 1)
                        poBuffer(lvTopLeftIndex + sLength + 2) = lvDistance
                    Next
                Next
            Catch ex As ThreadAbortException
                Err.Clear()
            Catch ex As Exception
                WriteDebugMessage(Application.StartupPath , [Assembly].GetExecutingAssembly().GetName.Name.ToString, MethodBase.GetCurrentMethod.Name, Err)
            End Try
    
            Return lvDistance - zeroCostCount
        End Function
    
        2
  •  2
  •   Mark Brackett    18 年前

    SSIS(在Sql 2005+Enterprise中)具有 Fuzzy Lookup 它就是为这种数据清理问题而设计的。

    除此之外,我只知道特定领域的解决方案,例如 address cleaning ,或一般 string matching techniques .

        3
  •  2
  •   MusiGenesis    18 年前

    有许多供应商提供产品来进行这种模式匹配。我会做一些调查和研究 找到一个好的,声誉良好的产品,并放弃国产系统 .

    正如你所说,你的产品只是好的,这是企业的普遍需求,我相信有不止一种优秀的产品。即使一个许可证要花费几千美元,它仍然比支付一批开发者在内部工作要便宜。

    此外,短语“错综复杂”、“CPU密集型”、“VBA代码”和“Access数据库”同时出现在您的系统描述中,这也是找到好的第三方工具的另一个原因。

    编辑:也有可能.NET有一个内置的组件来做这种事情,在这种情况下,你不必为此付费。我仍然偶尔会对.NET提供的工具感到惊讶。

        4
  •  2
  •   Community Mohan Dere    9 年前

    我正在处理完全相同的问题。看看:

    Tools for matching name/address data

    寻找一些可能有用的工具。

        5
  •  1
  •   HLGEM    18 年前

    Access实际上没有用于此目的的工具。在理想情况下,我会使用SSIS解决方案并使用模糊查找。但是,如果您目前正在使用Access,我认为您的办公室购买SQL Server Enterprise edition的可能性很低。如果你被当前的环境所困扰,你可以尝试一种蛮力的方法。

    至于公司名称,您可以尝试匹配名称的前5个字符和地址或电话。您还可以创建一个表,其中包含已知的变体以及它们在数据库中的相关内容,以用于清理将来的文件。因此,如果您的id为100的记录是Acme,Inc.的,那么您可以有这样一个表:

    idfield名称

    100 Acme公司

    100 Acme公司

    100 Acme有限责任公司

    100顶点

    如果您在每次查找和修复重复项(使其成为重复数据消除过程的一部分)以及每次能够将名称和地址的第一部分与现有公司匹配时都创建一个条目,那么这将是一个很小的开始,但会随着时间的推移而构建。

    我还会看看Torial发布的函数,看看它是否有用。

    所有这些都将是痛苦和耗时的,但随着时间的推移,当您发现新的变体并将其添加到代码或列表中时,情况会变得更好。如果您确实决定对addressdata进行标准化,请确保首先清理生产数据,然后对工作表执行任何导入并清理,然后尝试与生产数据匹配并插入新记录。

        6
  •  0
  •   TBarnes    13 年前

    有很多方法可以解决这个问题,但这些方法可能并不明显。最好的方法是找到唯一的标识符,用于在字段外匹配拼写错误等。

    一些想法

    1. 明显的,社会保险号码,驾驶执照等
    2. 电子邮件地址
    3. 已清除的电话号码(删除标点符号等)

    就供应商而言,我刚刚回答了一个类似的问题,我将粘贴到下面。

    每个主要提供商都有自己的解决方案。Oracle、IBM、SAS Dataflux等公司都声称在这类问题上是最优秀的。

    独立验证评估:

    澳大利亚科廷大学数据链接中心进行了一项研究,模拟了440万条记录的匹配。确定提供商在准确性方面的情况(找到的匹配数与可用的匹配数。错误匹配数)

    DataMatch Enterprise, 最高精度(>95%),非常快速,成本低

    IBM Quality Stage ,精度高(>90%),速度快,成本高(>10万美元)

    这是我们能找到的最好的独立评估,非常彻底。