Eu entendo que nenhuma extensão que faça isso, então encontrei uma solução limitada:
Se A e B forem ambos normalizados (comprimento 1),
cos(A, B) = 1 - 0.5 * ||A - B||^2
. ||A - B||
é a distância euclidiana, e cos(A, B)
é a similaridade do cosseno. Portanto, maior distância euclidiana <=> menor semelhança de cosseno (faz sentido intuitivamente se você imaginar um círculo unitário), e se você tiver vetores não normais, alterar suas magnitudes sem alterar suas direções não afeta suas semelhanças de cosseno. Ótimo, então posso normalizar meus vetores e comparar suas distâncias euclidianas... Há uma boa resposta aqui sobre o Cube , que suporta pontos n-dimensionais e índices GiST em Euclidiano distância, mas suporta apenas 100 ou menos dimensões (pode ser hackeado mais alto, mas tive problemas em torno de 135 ou mais, então agora estou com medo). Também requer Postgres 9.6 ou posterior.
Então:
- Certifique-se de que não me importo em ter no máximo 100 dimensões. Atualize para o Postgres 9.6 ou posterior.
- Preencha minha tabela com arrays para representar vetores.
- Normalize os vetores para criar uma coluna extra de
cube
pontos. Crie um índice GiST nesta coluna. - Ordenar por distância euclidiana crescente para obter similaridade de cosseno decrescente:
EXPLAIN SELECT * FROM mytable ORDER BY normalized <-> cube(array[1,2,3,4,5,6,7,8,9,0]) LIMIT 10;
Se eu precisar de mais de 100 dimensões, talvez consiga isso usando várias colunas indexadas. Irá atualizar a resposta nesse caso.
Atualização: Tenho certeza de que não há nada que eu possa fazer com a divisão do vetor> 100 dimensões em várias colunas. Eu acabo tendo que escanear a mesa inteira.