Requêtes de distance de hamming rapides dans PostgreSQL


15

J'ai une grande base de données (16 millions de lignes) contenant des hachages perceptuels d'images.

J'aimerais pouvoir rechercher des lignes en réduisant la distance dans un délai raisonnable.

Actuellement, pour autant que je comprends bien le problème, je pense que la meilleure option ici serait une implémentation SP-GiST personnalisée qui implémente un BK-Tree , mais cela semble beaucoup de travail, et je suis toujours flou sur la pratique les détails de l'implémentation correcte d'un index personnalisé. Calcul de la distance de Hamming est assez traitable, et je ne sais C, bien que.

Fondamentalement, quelle est l' approche appropriée ici? J'ai besoin de pouvoir rechercher des correspondances dans une certaine distance d'édition d'un hachage. Si je comprends bien, la distance de Levenshtein avec des chaînes de longueur égale est un obstacle fonctionnel à la distance, donc il existe au moins une prise en charge existante de ce que je veux, mais aucun moyen clair de créer un index à partir de celui-ci (rappelez-vous, la valeur que je recherche pour Je ne peux pas pré-calculer la distance à partir d'une valeur fixe, car cela ne serait utile que pour cette seule valeur).

Les hachages sont actuellement stockés sous la forme d'une chaîne de 64 caractères contenant l'encodage ASCII binaire du hachage (par exemple "10010101 ..."), mais je peux les convertir assez facilement en int64. Le vrai problème est que je dois pouvoir interroger relativement rapidement.

Il semble qu'il pourrait être possible de réaliser quelque chose dans le sens de ce que je veux avec le pg_trgm, mais je ne suis pas certain du fonctionnement du mécanisme de correspondance de trigrammes (en particulier, que représente réellement la métrique de similitude qu'il renvoie ? un peu comme edit-distance).

Les performances d'insertion ne sont pas critiques (il est très coûteux en calcul de calculer les hachages pour chaque ligne), donc je me soucie principalement de la recherche.



@NeilMcGuigan - Intéressant! La première présentation vient en fait des personnes qui maintiennent les systèmes SP-GiST et GIST dans les postgres.
Fake Name

Le premier lien concerne cependant quelque chose de fondamentalement différent. ils recherchent des intersections fixes, tandis que je cherche la distance de brouillage. Je pourrais embrouiller les phases en un ensemble, mais ce serait extrêmement compliqué et nécessiterais beaucoup de code de support partout ailleurs.
Fake Name

FWIW, À ce stade, j'ai plus ou moins conclu que je devais implémenter mon propre système d'indexation. Je recherche actuellement des indices SP-GiST personnalisés, mais je n'ai aucune idée de ce que je fais.
Fake Name

1
@FakeName: Lorsque vous dites la distance de hamming, je suppose que vous voulez dire la distance de hamming des chaînes de valeurs de hachage, pas les images? En d'autres termes, vous cherchez à demander: Trouver toutes les valeurs de hachage qui sont des substitutions de X bits loin du paramètre d'entrée
Thomas Kejser

Réponses:


11

Eh bien, j'ai passé un certain temps à étudier l'écriture d'une extension C postgres personnalisée, et j'ai fini par écrire un wrapper de base de données Cython qui maintient une structure d'arbre BK en mémoire.

Fondamentalement, il conserve une copie en mémoire des valeurs phash de la base de données et toutes les mises à jour de la base de données sont relues dans l'arborescence BK.

Tout est sur github ici . Il a également BEAUCOUP de tests unitaires.

L'interrogation sur un ensemble de données de 10 millions de valeurs de hachage pour les éléments avec une distance de 4 entraîne le toucher de ~ 0,25% à 0,5% des valeurs de l'arborescence et prend environ 100 ms.


BK-Tree en mémoire avec 16 millions de lignes en mémoire? Je regardais quelque chose de similaire mais avec 1000 images et 2000 descripteurs sur chaque image, ma taille en mémoire était énorme.
Stewart

@Stewart - Cela dépend en grande partie de la taille de votre hachage. Dans mon cas, la sortie de valeur de hachage est un seul champ binaire 64 bits que je stocke en tant qu'int64. Vous semblez avoir un type de données phash beaucoup plus large. Je ne sais pas non plus comment les recherches fonctionneraient sur un type de données différent comme celui-ci. Sont-ils toujours un espace métrique? Comment calculez-vous la distance?
Fake Name

J'utilise des descripteurs 32 bits avec le FLANN marcher fourni avec opencv. Pour calculer la distance, j'utilise le hamming avec un seuil basé sur le rapport de Lowe. À ce stade, je ne sais pas s'il est préférable d'essayer de conserver en mémoire FLANN qui fournit une structure d'arbre KD ou de passer à une solution plus similaire à la vôtre. Pourquoi avez-vous fini par rouler le vôtre et ne pas opter pour quelque chose comme libflann?
Stewart

@Stewart - Je n'ai pas roulé le mien. J'utilise un hachage basé sur DFT super ennuyeux .
Fake Name

7

MOAR RÉPONSES!

Ok, j'ai finalement pris le temps d'écrire une extension d'indexation PostgreSQL personnalisée. J'ai utilisé l' interface SP-GiST .

C'était assez difficile, principalement parce que Posgres est grand .

Quoi qu'il en soit, comme d'habitude, c'est sur github ici .

En termes de performances, il est actuellement environ 2 à 3 fois plus lent que l'implémentation pure en mémoire dans mon autre réponse à cette question, mais il est tellement plus pratique à utiliser que je mangerai volontiers ce résultat de performance (en réalité, c'est ~ 50 ms / requête - 150 ms / requête, ce qui est encore assez petit).


Tu es incroyable! Pouvez-vous ajouter un fichier README sur la façon d'installer? Je n'ai jamais vraiment installé quoi que ce soit dans Postgres: P
HypeWolf

1
@HypeWolf - La racine du dépôt a un README . Cela ne couvre-t-il pas ce que vous voulez?
Fake Name

Mon erreur, je ne l'ai pas vu, je ne sais pas où je cherchais: /
HypeWolf

Je cherchais aussi le fichier README. C'est dans le dossier racine. Le lien va vers un sous-dossier. C'était déroutant.
luckydonald
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.