Pesquisa rápida por vizinhos mais próximos no espaço 150-dimensional

13

Quero criar um banco de dados usando qualquer um dos RDBMS possíveis. Terá uma tabela com aproximadamente 150 colunas. O objetivo é realizar a pesquisa de vizinhos mais próximos de alguns outros objetos. Portanto, é um NNS no espaço 150-dimensional.

Eu já tentei usar alguns métodos óbvios, como distâncias L1 ou L2, mas é claro que leva muito tempo para tabelas com muitas linhas. Também tentei olhar para a árvore KD (note que não a testei) e PG-Strom, mas elas não são uma boa solução para dados com muitas dimensões.

Posso, de alguma forma, melhorar a velocidade da pesquisa descrita usando métodos matemáticos (como KD-tree) ou métodos técnicos (como PG-Strom)?

Vou tentar usar qualquer RDBMS que permita melhorar a velocidade do NNS. Mas MySQL e PostgreSQL são os DBMS mais apropriados para mim.

don-prog
fonte
1
Esses são outros problemas. Basta fazer outra pergunta @ don-prog
Evan Carroll

Respostas:

17

PostgreSQL 9.6 usando cube

Primeiro instale a extensão do cubo

CREATE EXTENSION cube;

Agora vamos criar um espaço n-dimensional com 100.000 pontos em 50 dimensões. Além disso, adicionaremos um índice 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;

Agora, geraremos um único ponto e usaremos o <->operador para encontrar o ponto mais próximo usando a distância euclediana.

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;

O PostgreSQL 9.6+ suporta outros operadores à distância cube. Tudo isso pode usar o índice GIST que criamos. Nomeadamente,

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.

Dito isto, há uma ressalva,

Para tornar mais difícil as pessoas quebrarem coisas, há um limite de 100 no número de dimensões de cubos. Isso é definido em cubedata.h se você precisar de algo maior.

Você pede 150 dimensões. Isso pode apresentar uma pequena complicação.

Evan Carroll
fonte
1
A edição de cubedata.hnão funciona além das 130 dimensões na minha experiência. Talvez você também possa alterar todos os doubles float8na extensão para float4, uma vez que o Postgres tem um limite no tamanho do índice por linha do qual você pode ficar afastado pela metade de quantos bytes você usa em cada número. Fiz alguns testes e obtive mais dimensões dessa maneira, e o IIRC superei os 150, mas não tenho muita certeza.
Sudo #
Eu tive o mesmo problema com o limite de dimensões e criei a imagem do docker com o limite de 2048: hub.docker.com/r/expert/postgresql-large-cube
expert
2

Considere executar a redução de dimensão primeiro (por exemplo, Análise de componentes principais).

Então você está executando o NN em um pequeno número de dimensões com maior desempenho.

Você pode usar o Pl / R para executar o PCA dentro do postgres, se necessário.

Robin Chauhan
fonte
0

Dê uma olhada em https://github.com/a-mma/AquilaDB , é um banco de dados vetorial para armazenar vetores de recursos junto com metadados JSON. Mantenha-o junto com seu RDBMS e use metadados para manter a referência cruzada entre dados.

a_ മ്മ
fonte