Ähnliche Bilder Suche von pHash Entfernung in Elasticsearch

Ähnliches Bild Suche problem

  • Millionen von Bildern pHash'ed gespeichert und in Elasticsearch.
  • Format ist "11001101...11" (Länge 64), kann aber geändert werden (besser nicht).

Gegeben, unterliegen Bild-hash "100111..10" wir wollen alle zu finden ähnlich wie Bild-hashes in Elasticsearch index innerhalb hamming-Distanz von 8.

Natürlich, Abfrage zurückgeben kann Bilder mit mehr Abstand als 8 und Skript in Elasticsearch oder außerhalb können filter der Ergebnismenge. Aber insgesamt suchen, mal muss innerhalb von 1 Sekunde oder so.

Unsere aktuelle Zuordnung

Jedes Dokument mit verschachtelten images Feld mit Bild hashes:

{
  "images": {
    "type": "nested", 
    "properties": {
      "pHashFingerprint": {"index": "not_analysed", "type": "string"}
    }
  }
}

Unsere schlechte Lösung

Tatsache: Elasticsearch fuzzy-query unterstützt die Levenshtein-Distanz von max 2 nur.

Wir verwendet benutzerdefinierte tokenisierung split 64-bit-Zeichenfolge in 4 Gruppen von 16 bits und do 4-Gruppe suchen, mit vier fuzzy-Abfragen.

Analyzer:

{
   "analysis": {
      "analyzer": {
         "split4_fingerprint_analyzer": {
            "type": "custom",
            "tokenizer": "split4_fingerprint_tokenizer"
         }
      },
      "tokenizer": {
         "split4_fingerprint_tokenizer": {
            "type": "pattern",
            "group": 0,
            "pattern": "([01]{16})"
         }
      }
   }
}

Dann neues Feld-mapping:

"index_analyzer": "split4_fingerprint_analyzer",

Dann Abfrage:

{
   "query": {
      "filtered": {
         "query": {
            "nested": {
               "path": "images",
               "query": {
                  "bool": {
                     "minimum_should_match": 2,
                     "should": [
                        {
                           "fuzzy": {
                              "phashFingerprint.split4": {
                                 "value": "0010100100111001",
                                 "fuzziness": 2
                              }
                           }
                        },
                        {
                           "fuzzy": {
                              "phashFingerprint.split4": {
                                 "value": "1010100100111001",
                                 "fuzziness": 2
                              }
                           }
                        },
                        {
                           "fuzzy": {
                              "phashFingerprint.split4": {
                                 "value": "0110100100111001",
                                 "fuzziness": 2
                              }
                           }
                        },
                        {
                           "fuzzy": {
                              "phashFingerprint.split4": {
                                 "value": "1110100100111001",
                                 "fuzziness": 2
                              }
                           }
                        }
                     ]
                  }
               }
            }
         },
         "filter": {}
      }
   }
}

Beachten Sie, dass wir Dokumente haben, die passenden Bilder, nicht die Bilder selbst, aber das sollte nicht ändern Sie die Dinge ein Menge.

Das problem ist, dass diese Abfrage gibt Hunderte von tausenden von Ergebnissen auch nach hinzufügen von weiteren Domänen-spezifischen Filter zur Reduzierung der anfänglichen Satz. Script hat zu viel Arbeit zu berechnen, die hamming-Distanz wieder, daher die Abfrage kann einige Minuten in Anspruch nehmen.

Als erwartet, wenn die Erhöhung minimum_should_match 3 und 4, nur die Teilmenge der Bilder, die gefunden werden müssen zurückgegeben werden, aber die Ergebnismenge ist klein und schnell. Unter 95% der benötigten Bilder werden zurückgegeben mit minimum_should_match == 3 aber wir brauchen 100% (oder 99,9 Prozent), wie mit minimum_should_match == 2.

Wir haben versucht, ähnliche Ansätze mit n-Gramm, aber noch nicht so viel Erfolg in gleicher Weise zu viele Ergebnisse.

Lösungen, die von anderen Daten-Strukturen und-Abfragen?

Bearbeiten:

Merkten wir, dass es ein Fehler war, in unserem Evaluierungsprozess und minimum_should_match == 2 liefert 100% der Ergebnisse. Doch die Verarbeitung Zeit danach dauert im Durchschnitt 5 Sekunden. Wir werden sehen, wenn das script lohnt sich die Optimierung.

  • Wenn B ist der ganzzahlige Anzahl von bits in jeder Fingerabdruck (0 <= B <= 64). Dann können Sie speichern B mit jedem Dokument, und zunächst filtern Sie alle Datensätze, in denen B < (sourceB - 8) und B - > (sourceB + 8). Sollte reduzieren Sie Ihre Fingerabdrücke unter Berücksichtigung von mindestens 4x gegeben ist die Gleichverteilung.
  • Während es wahr ist, dass Elasticsearch fuzzy-Abfrage und die meisten anderen APIs mit einer Unschärfe param unterstützen nur max edit-Distanz von 2, was fuzzy_like_this Abfrage? Ihre docs tun, beachten Sie, dass es eine Ausnahme für Sie, dass hier. Ich denke, dass könnte Ihnen ermöglichen, zu vermeiden, mit dem hacky Lösung, die Sie derzeit haben. Und natürlich, Sie sind nicht immer Ergebnisse innerhalb der hamming-Abstand 8 aber die Levenshtein-Distanz 8, so bin ich nicht sicher, ob Sie neu berechnet, dass.
  • das ist eine interessante Idee, obwohl, dass ist eine sehr große Auswahl, um die Suche auf diese Binomialverteilung, also Reduktion ist sehr klein.
  • danke, wir haben versucht, fuzzy_like_this, aber es dauert Minuten dauert ES und es ist eine veraltete Funktion. Gute Idee, obwohl.
  • Eigentlich ein paar Millionen Elemente ist nicht viel, sogar 100 Millionen 64-bit-Ganzzahlen (also 8 Byte) ist nur 800 MB RAM und passt problemlos auf der GPU. Ich konnte nicht finden eine gute Referenz, aber ich erwarte, dass CUDA-stream über das dataset in 10er Millisekunden und die genaue Liste als Ausgabe. In hoch-dimensionalen Räumen, insbesondere fuzzy-matching kann nicht profitieren viel von Indizierung und Datenstrukturen. Auch bei der Sortierung, die Sie durch gehen könnte 1740 Millionen 32-bit-keys / Sekunde!
  • Ich mag die CUDA-Idee. Ohne eine domain-spezifische hashing-Schema, wirklich der einzige Weg, um die Geschwindigkeit Ihrer Berechnung in Elasticsearch ist durch Splitter Ihre Daten über mehrere cluster-Knoten. In der Erwägung, dass auf einer GPU können Sie schreiben eine optimierte Hamming-tester, der parallelisiert werden kann 32-Wege ohne Netzwerk-oder Festplatten-IO.
  • Natürlich ^oben^ ist wohl die vorzeitige Optimierung, es sei denn, Sie müssen subsecond Reaktionszeit. (Dein Anwendungsfall ist das recall-konzentriert, so jemand ist eindeutig investiert in die Beurteilung von tausenden von hamming=8 Spiele, die dauern würde, genug user-Zeit/ - Aufwand zum Rendern Suche Leistung weniger kritisch.)
  • Re: Sie sind neueste update (minimum_should_match gibt 100%): Das ist toll!!! Wenn du einen Weg findest, um deine zu pushen Hamming-Wertung aus jeder Elasticsearch-cluster-Knoten, sparen Sie auf I/O-und post-processing. Look at function_score Abfragen mit script_score. Groovy unterstützt den XOR-operator (^) und Sie können die Verwendung von Java ist Integer.bitCount auf der XOR-Ausgang, um Ihnen Hamming-Gewicht.
  • Ich bin auf der Suche auf das gleiche problem, diesmal aber beginnend mit einem hex-string. Also mein Skript wird zuerst analysiert den hex-string in einen BigInteger und vergleicht dann mit den ankommenden string mit @PeterDixon-Moses Vorschlag von XOR-und dann bitCount. Es dauert noch viel zu lange, um zu verarbeiten. In der Tat, dies ist die zweite scoring-script, das ich habe versucht, mit ES (ich habe vorher versucht, viele Iterationen des euklidischen Distanz), und ich habe es nicht geschafft, eine bis-Skala noch. Ich möchte Frage Sie, wie Sie erwarten, dass diese Funktionen skalieren elastisch, aber ich kann nicht sehen, um die join-user-group!
  • Spotify hat ein open-source-tool namens [zu ärgern], [1] dass sich aus der box. [1]: github.com/spotify/annoy

Schreibe einen Kommentar