Un enfoque común (al menos común para mí) es dividir su cadena de bits en varios fragmentos y consultar estos fragmentos para obtener una coincidencia exacta como paso previo al filtro. Si trabaja con archivos, cree tantos archivos como fragmentos tenga (por ejemplo, 4 aquí) con cada fragmento permutado al frente y luego clasifique los archivos. Puede usar una búsqueda binaria e incluso puede expandir su búsqueda por encima y por debajo de una parte correspondiente para obtener una bonificación.
Luego, puede realizar un cálculo de la distancia de Hamming bit a bit en los resultados devueltos, que deberían ser solo un subconjunto más pequeño de su conjunto de datos general. Esto se puede hacer usando archivos de datos o tablas SQL.
Entonces, para recapitular: digamos que tiene un montón de cadenas de 32 bits en una base de datos o archivos y que desea encontrar cada hash que se encuentre dentro de una distancia de Hamming de 3 bits o menos de su cadena de bits de "consulta":
cree una tabla con cuatro columnas: cada una contendrá una porción de 8 bits (como una cadena o int) de los hashes de 32 bits, islice 1 a 4. O si usa archivos, cree cuatro archivos, cada uno siendo una permutación de las rebanadas que tienen un "islice" al frente de cada "fila"
corte su cadena de bits de consulta de la misma manera en qslice 1 a 4.
consultar esta tabla de modo que cualquiera de qslice1=islice1 or qslice2=islice2 or qslice3=islice3 or qslice4=islice4
. Esto le proporciona todas las cadenas que están dentro de los 7 bits ( 8 - 1
) de la cadena de consulta. Si usa un archivo, haga una búsqueda binaria en cada uno de los cuatro archivos permutados para obtener los mismos resultados.
para cada cadena de bits devuelta, calcule la distancia de hamming exacta por pares con su cadena de bits de consulta (reconstruyendo las cadenas de bits del lado del índice a partir de las cuatro secciones, ya sea desde la base de datos o desde un archivo permutado)
El número de operaciones en el paso 4 debería ser mucho menor que un cálculo hamming completo por pares de toda la tabla y es muy eficiente en la práctica. Además, es fácil fragmentar los archivos en archivos más pequeños si se necesita más velocidad mediante el paralelismo.
Ahora, por supuesto, en su caso, está buscando un tipo de autounión, es decir, todos los valores que están a cierta distancia entre sí. El mismo enfoque todavía funciona en mi humilde opinión, aunque tendrá que expandir hacia arriba y hacia abajo desde un punto de partida para las permutaciones (usando archivos o listas) que comparten el fragmento inicial y calcular la distancia de hamming para el grupo resultante.
Si se ejecuta en memoria en lugar de archivos, su conjunto de datos de cadenas de 32 bits de 100M estaría en el rango de 4 GB. Por lo tanto, las cuatro listas permutadas pueden necesitar alrededor de 16 GB + de RAM. Aunque obtengo excelentes resultados con archivos mapeados en memoria y debo menos RAM para conjuntos de datos de tamaño similar.
Hay implementaciones de código abierto disponibles. Lo mejor en el espacio es en mi humilde opinión el hecho para Simhash por Moz , C ++ pero diseñado para cadenas de 64 bits y no de 32 bits.
Este enfoque distancia happing acotada fue descrita por primera AFAIK por Moses Charikar en su "simhash" seminal papel y la correspondiente Google patente :
- BÚSQUEDA APROXIMADA DE VECINOS MÁS CERCANOS EN EL ESPACIO DE HAMMING
[...]
Dados los vectores de bits que constan de d bits cada uno, elegimos N = O (n 1 / (1+)) permutaciones aleatorias de los bits. Para cada permutación aleatoria σ, mantenemos un orden ordenado O σ de los vectores de bits, en orden lexicográfico de los bits permutados por σ. Dado un vector de bits de consulta q, encontramos el vecino más cercano aproximado haciendo lo siguiente:
Para cada permutación σ, realizamos una búsqueda binaria en O σ para localizar los dos vectores de bits más cercanos a q (en el orden lexicográfico obtenido por bits permutados por σ). Ahora buscamos en cada uno de los órdenes ordenados O σ examinando los elementos arriba y abajo de la posición devuelta por la búsqueda binaria en orden de la longitud del prefijo más largo que coincide con q.
Monika Henziger amplió esto en su artículo "Encontrar páginas web casi duplicadas: una evaluación a gran escala de algoritmos" :
3.3 Los resultados del algoritmo C
Dividimos la cadena de bits de cada página en 12 piezas de 4 bytes no superpuestas, creando 20B piezas y calculamos la similitud C de todas las páginas que tenían al menos una pieza en común. Se garantiza que este enfoque encontrará todos los pares de páginas con una diferencia de hasta 11, es decir, C-similitud 373, pero podría perder algunas para diferencias más grandes.
Esto también se explica en el documento Detección de casi duplicados para rastreo web de Gurmeet Singh Manku, Arvind Jain y Anish Das Sarma:
- EL PROBLEMA DE LA DISTANCIA DEL MARTILLO
Definición: Dada una colección de huellas dactilares de f -bit y una huella dactilar de consulta F, identifique si una huella dactilar existente difiere de F en como máximo k bits. (En la versión en modo por lotes del problema anterior, tenemos un conjunto de huellas digitales de consulta en lugar de una sola huella digital de consulta)
[...]
Intuición: considere una tabla ordenada de huellas dactilares verdaderamente aleatorias de 2 df-bit. Concéntrese solo en los bits d más significativos de la tabla. Una lista de estos números de d-bit equivale a “casi un contador” en el sentido de que (a) existen bastantes combinaciones de 2 d bits, y (b) muy pocas combinaciones de d bits están duplicadas. Por otro lado, los bits f - d menos significativos son "casi aleatorios".
Ahora elija d tal que | d - d | es un pequeño entero. Dado que la tabla está ordenada, una sola sonda es suficiente para identificar todas las huellas dactilares que coinciden con F en las posiciones de bit más significativas. Dado que | d - d | es pequeño, también se espera que el número de estos partidos sea pequeño. Para cada huella dactilar coincidente, podemos averiguar fácilmente si difiere de F en la mayoría de las k posiciones de bits o no (estas diferencias, naturalmente, se limitarían a las f - d posiciones de bits menos significativas).
El procedimiento descrito anteriormente nos ayuda a ubicar una huella digital existente que difiere de F en k posiciones de bits, todas las cuales están restringidas a estar entre los bits f - d menos significativos de F. Esto se ocupa de un buen número de casos. Para cubrir todos los casos, basta con construir una pequeña cantidad de tablas adicionales ordenadas, como se describe formalmente en la siguiente sección.
Nota: publiqué una respuesta similar a una pregunta relacionada solo con base de datos