Ho capito che nessuna estensione lo fa, quindi ho trovato una soluzione alternativa limitata:
Se A e B sono entrambi normalizzati (lunghezza 1), cos(A, B) = 1 - 0.5 * ||A - B||^2
. ||A - B||
è la distanza euclidea e cos(A, B)
è la somiglianza del coseno. Quindi maggiore distanza euclidea <=> minore somiglianza del coseno (ha senso intuitivamente se immagini un cerchio unitario) e se hai vettori non normali, cambiare le loro grandezze senza cambiare le loro direzioni non influisce sulle loro somiglianze del coseno. Ottimo, così posso normalizzare i miei vettori e confrontare le loro distanze euclidee...
C'è una bella risposta qui su Cubo , che supporta punti n-dimensionali e indici GiST su Euclideo distanza, ma supporta solo 100 o meno dimensioni (può essere violato più in alto, ma ho avuto problemi intorno a 135 e oltre, quindi ora temo). Richiede anche Postgres 9.6 o successivo.
Quindi:
- Assicurati che non mi interessi avere al massimo 100 dimensioni. Esegui l'upgrade a Postgres 9.6 o successivo.
- Riempi la mia tabella con gli array per rappresentare i vettori.
- Normalizza i vettori per creare una colonna extra di
cube
punti. Crea un indice GiST su questa colonna. - Ordina per distanza euclidea crescente per ottenere la somiglianza del coseno decrescente:
EXPLAIN SELECT * FROM mytable ORDER BY normalized <-> cube(array[1,2,3,4,5,6,7,8,9,0]) LIMIT 10;
Se ho bisogno di più di 100 dimensioni, potrei essere in grado di ottenere questo risultato utilizzando più colonne indicizzate. Aggiornerò la risposta in tal caso.
Aggiornamento: Abbastanza sicuro che non posso fare nulla con la divisione del vettore a 100 dimensioni in più colonne. Finisco per dover scansionare l'intera tabella.