Estoy buscando una biblioteca de JavaScript de búsqueda difusa para filtrar una matriz. Intenté usar fuzzyset.js y fuse.js , pero los resultados son terribles (hay demostraciones que puede probar en las páginas vinculadas).
Después de leer un poco sobre la distancia de Levenshtein, me parece una mala aproximación de lo que buscan los usuarios cuando escriben. Para aquellos que no lo saben, el sistema calcula cuántas inserciones , eliminaciones y sustituciones se necesitan para hacer coincidir dos cadenas.
Un defecto obvio, que se corrige en el modelo de Levenshtein-Demerau, es que tanto el blub como el boob se consideran igualmente similares al bulbo (cada uno requiere dos sustituciones). Sin embargo, está claro que bulb es más similar a blub que boob , y el modelo que acabo de mencionar lo reconoce al permitir transposiciones .
Quiero usar esto en el contexto de la finalización de texto, por lo que si tengo una matriz ['international', 'splint', 'tinder']
y mi consulta es int , creo que internacional debería tener una clasificación más alta que la tablilla , aunque la primera tiene una puntuación (más alta = peor) de 10 frente al 3 de este último.
Entonces, lo que estoy buscando (y crearé si no existe) es una biblioteca que haga lo siguiente:
- Pesa las diferentes manipulaciones de texto
- Pesa cada manipulación de manera diferente dependiendo de dónde aparecen en una palabra (las manipulaciones tempranas son más costosas que las manipulaciones tardías)
- Devuelve una lista de resultados ordenados por relevancia.
¿Alguien se ha encontrado con algo como esto? Me doy cuenta de que StackOverflow no es el lugar para pedir recomendaciones de software, pero implícito (¡ya no!) En lo anterior es: ¿estoy pensando en esto de la manera correcta?
Editar
Encontré un buen artículo (pdf) sobre el tema. Algunas notas y extractos:
Las funciones afines de distancia de edición asignan un costo relativamente menor a una secuencia de inserciones o eliminaciones
la función de distancia de Monger-Elkan (Monge y Elkan 1996), que es una variante afín de la función de distancia de Smith-Waterman (Durban et al. 1998) con parámetros de costo particulares
Para la distancia de Smith-Waterman (wikipedia) , "En lugar de mirar la secuencia total, el algoritmo de Smith-Waterman compara segmentos de todas las longitudes posibles y optimiza la medida de similitud". Es el enfoque de n-gramas.
Una métrica muy similar, que no se basa en un modelo de distancia de edición, es la métrica de Jaro (Jaro 1995; 1989; Winkler 1999). En la literatura sobre vinculación de registros, se han obtenido buenos resultados utilizando variantes de este método, que se basa en el número y el orden de los caracteres comunes entre dos cadenas.
Una variante de esto debido a Winkler (1999) también usa la longitud P del prefijo común más largo
(parece estar destinado principalmente a cadenas cortas)
Para completar el texto, los enfoques de Monger-Elkan y Jaro-Winkler parecen tener más sentido. La adición de Winkler a la métrica de Jaro pondera de manera efectiva los comienzos de las palabras más. Y el aspecto afín de Monger-Elkan significa que la necesidad de completar una palabra (que es simplemente una secuencia de adiciones) no la desaprovechará demasiado.
Conclusión:
la clasificación TFIDF se desempeñó mejor entre varias métricas de distancia basadas en tokens, y una métrica de distancia de edición de brecha afín sintonizada propuesta por Monge y Elkan se desempeñó mejor entre varias métricas de distancia de edición de cadenas. Una métrica de distancia sorprendentemente buena es un esquema heurístico rápido, propuesto por Jaro y luego ampliado por Winkler. Esto funciona casi tan bien como el esquema Monge-Elkan, pero es un orden de magnitud más rápido. Una forma sencilla de combinar el método TFIDF y Jaro-Winkler es reemplazar las coincidencias de token exactas utilizadas en TFIDF con coincidencias de token aproximadas basadas en el esquema Jaro-Winkler. Esta combinación tiene un rendimiento ligeramente mejor que Jaro-Winkler o TFIDF en promedio y, en ocasiones, funciona mucho mejor. También se acerca en rendimiento a una combinación aprendida de varias de las mejores métricas consideradas en este documento.
krole
no se vuelve a escribirFinal Fantasy V: Krile
, aunque me gustaría. Requiere que todos los caracteres de la consulta estén presentes en el mismo orden en el resultado, lo cual es bastante miope. Parece que la única forma de tener una buena búsqueda difusa es tener una base de datos de errores tipográficos comunes.Respuestas:
¡Buena pregunta! Pero mi pensamiento es que, en lugar de intentar modificar Levenshtein-Demerau, sería mejor probar un algoritmo diferente o combinar / ponderar los resultados de dos algoritmos.
Me parece que las coincidencias exactas o cercanas al "prefijo inicial" son algo a lo que Levenshtein-Demerau no le da un peso particular, pero sus expectativas aparentes de usuario sí lo harían.
Busqué "mejor que Levenshtein" y, entre otras cosas, encontré esto:
http://www.joyofdata.de/blog/comparison-of-string-distance-algorithms/
Esto menciona una serie de medidas de "distancia de la cuerda". Tres que parecían particularmente relevantes para su requerimiento serían:
Distancia de subcadena común más larga: número mínimo de símbolos que deben eliminarse en ambas cadenas hasta que las subcadenas resultantes sean idénticas.
Distancia de q-gramo: Suma de las diferencias absolutas entre los vectores de N-gramo de ambas cadenas.
Distancia de Jaccard: 1 minuto es el cociente de N-gramos compartidos y todos los N-gramos observados.
Tal vez podría usar una combinación ponderada (o un mínimo) de estas métricas, con Levenshtein: la subcadena común, el N-gram común o Jaccard preferirán encarecidamente similares cadenas , o tal vez intente usar simplemente Jaccard.
Dependiendo del tamaño de su lista / base de datos, estos algoritmos pueden ser moderadamente costosos. Para una búsqueda difusa que implementé, utilicé un número configurable de N-gramos como "claves de recuperación" de la base de datos y luego ejecuté la costosa medida de distancia entre cadenas para clasificarlos en orden de preferencia.
Escribí algunas notas sobre la búsqueda de cadenas difusas en SQL. Ver:
fuente
Intenté usar bibliotecas difusas existentes como fuse.js y también las encontré terribles, así que escribí una que se comporta básicamente como una búsqueda sublime. https://github.com/farzher/fuzzysort
El único error tipográfico que permite es una transposición. Es bastante sólido (1k estrellas, 0 números) , muy rápido y maneja su caso fácilmente:
fuente
Esta es una técnica que he usado varias veces ... Da muy buenos resultados. Sin embargo, no hace todo lo que pidió. Además, esto puede resultar caro si la lista es enorme.
Pasar dos cadenas a las
string_similarity
que devolverán un número entre0
y1.0
dependiendo de qué tan similares sean. Este ejemplo usa Lo-DashEjemplo de uso ...
Además ... ten un violín
Asegúrese de que su consola esté abierta o no verá nada :)
fuente
esta es mi función corta y compacta para la coincidencia difusa:
fuente
fuzzyMatch('c a', 'a b c')
debería regresartrue
puede echar un vistazo a https://github.com/atom/fuzzaldrin/ lib de Atom .
está disponible en npm, tiene una API simple y funcionó bien para mí.
fuente
Actualización de noviembre de 2019. Encontré que Fuse tiene algunas actualizaciones bastante decentes. Sin embargo, no pude hacer que usara los operadores bool (es decir, OR, AND, etc.) ni pude usar la interfaz de búsqueda API para filtrar los resultados.
Descubrí
nextapps-de/flexsearch
: https://github.com/nextapps-de/flexsearch y creo que supera con creces muchas de las otras bibliotecas de búsqueda de javascript que he probado, y tiene soportebool
, filtrado de búsquedas y paginación.Puede ingresar una lista de objetos javascript para sus datos de búsqueda (es decir, almacenamiento), y la API está bastante bien documentada: https://github.com/nextapps-de/flexsearch#api-overview
Hasta ahora he indexado cerca de 10,000 registros y mis búsquedas son casi inmediatas; es decir, una cantidad de tiempo imperceptible para cada búsqueda.
fuente
> 100kb
) y tiene una gran cantidad de problemas y relaciones públicas no atendidos. No lo usaría por esas dos razones.aquí está la solución proporcionada por @InternalFX, pero en JS (la usé para compartir):
fuente
Arreglé los problemas con la solución de bigram CoffeeScript de InternalFx y la convertí en una solución genérica de n-gramos (puede personalizar el tamaño de los gramos).
Esto es TypeScript, pero puede eliminar las anotaciones de tipo y también funciona como vainilla JavaScript.
Ejemplos:
Pruébelo en TypeScript Playground
fuente
jsfiddle http://jsfiddle.net/guest271314/QP7z5/
fuente
Consulte mi complemento de Google Sheets llamado Flookup y use esta función:
Los detalles de los parámetros son:
lookupValue
: el valor que estás buscandotableArray
: la tabla que desea buscarlookupCol
: la columna que desea buscarindexNum
: la columna de la que desea que se devuelvan los datosthreshold
: el porcentaje de similitud por debajo del cual no se deben devolver los datosrank
: la enésima mejor coincidencia (es decir, si la primera coincidencia no es de su agrado)Esto debería satisfacer sus requisitos ... aunque no estoy seguro del punto número 2.
Obtenga más información en el sitio web oficial .
fuente