按需模糊查找

db2*_*db2 6 sql-server-2008 sql-server ssis

我们有一个客户表(谁没有?),其中包含许多从业务角度来看是重复的记录。我已经能够创建一个 SSIS 包来执行模糊分组,并报告潜在的重复项。

现在,假设我想在有人进入新客户时进行这种分析。这个想法是对客户名称(可能还有一些其他基本信息,如邮政编码)执行模糊查找,并在继续客户创建表单之前显示潜在的重复项。

这里明显的问题是模糊分组和查找组件是 SSIS 的一部分。如果我想按需运行那些,我必须做一些疯狂的事情,比如将搜索词放在临时表中,运行 SSIS 包,等待它完成,并从输出表中获取结果。这会很慢,很痛苦,并且有严重的并发问题。

因此,另一个想法是使用全文索引。在试用它时,它看起来不合适。它无法捕捉到客户名称的细微拼写错误,或“Company”与“Corporation”与“Co.”或“Anderson”与“Andersen”以及其他此类变体的名称不同的名称。

有没有什么东西可以让 T-SQL 灵活地进行模糊分组/匹配?我可以通过模糊查找来保存标记,但看起来我仍然需要重新实现大部分匹配算法才能使用它们。

Rac*_*hel 2

过去,我在 .Net CLR 函数中构建了“模糊搜索”。该函数的调用方式与用户定义函数的调用方式相同。

例如,

select id, name
from customers
where dbo.CompareStrings("newCustomerName", customers.name) > .8
Run Code Online (Sandbox Code Playgroud)

只会返回姓名与输入姓名 80% 相似的客户。

% 匹配基于将一个值转换为另一个值所需的更改数量,而不是不同的字符数。我们用它来比较地址,发现这种方法更有效,因为使用了许多街道缩写。

这是我用来比较字符串的代码。我很久以前就这样做了,以至于我不记得如何部署它,尽管快速搜索会向您展示许多有关如何创建 SQL CLR 函数的文章

' Checks two strings against each other and returns a decimal between 0 (doesn't match at all) and 1 (100% match)
<Microsoft.SqlServer.Server.SqlFunction()> _
Public Shared Function CompareStrings(ByVal input1 As SqlChars, ByVal input2 As SqlChars) _
As <SqlFacet(Precision:=10, Scale:=4)> SqlDecimal

    If IsNothing(input1) And IsNothing(input2) Then
        Return New SqlDecimal(1.0)
    ElseIf IsNothing(input1) Or IsNothing(input2) Then
        Return New SqlDecimal(0.0)
    End If

    Dim s1 As String = New String(input1.Value)
    Dim s2 As String = New String(input2.Value)

    If s1.Length = 0 Or s2.Length = 0 Then
        Return New SqlDecimal(1.0)
    Else
        Dim re As New Regex("[^A-Za-z0-9 ]", RegexOptions.IgnorePatternWhitespace Xor RegexOptions.Singleline)
        s1 = re.Replace(s1, "( )\1*", "$1")
        s2 = re.Replace(s2, "( )\1*", "$1")
        s1 = UCase(re.Replace(s1, ""))
        s2 = UCase(re.Replace(s2.ToString, ""))

        Dim dif As Integer = GetStringSimilarity(s1, s2)
        Dim max As Integer = s1.Length
        If s2.Length > max Then max = s2.Length

        Return New SqlDecimal(1.0 - (dif / max))
    End If
End Function

' Compares two strings using the relationship in patterns of letters
Private Shared Function GetStringSimilarity(ByVal s1 As String, ByVal s2 As String) As Integer
    Dim n As Integer = s1.Length
    Dim m As Integer = s2.Length
    Dim distance(n + 1, m + 1) As Integer

    Dim cost As Integer = 0
    If n = 0 Then Return m
    If m = 0 Then Return n

    For i As Integer = 0 To n
        distance(i, 0) = i
    Next
    For j As Integer = 0 To m
        distance(0, j) = j
    Next

    For i As Integer = 1 To n
        For j As Integer = 1 To m
            If Mid(s2, j, 1) = Mid(s1, i, 1) Then cost = 0 Else cost = 1
            distance(i, j) = Min3(distance(i - 1, j) + 1, distance(i, j - 1) + 1, distance(i - 1, j - 1) + cost)
        Next
    Next
    Return distance(n, m)
End Function

' Returns the min of 3 values
Private Shared Function Min3(ByVal x As Integer, ByVal y As Integer, ByVal z As Integer) As Integer
    Dim min As Integer = x
    If y < min Then min = y
    If z < min Then min = z
    Return min
End Function
Run Code Online (Sandbox Code Playgroud)

  • @db2 这太糟糕了。我们对该脚本的主要用途是将大约 900 个公司地址与大约 300 万个消费者地址进行比较,该过程大约需要 2 分钟。该脚本过去可以在具有 8GB RAM 的 Windows 2003(32 位)上运行,没有任何问题(从那时起我们已经升级了 sql 服务器)。也许您可以研究一下为什么 CLR 函数在您的计算机上运行得如此缓慢? (2认同)