sql >> Base de Datos >  >> RDS >> PostgreSQL

Postgres:índice de similitud de coseno de matrices flotantes para búsqueda de uno a muchos

Deduzco que ninguna extensión hace esto, así que encontré una solución limitada:

Si tanto A como B están normalizados (longitud 1), cos(A, B) = 1 - 0.5 * ||A - B||^2 . ||A - B|| es la distancia euclidiana, y cos(A, B) es la semejanza del coseno. Entonces, mayor distancia euclidiana <=> menor similitud de coseno (tiene sentido intuitivamente si imaginas un círculo unitario), y si tienes vectores no normales, cambiar sus magnitudes sin cambiar sus direcciones no afecta sus similitudes de coseno. Genial, puedo normalizar mis vectores y comparar sus distancias euclidianas...

Hay una buena respuesta aquí sobre Cubo , que admite puntos n-dimensionales e índices GiST en Euclidiano distancia, pero solo admite 100 o menos dimensiones (se puede piratear más alto, pero tuve problemas alrededor de 135 y más, así que ahora tengo miedo). También requiere Postgres 9.6 o posterior.

Entonces:

  1. Asegúrese de que no me importe tener como máximo 100 dimensiones. Actualice a Postgres 9.6 o posterior.
  2. Llenar mi tabla con arreglos para representar vectores.
  3. Normalice los vectores para crear una columna extra de cube puntos. Cree un índice GiST en esta columna.
  4. Ordenar por distancia euclidiana ascendente para obtener similitud de coseno descendente:EXPLAIN SELECT * FROM mytable ORDER BY normalized <-> cube(array[1,2,3,4,5,6,7,8,9,0]) LIMIT 10;

Si necesito más de 100 dimensiones, podría lograrlo usando varias columnas indexadas. Actualizaré la respuesta en ese caso.

Actualización: Estoy bastante seguro de que no hay nada que pueda hacer al dividir el vector de> 100 dimensiones en varias columnas. Termino teniendo que escanear toda la tabla.