Tengo una gran base de datos (16 millones de filas) que contiene hashes perceptuales de imágenes.
Me gustaría poder buscar filas por distancia de distancia en un plazo razonable.
Actualmente, hasta donde entiendo correctamente el problema, creo que la mejor opción aquí sería una implementación personalizada de SP-GiST que implemente un BK-Tree , pero eso parece mucho trabajo, y todavía estoy confuso en la práctica detalles de la implementación adecuada de un índice personalizado. El cálculo de la distancia de Hamming es lo suficientemente manejable, y hacer saber C, sin embargo.
Básicamente, ¿cuál es el enfoque apropiado aquí? Necesito poder buscar coincidencias dentro de una cierta distancia de edición de un hash. Según tengo entendido, la distancia de Levenshtein con cadenas de igual longitud es funcionalmente la distancia de Hamming, por lo que hay al menos algún soporte existente para lo que quiero, aunque no hay una forma clara de crear un índice a partir de él (recuerde, el valor que estoy buscando cambios. No puedo calcular previamente la distancia desde un valor fijo, ya que eso solo sería útil para ese valor).
Los hashes se almacenan actualmente como una cadena de 64 caracteres que contiene la codificación binaria ASCII del hash (por ejemplo, "10010101 ..."), pero puedo convertirlos a int64 con bastante facilidad. El verdadero problema es que necesito poder consultar relativamente rápido.
Parece que podría ser posible lograr algo similar a lo que quiero con el pg_trgm
, pero no tengo claro cómo funciona el mecanismo de coincidencia de trigrama (en particular, ¿qué representa realmente la métrica de similitud que devuelve ? Parece algo así como editar-distancia).
El rendimiento de la inserción no es crítico (es muy costoso desde el punto de vista computacional calcular los hashes para cada fila), por lo que principalmente me preocupa la búsqueda.
fuente
Respuestas:
Bueno, pasé un tiempo mirando escribir una extensión C personalizada de postgres, y terminé simplemente escribiendo un contenedor de base de datos Cython que mantiene una estructura de árbol BK en la memoria.
Básicamente, mantiene una copia en memoria de los valores phash de la base de datos, y todas las actualizaciones de la base de datos se reproducen en el árbol BK.
Todo está en Github aquí . También tiene MUCHAS pruebas unitarias.
La consulta a través de un conjunto de datos de 10 millones de valores hash para elementos con una distancia de 4 resulta en tocar ~ 0.25% -0.5% de los valores en el árbol, y toma ~ 100 ms.
fuente
¡RESPUESTAS DE MOAR!
Ok, finalmente me he tomado el tiempo para escribir una extensión de indexación PostgreSQL personalizada. He utilizado la interfaz de SP-GiST .
Esto fue bastante desafiante, principalmente porque Posgres es grande .
De todos modos, como de costumbre, está en github aquí .
En cuanto al rendimiento, actualmente es ~ 2-3 veces más lento que la implementación de memoria pura en mi otra respuesta a esta pregunta, pero es mucho más conveniente de usar. Me encantaría comer ese golpe de rendimiento (en realidad, es ~ 50 ms / query - 150 ms / query, que todavía es bastante pequeño).
fuente