sql >> Databasteknik >  >> RDS >> PostgreSQL

Postgres:index på cosinuslikhet för float-arrayer för en-till-många-sökning

Jag har förstått att det inte finns något tillägg som gör detta, så jag har hittat en begränsad lösning:

Om A och B båda är normaliserade (längd 1), cos(A, B) = 1 - 0.5 * ||A - B||^2 . ||A - B|| är det euklidiska avståndet och cos(A, B) är cosinuslikheten. Så större euklidiskt avstånd <=> mindre cosinuslikhet (gör intuitivt vettigt om du föreställer dig en enhetscirkel), och om du har icke-normala vektorer, påverkar inte deras cosinuslikheter att ändra deras magnituder utan att ändra deras riktningar. Bra, så jag kan normalisera mina vektorer och jämföra deras euklidiska avstånd...

Det finns ett bra svar här om kub , som stöder n-dimensionella punkter och GiST-index på Euklidiska avstånd, men det stöder bara 100 eller färre dimensioner (kan hackas högre, men jag hade problem runt 135 och högre, så nu är jag rädd). Kräver även Postgres 9.6 eller senare.

Så:

  1. Se till att jag inte bryr mig om att ha högst 100 dimensioner. Uppgradera till Postgres 9.6 eller senare.
  2. Fyll min tabell med arrayer för att representera vektorer.
  3. Normalisera vektorerna för att skapa en extra kolumn med cube poäng. Skapa ett GiST-index på den här kolumnen.
  4. Ordna efter euklidiskt avstånd stigande för att få cosinuslikhet fallande:EXPLAIN SELECT * FROM mytable ORDER BY normalized <-> cube(array[1,2,3,4,5,6,7,8,9,0]) LIMIT 10;

Om jag behöver mer än 100 dimensioner kanske jag kan uppnå detta med flera indexerade kolumner. Kommer att uppdatera svaret i så fall.

Uppdatering: Ganska säker på att det inte finns något jag kan göra med att dela upp vektorn>100 dimensioner i flera kolumner. Det slutar med att jag måste skanna hela tabellen.



  1. Kan inte ansluta till två postgres-databaser i rails 3.2.

  2. Rails 3 med mysql-problem

  3. C# MySqlParameter problem

  4. mysql hur man hittar om minst en rad från korsreferenstabellen är null eller kriterier