Я нахожусь в процессе создания системы, в которой пользователи должны зарегистрироваться. Эти пользователи, вероятно, также будут частью более крупной базы данных клиентов, и я хотел бы связать регистрацию с идентификатором пользователя в более крупной базе данных клиентов.
База данных клиентов несколько неполная. У некоторых клиентов просто есть телефонный номер, и он может иметь пробелы в разных местах в зависимости от того, кто / что ввел его. У других клиентов есть только адрес электронной почты, и он может содержать опечатки из-за того, что он был написан от руки, а затем обработан кем-то еще позже. Совсем кошмар на самом деле.
Я хотел бы найти ближайшую запись к тому, что пользователь ввел в систему, которую я строю. Эти данные довольно просты и будут проверены. Эти данные:
Моя первоначальная мысль — использовать алгоритм расстояния Левенштейна для вычисления «расстояния строки» для каждого из полей, если они не пусты, а затем упорядочить по общему количеству баллов. В приведенном ниже коде не показано, чтобы все было хорошо и читабельно, но я, очевидно, также обрежу (возможно, даже просто уберу) весь пробел.
Как псевдокод:
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 для обеих баз данных.
Я здесь на правильном пути или мне следует использовать что-то кроме Левенштейна? Стоит ли сравнивать какую-то комбинацию баллов по всем полям?
Трек, безусловно, правильный, но я бы добавил несколько заметок.
Подготовка данных
Прежде всего, для соответствия я рекомендую преобразовать данные, чтобы устранить, возможно, весь шум, например. конвертировать строки в верхний регистр, удалять пробелы, удалять все нецифровые цифры из телефонных номеров и т. д.
Нахождение ближайшего совпадения в неполных данных
Во-вторых, установка произвольных порогов (например, «меньше 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, вы можете подумать о каком-то флаге, позволяющем людям решать. Я уверен, что после некоторого времени, проведенного в обзоре, вы придумаете больше правил для его автоматизации.
Других решений пока нет …