Сравните имена, используя расстояние Левенштейна - PullRequest
0 голосов
/ 25 апреля 2018

В моем приложении мне нужно идентифицировать человека, ища его фамилию и имя. Одно из требований - допускать орфографические ошибки в определенной степени .

Мои попытки идентифицировать человека по имени и фамилии были:

  1. SQL-запрос с использованием soundex
  2. sql-запрос с использованием levenshtein-distance (LD), который был рассчитан с помощью этой LD-функции

На скриншоте содержатся некоторые записи теста и результат моего sql-запроса, который включает значение soundex для каждого столбца и LD

compare records using levenshtein distance

Мой текущий запрос выглядит так

SELECT t2.*
        , t1.Firstname + ' ' + t1.Lastname as SourceName
        , 'Torsten Mueller' as TargetName
        , dbo.FUNC_LEVENSHTEIN(t1.Firstname +' '+ t1.Lastname
                            , 'Torsten Mueller', 8) as LEVENSHTEIN_Distance     
 FROM #TestSoundex t1
 LEFT JOIN #TestSoundex t2 ON t1.Id = t2.Id
 WHERE t1.Soundex_Firstname = SOUNDEX('Torsten')
       AND t1.Soundex_Lastname = SOUNDEX('Mueller')

Как вы видите, я сначала фильтрую результат по soundex и вычисляю расстояние Левенштейна для оставшихся записей. В этом примере ниже расстояние Левенштейна варьируется от 0 (обе строки равны) до 3.

SourceName       | TargetName      | Levenshtein Distance 
Thorsten Müller  | Torsten Mueller |  3 
Torsten Müller   | Torsten Mueller |  2
Thorsten Mueller | Torsten Mueller |  1
Torsten Mueller  | Torsten Mueller |  0

В этом выступлении профессора Стэнфорда поясняется расчет расстояния:

I N T E * N TION 
| | | | | | | 
* E X E C U TION
d s s   i s

Каждое удаление d, вставка i добавляет 1 балл, замена s добавляет 2 балла. LD-function, который я использую, возвращает 5 точек для примера выше, но только 3 вместо 4 для расстояния между Thorsten Müller и Torsten Mueller. I

+1 point to delete h, 
+1 point instead of 2 to substitute ü 
+1 point to insert e

Итак, я добавил несколько образцов

Samples with Umlaut

Вопросы

У меня сложилось впечатление, что ни soundex, ни LD недостаточно для однозначной идентификации записи человека с учетом firstname и lastname и с учетом того, что могут быть несоответствия правописания.

  • Можете ли вы объяснить, как эта функция LD обрабатывает Umlaute ü,ö,ä, чтобы я мог лучше понять вычисления?
  • Что бы вы порекомендовали в качестве максимального значения для distance, чтобы найти правильное совпадение имени и фамилии с учетом строки s и t, должно ли оно основываться на длине обеих строк numberOrCharacters(s+t)/2 = max?

Исходный код

Это функция, которую я использую из связанного ответа . Я только изменил название функции с edit_distance_within на FUNC_LEVENSHTEIN

SET QUOTED_IDENTIFIER ON 
GO
SET ANSI_NULLS ON 
GO

CREATE FUNCTION FUNC_LEVENSHTEIN(@s nvarchar(4000), @t nvarchar(4000), @d int)
RETURNS int
AS
BEGIN
  DECLARE @sl int, @tl int, @i int, @j int, @sc nchar, @c int, @c1 int,
    @cv0 nvarchar(4000), @cv1 nvarchar(4000), @cmin int
  SELECT @sl = LEN(@s), @tl = LEN(@t), @cv1 = '', @j = 1, @i = 1, @c = 0
  WHILE @j <= @tl
    SELECT @cv1 = @cv1 + NCHAR(@j), @j = @j + 1
  WHILE @i <= @sl
  BEGIN
    SELECT @sc = SUBSTRING(@s, @i, 1), @c1 = @i, @c = @i, @cv0 = '', @j = 1, @cmin = 4000
    WHILE @j <= @tl
    BEGIN
      SET @c = @c + 1
      SET @c1 = @c1 - CASE WHEN @sc = SUBSTRING(@t, @j, 1) THEN 1 ELSE 0 END
      IF @c > @c1 SET @c = @c1
      SET @c1 = UNICODE(SUBSTRING(@cv1, @j, 1)) + 1
      IF @c > @c1 SET @c = @c1
      IF @c < @cmin SET @cmin = @c
      SELECT @cv0 = @cv0 + NCHAR(@c), @j = @j + 1
    END
    IF @cmin > @d BREAK
    SELECT @cv1 = @cv0, @i = @i + 1
  END
  RETURN CASE WHEN @cmin <= @d AND @c <= @d THEN @c ELSE -1 END
END
GO

Источник для проверки функции выше

Это еще один тест

CREATE TABLE #TestLevenshteinDistance(
    Id int  IDENTITY(1,1) NOT NULL,
    SourceName nvarchar(100) NULL,  
    Soundex_SourceName varchar(4) NULL,    
    Targetname nvarchar(100) NULL, 
    Soundex_TargetName varchar(4) NULL, 
    );      

INSERT INTO #TestLevenshteinDistance 
    (    SourceName,          
         Soundex_SourceName,
         Targetname,
         Soundex_TargetName) 
VALUES 
   ('Intention',SOUNDEX('Intention'), 'Execution', SOUNDEX('Execution')),    
   ('Karsten' , SOUNDEX('Karsten'), 'Torsten', SOUNDEX('Torsten')); 


SELECT t1.*
        , dbo.FUNC_LEVENSHTEIN(t1.SourceName, t1.Targetname, 8) as LEVENSHTEIN_Distance
        FROM #TestLevenshteinDistance t1
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...