题
我们有一个SQL Server表含有公司名称、地址、联系人姓名(及其他)。
我们经常收到的数据文件从外部来源,需要我们的匹配起来反对这表。不幸的是,数据略有不同,因为它来自一个完全不同的系统。例如,我们有"123E.主街"我们收到"123东主街"。另一个例子,我们有"尖端,有限责任公司",该文件包含"Acme Inc.".另一个是,我们有"埃德*史密斯"他们"的爱德华史密斯"
我们有一个遗留系统,使用了一些相当复杂和CPU密集的方法处理这些相匹配。一些涉及纯SQL和其他涉及载>>>情绪的一个Access数据库。目前的系统是好的,但不完善和繁琐和难以维持
管理这里想要扩大其使用。开发商将继承的支持系统想要更换一个更敏捷的解决方案,需要较少的维修。
是否有一个普遍接受的方式处理这种数据匹配?
解决方案
这是我为几乎相同的堆栈编写的内容(我们需要标准化硬件的制造商名称,并且有各种各样的变体)。这是客户端(确切地说是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
其他提示
有许多供应商提供产品来进行这种模式匹配。我会做一些研究,并且找到一个好的,知名的产品并废弃本土系统。
正如你所说,你的产品只是好的,这对于企业来说是一种普遍的需求,我相信那里有不止一种优秀的产品。即使许可证花费几千美元,它仍然比支付一堆开发人员在内部工作更便宜。
此外,短语“复杂”,“CPU密集”,“VBA代码”等事实也是如此。和“访问数据库”在您的系统描述中一起出现是找到一个好的第三方工具的另一个原因。
编辑:.NET也有可能有一个内置组件来执行此类操作,在这种情况下,您不必为此付费。我仍然会偶尔通过.NET提供的工具感到惊讶。访问并没有真正的工具。在一个理想的世界,我会去的SSIS解决方案,并利用模糊查找。但如果你是目前使用访问的机会你的办公室购买SQL服务器的企业的版本似乎低到我。如果你坚持目前的环境中,你可以尝试一种强力的方法。
开始与标准化清洁的地址。挑选标准缩写为街路,等等。以及编写代码,以改变所有的正常的变化对这些标准addesses.替换任何实例中的两个空间的一个空间,装饰的所有数据和去除任何非字母数字符。正如你可以看到这是一个相当任务。
作为对公司名称,也许你可以试着匹配上的第一个5个字符的姓名和地址或电话。你也可以创建一个表格的已知变化和什么他们将涉及在数据库中用于cleanising未来的文件。所以,如果你记录与id100Acme,Inc.你可以有一个表这样的:
(例如坐标系的名字
100Acme,Inc.
100Acme公司
100Acme,代
100Acme,有限责任公司
100Acme
这将开始小,但建立随着时间的推移,如果你让一个条目的每一次你发现和解决重复(让你的一部分de-dupping过程)和如果你让一个条目的每一次你都能够匹配的第一部分姓名和地址给一个现有公司。
我也想看看这一职能Torial贴,看看是否有帮助。
所有这一切都将是痛苦和耗时,但将得到更好的随着时间的推移你会发现新的变化和增加他们的代码或清单。如果你决定要stardardize你addressdata,确保清洁生产数据,然后再做任何进口到工作表格和干净它,然后试着匹配以生产数据,并插入新的记录。
我刚刚找到了相关的链接。
我发誓我在发布之前就已经看了。
有很多方法可以解决这个问题,这可能并不明显。最好的方法是找到唯一的标识符,您可以使用这些标识符来填充字段以外的错误拼写等等。
一些想法
- 显而易见的社会安全号码,驾驶执照等
- 电子邮件地址
- 已清理的电话号码(Rremove标点符号等) 醇>
就供应商而言,我刚回答了一个类似的问题,并在下面粘贴。
每个主要提供商都有自己的解决方案。 Oracle,IBM,SAS Dataflux等都声称在这类问题上表现最好。
独立验证评估:
在澳大利亚科廷大学数据链接中心进行的一项研究模拟了440万条记录的匹配。确定了提供商在准确性方面的优势(找到的匹配数与可用数量。错误匹配数)
DataMatch Enterprise,最高准确度(> 95%),非常快速,低成本
IBM Quality Stage ,高准确度(&gt; 90%),非常快,成本高(> 100K美元)
SAS数据通量,中等准确度(> 85%),快速,高成本(> 100K) 这是我们能找到的最好的独立评估,非常彻底。