sql >> Database teknologi >  >> RDS >> PostgreSQL

Postgresql k-nærmeste nabo (KNN) på flerdimensionel terning

PostgreSQL understøtter afstandsoperatør <-> og som jeg forstår det, kan dette bruges til at analysere tekst (med pg_trgrm-modul) og geometri datatype.

Jeg ved ikke, hvordan du kan bruge det med mere end 1 dimension. Måske bliver du nødt til at definere din egen afstandsfunktion eller på en eller anden måde konvertere dine data til én kolonne med tekst eller geometritype. For eksempel hvis du har en tabel med 8 kolonner (8-dimensionel terning):

c1 c2 c3 c4 c5 c6 c7 c8
 1  0  1  0  1  0  1  2

Du kan konvertere det til:

c1 c2 c3 c4 c5 c6 c7 c8
 a  b  a  b  a  b  a  c

Og så til tabel med én kolonne:

c1
abababac

Så kan du bruge (efter at have oprettet gist indeks ):

SELECT c1, c1 <-> 'ababab'
 FROM test_trgm 
 ORDER BY c1 <-> 'ababab';

Eksempel

Opret eksempeldata

-- Create some temporary data
-- ! Note that table are created in tmp schema (change sql to your scheme) and deleted if exists !
drop table if exists tmp.test_data;

-- Random integer matrix 100*8 
create table tmp.test_data as (
   select 
      trunc(random()*100)::int as input_variable_1,
      trunc(random()*100)::int as input_variable_2, 
      trunc(random()*100)::int as input_variable_3,
      trunc(random()*100)::int as input_variable_4, 
      trunc(random()*100)::int as input_variable_5, 
      trunc(random()*100)::int as input_variable_6, 
      trunc(random()*100)::int as input_variable_7, 
      trunc(random()*100)::int as input_variable_8
   from 
      generate_series(1,100,1)
);

Transform inputdata til tekst

drop table if exists tmp.test_data_trans;

create table tmp.test_data_trans as (
select 
   input_variable_1 || ';' ||
   input_variable_2 || ';' ||
   input_variable_3 || ';' ||
   input_variable_4 || ';' ||
   input_variable_5 || ';' ||
   input_variable_6 || ';' ||
   input_variable_7 || ';' ||
   input_variable_8 as trans_variable
from 
   tmp.test_data
);

Dette vil give dig en variabel trans_variable hvor alle de 8 dimensioner er gemt:

trans_variable
40;88;68;29;19;54;40;90
80;49;56;57;42;36;50;68
29;13;63;33;0;18;52;77
44;68;18;81;28;24;20;89
80;62;20;49;4;87;54;18
35;37;32;25;8;13;42;54
8;58;3;42;37;1;41;49
70;1;28;18;47;78;8;17

I stedet for || operatør kan du også bruge følgende syntaks (kortere, men mere kryptisk):

select 
   array_to_string(string_to_array(t.*::text,''),'') as trans_variable
from 
   tmp.test_data t

Tilføj indeks

create index test_data_gist_index on tmp.test_data_trans using gist(trans_variable);

Testafstand Bemærk:Jeg har valgt en række fra tabel - 52;42;18;50;68;29;8;55 - og brugt lidt ændret værdi (42;42;18;52;98;29;8;55 ) for at teste afstanden. Selvfølgelig vil du have helt andre værdier i dine testdata, fordi det er RANDOM matrix.

select 
   *, 
   trans_variable <->  '42;42;18;52;98;29;8;55' as distance,
   similarity(trans_variable, '42;42;18;52;98;29;8;55') as similarity,
from 
   tmp.test_data_trans 
order by
   trans_variable <-> '52;42;18;50;68;29;8;55';

Du kan bruge afstandsoperatør <-> eller lighedsfunktion. Afstand =1 - lighed



  1. Sådan defineres en auto-inkrement primær nøgle i Oracle

  2. Udvikl React m/ full-stack (WAMP) lokalt

  3. Hvad er den bedste tilgang til at finde alle adresser, der er i en bestemt afstand til det valgte punkt

  4. Hvordan gemmer man automatisk valg i ComboBox i MYSQL i PHP uden indsend-knap?