Consultas rápidas sobre distâncias hamming no postgres

15

Eu tenho um banco de dados grande (16 milhões de linhas) contendo hashes perceptivos de imagens.

Gostaria de poder pesquisar linhas impedindo a distância em um prazo razoável.

Atualmente, até onde eu entendi direito o problema, acho que a melhor opção aqui seria uma implementação personalizada do SP-GiST que implemente uma BK-Tree , mas isso parece muito trabalhoso e ainda estou confuso quanto à prática detalhes da implementação adequada de um índice personalizado. Calcular a distância de Hamming é suficiente tratável, e eu fazer sabe C, no entanto.

Basicamente, qual é a abordagem apropriada aqui? Eu preciso ser capaz de consultar correspondências dentro de uma certa distância de edição de um hash. Pelo que entendi, a distância de Levenshtein com cadeias de comprimento igual está prejudicando funcionalmente a distância, portanto há pelo menos algum suporte existente para o que eu quero, embora não haja uma maneira clara de criar um índice a partir dele (lembre-se, o valor que estou consultando Não consigo pré-calcular a distância de um valor fixo, pois isso seria útil apenas para esse valor).

Atualmente, os hashes são armazenados como uma cadeia de 64 caracteres contendo a codificação ASCII binária do hash (por exemplo, "10010101 ..."), mas posso convertê-los em int64 com bastante facilidade. O problema real é que preciso ser capaz de consultar relativamente rápido.

Parece que pode ser possível obter algo na linha do que eu quero com o pg_trgm, mas não sei como funciona o mecanismo do trigrama correspondente (em particular, o que a métrica de similaridade que ele retorna realmente representa? tipo como editar distância).

O desempenho da pastilha não é crítico (é muito computacionalmente caro calcular os hashes para cada linha), então eu me preocupo principalmente com a pesquisa.

Nome falso
fonte
A extensão smlar pode ter o que você precisa: pgcon.org/2012/schedule/attachments/252_smlar-2012.pdf ou pg_similarity: pgcon.org/2009/schedule/attachments/108_pg_similarity.pdf
Neil McGuigan
@NeilMcGuigan - Interesting! A primeira apresentação é realmente das pessoas que mantêm os sistemas SP-GiST e GIST no postgres.
Fake Name
O primeiro link é para algo fundamentalmente diferente. eles estão procurando interseções definidas, enquanto eu estou procurando distâncias dificultadoras. Eu poderia embaralhar as fases em um conjunto, mas seria extremamente confuso e exigiria muito código de suporte em qualquer outro lugar.
Nome falso
FWIW, Neste ponto, concluí mais ou menos que preciso implementar meu próprio sistema de indexação. Estou analisando índices personalizados do SP-GiST no momento, mas não tenho ideia do que estou fazendo.
Fake Name
1
@FakeName: Quando você diz a distância de hamming, suponho que você queira dizer a distância de hamming das seqüências de valores hash, não as imagens? Em outras palavras, você deve perguntar: Encontre todos os valores de hash que são substituições de bits X longe do parâmetro de entrada
Thomas Kejser 27/10/14

Respostas:

11

Bem, passei um tempo olhando para escrever uma extensão C personalizada do postgres e acabei escrevendo um wrapper de banco de dados Cython que mantém uma estrutura de árvore BK na memória.

Basicamente, ele mantém uma cópia na memória dos valores de phash do banco de dados, e todas as atualizações no banco de dados são repetidas na árvore BK.

Está tudo no github aqui . Ele também tem muitos testes de unidade.

A consulta em um conjunto de dados de 10 milhões de valores de hash para itens com uma distância de 4 resulta em tocar entre 0,25% e 0,5% dos valores na árvore e leva aproximadamente 100 ms.

Nome falso
fonte
BK-Tree na memória com 16 milhões de linhas na memória? Eu estava olhando para algo semelhante, no entanto, com 1000 imagens e 2000 descritores em cada imagem meu tamanho na memória era enorme.
Stewart
@ Stewart - Muito disso depende do tamanho do seu hash. No meu caso, a saída do valor de hash é um único campo de bits de 64 bits que eu armazeno como int64. Você parece ter um tipo de dados phash muito maior. Também não tenho certeza de como as pesquisas funcionariam em um tipo de dados diferente como esse. Eles ainda são um espaço métrico? Como você calcula a distância?
Fake Name
Estou usando descritores de 32 bits com o marcador da FLANN fornecido com o opencv. Para calcular a distância, uso hamming com um limite baseado na razão de Lowe. Neste ponto, não tenho certeza se é melhor tentar manter a memória na FLANN, que fornece uma estrutura em árvore KD ou mudar para uma solução mais semelhante à sua. Por que você acabou rolando sozinho e não apostando em algo como libflann?
Stewart
@ Stewart - eu não rolei o meu próprio. Estou usando um hash baseado em DFT super chato .
Fake Name
7

MOAR RESPOSTAS!

Ok, finalmente tirei um tempo para escrever uma extensão de indexação personalizada do PostgreSQL. Eu usei a interface SP-GiST .

Isso foi bastante desafiador, principalmente porque o Posgres é grande .

De qualquer forma, como sempre, está no github aqui .

No que diz respeito ao desempenho, atualmente é ~ 2-3 vezes mais lento que a implementação de memória pura na minha outra resposta a esta pergunta, mas é muito mais conveniente usá-lo. ms / query - 150 ms / query, que ainda é bem pequeno).

Nome falso
fonte
Você é demais! Você pode adicionar um README sobre como instalar? Eu realmente nunca instalei nada no Postgres: P
HypeWolf
1
@HypeWolf - A raiz do repositório tem um README . Isso não cobre o que você quer?
Fake Name
Meu erro, eu não vi, não tenho certeza para onde estava olhando: /
HypeWolf
Estava procurando o README também. Está na pasta raiz. O link está indo para alguma subpasta. Isso foi confuso.
luckydonald 01/10/19