数据比较
我们有一个SQL Server表,其中包含"公司名称","地址"和"联系人姓名"(以及其他名称)。
我们会定期从外部来源接收数据文件,这些数据文件要求我们对此表进行匹配。不幸的是,由于数据来自完全不同的系统,因此数据略有不同。例如,我们有" 123 E. Main St."我们会收到"东大街123号"。另一个示例,我们有" Acme,LLC",文件包含" Acme Inc."。另一个是,我们有"爱德·史密斯",而他们有"爱德华·史密斯"
我们有一个遗留系统,该系统利用一些相当复杂且占用大量CPU的方法来处理这些匹配项。一些涉及纯SQL,而其他涉及Access数据库中的VBA代码。当前的系统是好的,但不是完美的,麻烦且难以维护
此处的管理层希望扩大其用途。将继承该系统支持的开发人员希望用一种更灵活的解决方案来替换它,该解决方案需要更少的维护。
有一种普遍接受的方式来处理这种数据匹配吗?
解决方案
这是我为几乎相同的堆栈编写的(我们需要标准化硬件的制造商名称,并且有各种各样的变体)。但是,这是客户端(准确地说是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
SSIS(在Sql 2005+企业版中)具有"模糊查找"功能,该功能专门用于解决此类数据清除问题。
除此之外,我只知道特定于域的解决方案,例如地址清除或者常规的字符串匹配技术。
有很多供应商提供产品来进行这种模式匹配。我会做一些研究,找到一个信誉良好的好产品,然后放弃自己生产的系统。
正如我们所说,产品仅是好产品,而这对于企业来说已经足够了,我确信这里有不止一种优秀的产品。即使许可证的价格为几千美元,它仍然比付给一群开发人员内部开发工作要便宜。
同样,短语"复杂"," CPU密集型"," VBA代码"和"访问数据库"一起出现在系统的说明中,这也是找到好的第三方工具的另一个原因。
编辑:.NET也可能具有执行此类操作的内置组件,在这种情况下,我们无需为此付费。 .NET所提供的工具仍然让我感到有些惊讶。
我正在处理完全相同的问题。看一眼:
匹配名称/地址数据的工具
一些可能有用的工具。
Access确实没有用于此的工具。在理想情况下,我将使用SSIS解决方案并使用模糊查找。但是,如果我们当前正在使用Access,那么对我来说,办公室购买SQL Server Enterprise版的机会似乎很小。如果我们对当前的环境感到困惑,则可以尝试使用蛮力方法。
从标准的地址清理开始。 PIck Street,Raod等的标准缩写,并编写代码以将所有常规变体更改为这些标准附件。用一个空格替换两个空格的任何实例,修剪所有数据并删除所有非字母数字字符。如我们所见,这是一项艰巨的任务。
至于公司名称,也许我们可以尝试在名称的前5个字符与地址或者电话上进行匹配。我们还可以创建一个表,其中包含已知变体以及它们在数据库中所涉及的内容,以用于清理将来的文件。因此,如果ID为100的记录是Acme,Inc.,则可能有一个这样的表:
idfield名称
100 Acme,Inc.
100 Acme,Inc
100 Acme,Incorporated
100 Acme,LLC
100 Acme
如果我们每次每次查找并修复重复项时都进行输入(使其成为去重复过程的一部分),并且每次都能够进行匹配时都进行输入,则此操作开始时会逐渐建立到现有公司的名称和地址。
我还要看一下Torial发布的功能,看看是否有帮助。
所有这些都是痛苦且耗时的,但是随着时间的推移,发现新的变体并将它们添加到代码或者列表中会变得更好。如果我们确实决定对地址数据进行标准处理,请确保先清除生产数据,然后再导入工作表并进行清洁,然后尝试与生产数据匹配并插入新记录。
我刚刚找到了与此相关的链接。
我发誓在发布此消息之前已经看过了。