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.
la source
Réponses:
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.
la source
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).
la source