Разбирам, че няма разширение, което да прави това, така че намерих ограничено решение:
Ако A и B са нормализирани (дължина 1), cos(A, B) = 1 - 0.5 * ||A - B||^2
. ||A - B||
е евклидовото разстояние и cos(A, B)
е косинусното подобие. Така че по-голямо евклидово разстояние <=> по-малко косинусово подобие (има смисъл интуитивно, ако си представите единична окръжност) и ако имате ненормални вектори, промяната на техните величини без промяна на посоките им не влияе на техните косинусови подобия. Страхотно, така че мога да нормализирам моите вектори и да сравня техните евклидови разстояния...
Има хубав отговор тук относно Cube , който поддържа n-измерни точки и GiST индекси на Евклидов разстояние, но поддържа само 100 или по-малко измерения (може да бъде хакнат по-високо, но имах проблеми около 135 и по-високи, така че сега се страхувам). Също така изисква Postgres 9.6 или по-нова версия.
И така:
- Уверете се, че не ми пука да имам най-много 100 измерения. Надстройте до Postgres 9.6 или по-нова версия.
- Попълнете моята таблица с масиви за представяне на вектори.
- Нормализирайте векторите, за да създадете допълнителна колона от
cube
точки. Създайте GiST индекс в тази колона. - Подреждане по евклидово разстояние във възходящ ред, за да получите косинусово сходство в низходящ ред:
EXPLAIN SELECT * FROM mytable ORDER BY normalized <-> cube(array[1,2,3,4,5,6,7,8,9,0]) LIMIT 10;
Ако имам нужда от повече от 100 измерения, може да успея да постигна това с помощта на множество индексирани колони. В този случай ще актуализира отговора.
Актуализация: Сигурен съм, че не мога да направя нищо с разделянето на>100-измерния вектор на множество колони. В крайна сметка трябва да сканирам цялата таблица.