Вопрос
У нас есть таблица SQL Server, содержащая название компании, адрес и имя контактного лица (среди прочего).
Мы регулярно получаем файлы данных из внешних источников, которые требуют от нас сверки с этой таблицей.К сожалению, данные немного отличаются, поскольку поступают из совершенно другой системы.Например, у нас есть «123 Е.Мейн-стрит», и мы получаем «123 Ист-Мейн-стрит».Другой пример: у нас есть «Acme, LLC», а файл содержит «Acme Inc.».Другой вариант: у нас есть «Эд Смит», а у них есть «Эдвард Смит».
У нас есть устаревшая система, в которой для обработки таких совпадений используются довольно сложные и ресурсоемкие методы.Некоторые используют чистый SQL, а другие используют код VBA в базе данных Access.Существующая система хороша, но не идеальна, громоздка и сложна в обслуживании.
Руководство здесь хочет расширить его использование.Разработчики, которые унаследуют поддержку системы, хотят заменить ее более гибким решением, требующим меньшего обслуживания.
Существует ли общепринятый способ справиться с таким сопоставлением данных?
Решение
Вот что я написал для почти идентичного стека (нам нужно было стандартизировать названия производителей оборудования, и были всевозможные вариации).Однако это клиентская сторона (точнее, VB.Net) - и используйте алгоритм расстояния Левенштейна (модифицированный для лучших результатов):
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+ Enterprise) имеет Нечеткий поиск который предназначен именно для таких задач очистки данных.
Помимо этого, я знаю только решения, специфичные для предметной области, такие как очистка адреса, или общий методы сопоставления строк.
Существует множество поставщиков, предлагающих продукты для такого рода сопоставления с образцом.Я бы провел небольшое исследование и Найдите хороший продукт с хорошей репутацией и откажитесь от отечественной системы..
Как вы говорите, ваш продукт только хорош, и это достаточно распространенная потребность в бизнесе, и я уверен, что существует более одного превосходного продукта.Даже если лицензия будет стоить несколько тысяч долларов, это все равно будет дешевле, чем платить группе разработчиков за работу над чем-то собственными силами.
Кроме того, тот факт, что фразы «сложный», «интенсивный процессор», «код VBA» и «база данных доступа» встречаются вместе в описании вашей системы, является еще одной причиной найти хороший сторонний инструмент.
РЕДАКТИРОВАТЬ:Также возможно, что в .NET есть встроенный компонент, который делает подобные вещи, и в этом случае вам не придется за него платить.Я до сих пор время от времени удивляюсь инструментам, которые предлагает .NET.
Я имею дело с точно такой же проблемой.Взгляни на:
Инструменты для сопоставления данных имени/адреса
для некоторых инструментов, которые могут помочь.
В Access на самом деле нет инструментов для этого.В идеальном мире я бы выбрал решение SSIS и использовал нечеткий поиск.Но если вы в настоящее время используете Access, шансы на то, что ваш офис купит версию SQL Server Enterprise, кажутся мне низкими.Если вы застряли в текущей среде, вы можете попробовать метод грубой силы.
Начните со стандартизированной очистки адресов.Подберите стандартные сокращения для Street, raod и т. д.и напишите код, чтобы изменить все обычные варианты этих стандартных адресов.Замените любые экземпляры двух пробелов одним пробелом, обрежьте все данные и удалите все небуквенно-цифровые символы.Как видите, это довольно сложная задача.
Что касается названий компаний, возможно, вы можете попробовать сопоставить первые 5 символов имени и адреса или телефона.Вы также можете создать таблицу известных вариантов и того, к чему они будут относиться в вашей базе данных, чтобы использовать ее для очистки будущих файлов.Итак, если вы записываете с идентификатором 100, это Acme, Inc.у вас может быть такая таблица:
Имя поля идентификатора
100 Акме, Инк.
100 Акме, Инк.
100 Акме, Инкорпорейтед
100 Акме, ООО
100 акме
Это начнется с малого, но со временем будет развиваться, если вы будете делать запись каждый раз, когда найдете и исправить дубликат (сделайте это частью процесса удаления дубликатов), и если вы будете делать запись каждый раз, когда сможете сопоставить первую часть название и адрес существующей компании.
Я бы также посмотрел на эту функцию, опубликованную Ториалом, и посмотрел, поможет ли она.
Все это будет болезненным и трудоемким, но со временем станет лучше, когда вы найдете новые варианты и добавите их в код или список.Если вы все же решили классифицировать свои адресные данные, сначала очистите производственные данные, затем выполните импорт в рабочую таблицу и очистите ее, а затем попытайтесь сопоставить производственные данные и вставить новые записи.
Я только что нашел это связь это связано.
Клянусь, я посмотрел, прежде чем опубликовать это.
Есть довольно много способов решить эту проблему, которые могут быть неочевидными.Лучше всего найти уникальные идентификаторы, которые можно использовать для сопоставления за пределами полей с ошибками в написании и т. д.
Некоторые мысли
- Очевидное: номер социального страхования, водительские права и т. д.
- Адрес электронной почты
- Очищенный номер телефона (удалена пунктуация и т. д.)
Что касается поставщиков, я только что ответил на аналогичный вопрос и вставляю ниже.
У каждого крупного провайдера есть свое собственное решение.Oracle, IBM, SAS Dataflux и т. д., и каждая из них претендует на звание лучшего в решении подобных задач.
Независимая проверенная оценка:
В Центре связи данных Университета Кертина в Австралии было проведено исследование, в котором моделировалось сопоставление 4,4 миллиона записей.Определили, что было у поставщиков с точки зрения точности (количество найденных совпадений и доступных.Количество ложных совпадений)
ДатаМатч Предприятие, Высочайшая точность (>95%), очень быстрая, низкая стоимость
Этап качества IBM , высокая точность (>90%), очень быстрая, высокая стоимость (>100 тыс. долларов США)
Поток данных SAS, точность средней (> 85%), быстрая, высокая стоимость (> 100K), которая была лучшей независимой оценкой, которую мы могли найти, была очень тщательной.