Нахождение одной записи пользователя в некоторых неполных данных?

Я нахожусь в процессе создания системы, в которой пользователи должны зарегистрироваться. Эти пользователи, вероятно, также будут частью более крупной базы данных клиентов, и я хотел бы связать регистрацию с идентификатором пользователя в более крупной базе данных клиентов.

База данных клиентов несколько неполная. У некоторых клиентов просто есть номер телефона, и в нем могут быть пробелы в разных местах в зависимости от того, кто/что ввел его. У других клиентов есть только адрес электронной почты, и в нем вполне могут быть опечатки из-за того, что он был написан от руки, а затем обработан кем-то другим. Настоящий кошмар на самом деле.

Я хотел бы найти ближайшую запись к тому, что пользователь ввел в систему, которую я создаю. Эти данные довольно просты и будут проверены. Эти данные:

  • Имя
  • Фамилия
  • Дата рождения (ГГГГ-ММ-ДД)
  • Адрес электронной почты
  • Номер телефона

Моя первоначальная мысль состоит в том, чтобы использовать алгоритм расстояния Левенштейна для вычисления «расстояния между строками» для каждого из полей, если они не пусты, а затем упорядочить по общему баллу. Не показано в приведенном ниже коде, чтобы все было красиво и читабельно, но я, очевидно, обрежу (возможно, даже просто удалю) все пробелы.

Как псевдокод:

SELECT c.customerID
FROM   customers c
WHERE  ( c.first_name IS NULL OR ( Levenshtein(c.first_name, $first_name) < 3 ) )
AND    ( c.last_name IS NULL OR ( Levenshtein(c.last_name, $last_name) < 3 ) )
AND    ( c.email IS NULL OR ( Levenshtein(c.email, $email) < 3 ) )
AND    ( c.telephone IS NULL OR ( Levenshtein(c.telephone, $telephone) < 3 ) )

Просто к вашему сведению, я использую PHP (Laravel) и MySQL для обеих баз данных.

Я на правильном пути или мне следует использовать что-то другое, кроме Левенштейна? Должен ли я сравнить какую-то комбинацию оценок всех полей?


person Mike    schedule 13.01.2015    source источник


Ответы (1)


Трек определенно правильный, но я бы добавил несколько замечаний.

Подготовка данных

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

Поиск ближайшего совпадения в неполных данных

Во-вторых, установка произвольных порогов (например, «менее 3» выше) делает его немного жестким. Хотя это требует больше ресурсов процессора, вам может быть лучше отсортировать результаты по «коэффициенту различия»:

SELECT c.customerID
FROM   customers c
ORDER BY
Levenshtein(c.first_name, $first_name)) +
Levenshtein(c.last_name, $last_name) +
Levenshtein(c.email, $email) +
Levenshtein(c.telephone, $telephone) asc
LIMIT 0,1;

Очевидно, вы можете добавить некоторую безопасность, чтобы не совпадать, когда различия смехотворно велики, но вы поняли идею. В тех случаях, когда у обоих объектов отсутствуют данные в одном и том же поле (например, у обоих отсутствует электронная почта), подход все еще в порядке. Проблемы возникают, когда отсутствует только одна сторона — тогда мы получаем большой пинок за разницу. Мы можем немного усложнить запрос, чтобы избежать этого:

ORDER BY
(if(c.first_name is null OR c.first_name = '' OR $first_name = '', 0, Levenshtein(c.first_name, $first_name))) +
...

Сокращено до одной строки для краткости — мы рассчитываем Lev dist, только если есть данные для сравнения.

Недостатки

Для всех записей, совпадающих с коэффициентом различия больше, чем X, вы можете придумать какой-то флаг, чтобы люди могли решать. После некоторого времени, потраченного на просмотр, я уверен, что вы придумали больше правил для его автоматизации.

person ptrk    schedule 13.01.2015
comment
Прохладный. В этом есть смысл. Я подготовлю данные как можно лучше, как вы упомянули. Меня беспокоит вышеизложенное, что в базе данных может вообще не быть существующего клиента. Могут быть даже строки без этих данных (например, у нас может быть просто адрес, который я не собираю), поэтому сравнение NULL и NULL приведет к идеальному совпадению. - person Mike; 13.01.2015
comment
Правильно, но я думаю, что это имеет смысл - если нет данных в конкретном свойстве с обеих сторон, это просто не влияет на фактор. Отсутствие данных вообще (в любом поле) было бы проблемой, но это проверка. Позвольте мне немного обновить ответ. - person ptrk; 13.01.2015