数据比较

时间:2008-09-24 12:40:18

标签: sql-server textmatching

我们有一个SQL Server表,其中包含公司名称,地址和联系人姓名(等等)。

我们会定期从外部来源收到数据文件,要求我们与此表格进行匹配。不幸的是,数据略有不同,因为它来自完全不同的系统。例如,我们有“123 E. Main St.”我们收到“东大街123号”。另一个例子,我们有“Acme,LLC”,文件包含“Acme Inc.”。另一个是,我们有“埃德史密斯”,他们有“爱德华史密斯”

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

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

是否有一种普遍接受的方式来处理这种数据匹配?

7 个答案:

答案 0 :(得分:4)

这是我为几乎相同的堆栈编写的内容(我们需要标准化硬件的制造商名称,并且存在各种变体)。这是客户端(确切地说是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

答案 1 :(得分:2)

SSIS(在Sql 2005+ Enterprise中)有Fuzzy Lookup,专为此类数据清理问题而设计。

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

答案 2 :(得分:2)

有许多供应商提供产品来进行这种模式匹配。我会做一些研究,并且找到一个好的,知名的产品并废弃本土系统

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

此外,“复杂”,“CPU密集”,“VBA代码”和“访问数据库”这两个短语在您的系统描述中一起出现,这是找到一个好的第三方工具的另一个原因。

编辑:.NET也有可能有一个内置组件来执行此类操作,在这种情况下,您不必为此付费。我仍然会偶尔通过.NET提供的工具感到惊讶。

答案 3 :(得分:2)

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

Tools for matching name/address data

对于某些可能有帮助的工具。

答案 4 :(得分:1)

Access实际上并没有这方面的工具。在理想的世界中,我会使用SSIS解决方案并使用模糊查找。但是,如果您目前正在使用Access,那么您的办公室购买SQL Server Enterprise版本的机会对我来说似乎很低。如果您对当前环境感到困惑,可以尝试使用暴力方法。

从标准化清理地址开始。用于Street,raod等的PIck标准缩写,并编写代码以更改这些标准addesses的所有常规变化。用一个空格替换两个空格的任何实例,修剪所有数据并删除任何非字母数字字符。正如您所看到的,这是一项非常重要的任务。

对于公司名称,也许您可​​以尝试匹配名称的前5个字符以及地址或电话。您还可以创建一个已知变体的表以及它们与数据库中的相关内容,以用于清理将来的文件。因此,如果您使用id 100记录Acme,Inc。,您可以拥有如下表格:

idfield名称

100 Acme,Inc。

100 Acme,Inc

100 Acme,Incorporated

100 Acme,LLC

100 Acme

如果你每次找到并修复一个复制品(让它成为你的去除过程的一部分),并且每次你能够匹配第一个现有公司的名称和地址的一部分。

我还会看看Torial发布的功能,看看它是否有帮助。

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

答案 5 :(得分:0)

我刚发现这个相关的link

我发誓我在发布之前就已经看了。

答案 6 :(得分:0)

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

一些想法

  1. 显而易见的社会安全号码,驾驶执照等
  2. 电子邮件地址
  3. 已清理的电话号码(Rremove标点符号等)
  4. 就供应商而言,我刚回答了一个类似的问题,并在下面粘贴。

    每个主要提供商都有自己的解决方案。 Oracle,IBM,SAS Dataflux等都声称在这类问题上表现最好。

    独立验证评估:

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

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

    IBM Quality Stage,高准确度(> 90%),非常快,高成本(> $ 100K)

    SAS数据通量,中等准确度(> 85%),快速,高成本(> 100K) 这是我们能找到的最好的独立评估,非常彻底。