Ich habe eine große Datenbank (16 Millionen Zeilen) mit wahrnehmbaren Hashes von Bildern.
Ich möchte in der Lage sein, nach Zeilen zu suchen, indem ich die Entfernung in einem angemessenen Zeitrahmen einschränke.
Derzeit denke ich, dass, soweit ich das Problem richtig verstehe, die beste Option hier eine benutzerdefinierte SP-GiST-Implementierung ist, die einen BK-Tree implementiert , aber das scheint eine Menge Arbeit zu sein, und ich bin immer noch unklar im praktischen Bereich Details zur ordnungsgemäßen Implementierung eines benutzerdefinierten Index. Die Berechnung der Hamming - Distanz ist lenkbar genug, und ich tun weiß , C, though.
Was ist hier grundsätzlich der richtige Ansatz? Ich muss in der Lage sein, Übereinstimmungen innerhalb einer bestimmten Bearbeitungsentfernung eines Hashs abzufragen. So wie ich es verstehe, ist Levenshtein-Abstand mit Zeichenfolgen gleicher Länge funktional ein Hamming-Abstand. Es gibt also zumindest eine gewisse Unterstützung für das, was ich möchte, obwohl es keine eindeutige Möglichkeit gibt, daraus einen Index zu erstellen (denken Sie daran, den Wert, nach dem ich frage) Ich kann den Abstand zu einem festen Wert nicht vorberechnen, da dies nur für diesen einen Wert sinnvoll wäre.
Die Hashes werden derzeit als 64-Zeichen-Zeichenfolge gespeichert, die die binäre ASCII-Codierung des Hashs enthält (z. B. "10010101 ..."), aber ich kann sie problemlos in int64 konvertieren. Das eigentliche Problem ist, dass ich in der Lage sein muss, relativ schnell abzufragen.
Es scheint möglich zu sein, etwas in der Art zu erreichen, wie ich es möchte pg_trgm
, aber ich bin mir ein wenig unklar, wie der Trigramm-Matching-Mechamismus funktioniert (insbesondere, welche Ähnlichkeitsmetrik gibt es tatsächlich wieder ? Es sieht aus Art wie Bearbeitungsentfernung).
Die Einfügeleistung ist nicht kritisch (es ist sehr rechenintensiv, die Hashes für jede Zeile zu berechnen), daher kümmere ich mich in erster Linie um die Suche.
quelle
Antworten:
Nun, ich habe eine Weile damit verbracht, eine benutzerdefinierte Postgres-C-Erweiterung zu schreiben, und habe gerade einen Cython-Datenbank-Wrapper geschrieben, der eine BK-Baumstruktur im Speicher beibehält.
Grundsätzlich wird eine speicherinterne Kopie der Phash-Werte aus der Datenbank verwaltet, und alle Aktualisierungen der Datenbank werden im BK-Baum wiedergegeben.
Es ist alles auf Github hier . Es hat auch viele Unit-Tests.
Das Abfragen eines Datensatzes mit 10 Millionen Hashwerten für Elemente mit einem Abstand von 4 führt zu einer Berührung von ~ 0,25% -0,5% der Werte im Baum und dauert ~ 100 ms.
quelle
MOAR ANTWORTEN!
Ok, ich habe mir endlich die Zeit genommen, eine benutzerdefinierte PostgreSQL-Indizierungserweiterung zu schreiben. Ich habe die SP-GiST-Schnittstelle verwendet .
Das war ziemlich herausfordernd, vor allem, weil Posgres groß ist .
Sowieso ist es hier wie immer auf Github .
In Bezug auf die Leistung ist es derzeit ca. 2-3 Mal langsamer als die Implementierung von Pure-in-Memory in meiner anderen Antwort auf diese Frage, aber es ist so viel praktischer zu verwenden, dass ich diesen Leistungstreffer gerne esse (realistischerweise ist es ca. 50) ms / query - 150 ms / query, was immer noch ziemlich klein ist).
quelle