2010-07-29 14 views
7

Tengo una necesidad de hacer coincidir los clientes potenciales con una base de datos de nuestros clientes.¿Hay alguna forma de filtrar un queryset django basado en la similitud de cadenas (a la python difflib)?

Los clientes potenciales provienen de un proveedor tercero a granel (miles de registros) y las ventas nos piden (en sus palabras) "filtrar a nuestros clientes" para que no intenten vender nuestro servicio a un cliente establecido .

Obviamente, hay errores ortográficos en los clientes potenciales. Charles se convierte en Charlie, Joseph se convierte en Joe, etc. Así que no puedo hacer un filtro comparando lead_first_name con client_first_name, etc.

Necesito usar algún tipo de mecanismo string similarity.

En este momento estoy usando el precioso difflib para comparar los nombres y apellidos de los clientes potenciales con una lista generada con Client.objects.all(). Funciona, pero debido a la cantidad de clientes tiende a ser lento.

Sé que la mayoría de las bases de datos sql tienen funciones soundex y diferencia. Vea mi prueba de esto en la actualización a continuación: no funciona tan bien como difflib.

¿Hay alguna otra solución? ¿Hay una mejor solución?

Editar:

Soundex, al menos en mi db, no se comporta así como difflib.

Aquí está una prueba simple - busque "Joe Lopes" en una tabla que contiene "José Lopes":

with temp (first_name, last_name) as (
select 'Joseph', 'Lopes' 
union 
select 'Joe', 'Satriani' 
union 
select 'CZ', 'Lopes' 
union 
select 'Blah', 'Lopes' 
union 
select 'Antonio', 'Lopes' 
union 
select 'Carlos', 'Lopes' 
) 
select first_name, last_name 
    from temp 
where difference(first_name+' '+last_name, 'Joe Lopes') >= 3 
order by difference(first_name+' '+last_name, 'Joe Lopes') 

Los rendimientos por encima de "Joe Satriani" como el único partido. Incluso si se reduce el umbral de similitud a 2 no se devuelve a "Joseph Lopes" como posible coincidencia.

Pero difflib hace un trabajo mucho mejor:

difflib.get_close_matches('Joe Lopes', ['Joseph Lopes', 'Joe Satriani', 'CZ Lopes', 'Blah Lopes', 'Antonio Lopes', 'Carlos Lopes']) 
['Joseph Lopes', 'CZ Lopes', 'Carlos Lopes'] 

Edición después de la respuesta de gruszczy:

Antes de escribir la mía, me buscó y found a T-SQL implementation of Levenshtein Distance in the repository of all knowledge.

En la prueba, todavía no hará un mejor trabajo de coincidencia que difflib.

Lo que me llevó a investigar qué algoritmo hay detrás de difflib. Parece ser un modified version del algoritmo Ratcliff-Obershelp.

Infelizmente parece que no puedo encontrar otro alma amable que ya haya creado una implementación de T-SQL basada en difflib ... Haré lo que pueda cuando pueda.

Si nadie viene con una mejor respuesta en los próximos días, se lo concederé a gruszczy. Gracias, amable señor

Respuesta

2

soundex no lo ayudará, porque es un algoritmo fonético. Joe y Joseph no son fonéticamente similares, por lo que soundex no los marcará como similares.

Puede probar Levenshtein distance, que se implementa en PostgreSQL.Tal vez en su base de datos también, y si no, debería poder escribir un procedimiento almacenado, que calculará la distancia entre dos cadenas y la usará en su cálculo.

+0

me enfrentaba a una situación similar en uno de mis proyectos. Generamos y almacenamos valores personalizados de soundex en lugar de confiar en el soundex incorporado. Esto mejoró algo los partidos. Pero como gruszczy dice que esto no puede ser resuelto solo por soundex. –

+0

Una función db es una buena idea. Pero Levenshtein no es tan bueno como difflib - ver mi actualización anterior. – cethegeek

+0

¿No puedes simplemente establecer una mayor distancia para la función levenshtein? Cuanto mayor sea, más resultados producirá. – gruszczy

Cuestiones relacionadas