Ricerca rapida del vicino più vicino nello spazio di 150 dimensioni


13

Voglio creare un database usando uno dei possibili RDBMS. Avrà una tabella con circa 150 colonne. L'obiettivo è eseguire la ricerca del vicino più vicino di alcuni altri oggetti. Quindi è un NNS nello spazio di 150 dimensioni.

Ho già provato a utilizzare alcuni metodi ovvi come le distanze L1 o L2, ma ovviamente ci vuole molto tempo per le tabelle con molte righe. Inoltre ho provato a guardare l'albero KD (nota che non l'ho testato) e PG-Strom ma non sono una buona soluzione per dati con molte dimensioni.

Posso in qualche modo migliorare la velocità della ricerca descritta usando metodi matematici (come KD-tree) o metodi tecnologici (come PG-Strom)?

Proverò a utilizzare qualsiasi RDBMS che consenta di migliorare la velocità dell'NNS. Ma MySQL e PostgreSQL sono il DBMS più appropriato per me.


1
Questi sono altri problemi. Basta fare un'altra domanda @ don-prog
Evan Carroll il

Risposte:


17

PostgreSQL 9.6 usando cube

Innanzitutto installa l' estensione del cubo

CREATE EXTENSION cube;

Ora creeremo uno spazio n-dimensionale con 100.000 punti in 50 dimensioni. Inoltre aggiungeremo un indice GIST.

CREATE TEMP TABLE space_nd
AS
  SELECT i, cube(array_agg(random()::float)) AS c
  FROM generate_series(1,1e5) AS i
  CROSS JOIN LATERAL generate_series(1,50)
    AS x
  GROUP BY i;

CREATE INDEX ON space_nd USING gist ( c );
ANALYZE space_nd;

Ora genereremo un singolo punto e useremo l' <->operatore per trovare il punto più vicino usando la distanza euclinese.

WITH points AS (
  SELECT cube(array_agg(random()::float)) AS c
  FROM generate_series(1,50)
    AS x
)
SELECT i,
  pg_typeof(space_nd.c),
  pg_typeof(points.c),
  cube_distance(space_nd.c, points.c)
FROM space_nd
CROSS JOIN points
ORDER BY space_nd.c <-> points.c
LIMIT 5;

PostgreSQL 9.6+ supporta altri operatori di distanza cube. Tutto ciò può utilizzare l'indice GIST che abbiamo creato. Vale a dire,

a <-> b float8  Euclidean distance between a and b.
a <#> b float8  Taxicab (L-1 metric) distance between a and b.
a <=> b float8  Chebyshev (L-inf metric) distance between a and b.

Detto questo c'è un avvertimento,

Per rendere più difficile per le persone rompere le cose, esiste un limite di 100 al numero di dimensioni dei cubi. Questo è impostato in cubedata.h se hai bisogno di qualcosa di più grande.

Richiedi 150 dimensioni. Ciò può presentare una piccola complicazione.


1
La modifica a cubedata.hnon funziona oltre 130 dimensioni nella mia esperienza. Forse puoi anche cambiare tutte le doubles float8nell'estensione float4, poiché Postgres ha un limite sulla dimensione dell'indice per riga da cui puoi stare alla larga dimezzando il numero di byte che usi su ciascun numero. Ho fatto alcuni test e ho ottenuto più dimensioni in quel modo, e IIRC ne ho superate 150, ma non ne sono del tutto sicuro.
sudo,

Ho avuto lo stesso problema con il limite delle dimensioni e ho creato l'immagine della finestra mobile con il limite del 2048: hub.docker.com/r/expert/postgresql-large-cube
expert

2

Considerare innanzitutto di eseguire la riduzione dimensionale (ad es. Analisi dei componenti di principio).

Quindi stai facendo NN in un piccolo numero di dimensioni con prestazioni più elevate.

È possibile utilizzare Pl / R per eseguire PCA all'interno di Postgres, se necessario.



0

Dai un'occhiata a https://github.com/a-mma/AquilaDB che è un database di vettori per l'archiviazione di vettori di funzioni insieme a metadati JSON. Conservalo insieme al tuo RDBMS e usa i metadati per mantenere il riferimento incrociato tra i dati.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.