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:
- Asegúrese de que no me importe tener como máximo 100 dimensiones. Actualice a Postgres 9.6 o posterior.
- Llenar mi tabla con arreglos para representar vectores.
- Normalice los vectores para crear una columna extra de
cube
puntos. Cree un índice GiST en esta columna. - 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.