


So implementieren Sie eine umfassendere Golang-Version des Kuckucksfilters
„Bestimmen, ob ein Wert in einer großen Menge enthalten ist“ (im Folgenden gemeinsam als Mengenzugehörigkeitstest bezeichnet) ist ein häufiges Datenverarbeitungsproblem. Wenn in der Vergangenheit eine bestimmte Falsch-Positiv-Rate zulässig ist, sind Bloom-Filter die erste Wahl, aber jetzt haben wir eine bessere Wahl: Kuckucksfilter. Neuere Unternehmen müssen Filter verwenden. Nach der Suche habe ich festgestellt, dass der Kuckucksfilter in unserem Szenario kostengünstiger und besser ist als der Bloom-Filter. Um die endgültige Technologieauswahl zu bestimmen, habe ich später, als ich mich für die Verwendung des Kuckucksfilters entschieden habe, festgestellt, dass es derzeit fast keine umfassenden Implementierungen von Golang gibt Fehler und Die Speicherplatznutzung wurde nicht maximiert, daher habe ich eine Version der Golang-Bibliothek unter Bezugnahme auf das Originalpapier und die ursprüngliche C++-Implementierung des Papiers transplantiert und optimiert. Die Details finden Sie unten. Die Codeadresse finden Sie hier. Willkommen zum Starren, Verwenden, Mitwirken und Debuggen: github.com/linvon/cuckoo-filter
Kuckucksfilter
Es gibt viele Einführungsartikel zum Kuckucksfilter im Internet, hier nicht mehr Einführung: Erwähnen Sie einfach die Hauptpunkte, um den folgenden Inhalt vorzustellen.
ist ein Filter, der auf dem Cuckoo-Hash-Algorithmus basiert. Es handelt sich im Wesentlichen um eine Cuckoo-Hash-Tabelle, die den Hash-Wert des Speicherelements speichert. Wenn Sie Bloom-Filter verstehen, sollten Sie wissen, dass das Prinzip von Bloom-Filtern darin besteht, mehrere Hashing-Methoden zu verwenden, um verschiedene Hashes von Speicherelementen Bit-Arrays zuzuordnen, und diese Bits bei der Abfrage zu überprüfen, um festzustellen, ob sie vorhanden sind.
Der Kuckucksfilter hasht das Speicherelement, entnimmt eine bestimmte Anzahl von Ziffern aus seinem Hash-Wert und speichert sie in einem Array. Bei der Abfrage stellt er fest, ob ein Hash gleicher Ziffern im Array vorhanden ist.
Warum Cuckoo Filter wählen? Sie speichern auch Hash-Werte, im Wesentlichen Multi-Bit-Hashes. Warum ist der Kuckucksfilter besser?
Erstens kann der Cuckoo-Hash-Tisch mehr Platz sparen, da er kompakter ist.
Der zweite Grund liegt darin, dass der Bloom-Filter beim Abfragen verschiedene Hash-Funktionen für mehrere Hashes verwendet, während der Cuckoo-Filter nur einen Hash benötigt, sodass die Abfrageeffizienz sehr hoch ist.
Der dritte Grund ist, dass der Cuckoo-Filter unterstützt wird Löschen, aber der Bloom-Filter unterstützt das Löschen nicht
Die Vorteile sind da, aber was sind die Nachteile? Im Vergleich zum Bloom-Filter verwendet der Cuckoo-Filter eine Backup-Kandidaten-Bucket-Lösung. Der Kandidaten-Bucket und der bevorzugte Bucket können durch XOR-Verknüpfung über die Position und den Speicherwert ermittelt werden. Diese Entsprechung erfordert, dass die Größe des Buckets exponentiell sein muss von 2
Beim Einfügen des Bloom-Filters wird der Hash berechnet und direkt in das Bit geschrieben. Nach der Berechnung des Kuckucksfilters kann es jedoch so aussehen, als ob der Fingerabdruck an der aktuellen Position gespeichert wurde. Der gespeicherte Fingerabdruck muss in den Kandidaten-Bucket geworfen werden. Je voller der Bucket ist, desto größer wird die Möglichkeit eines Konflikts und die Einfügezeit wird immer höher. Daher ist seine Einfügeleistung im Vergleich zum Bloom sehr schlecht Filter-
Einfügen doppelter Elemente: Stoff Der Long-Filter hat beim Einfügen doppelter Elemente keine Auswirkung, er setzt lediglich die vorhandenen Bits zurück. Der Kuckucksfilter verwirft vorhandene Werte, daher gibt es eine Obergrenze für das Einfügen wiederholter Elemente. Das Löschen des Kuckucksfilters ist nicht perfekt: Beim wiederholten Einfügen gelten die oben genannten Einschränkungen, und beim Löschen treten auch damit verbundene Probleme auf. : Das Löschen ist nur dann perfekt, wenn derselbe Hash-Wert einmal eingefügt wird. Wenn das Element gelöscht wird, ohne dass es eingefügt wurde, kann es zu einem versehentlichen Löschen kommen. Dies ist der gleiche Grund wie die Falsch-Positiv-Rate, wenn das Element mehrmals eingefügt wird Es wird nur ein Wert gelöscht. Sie müssen wissen, wie oft das Element eingefügt wurde, bevor es gelöscht werden kann, oder den Löschvorgang in einer Schleife ausführen, bis der Löschvorgang fehlschlägt. Lassen Sie uns sie noch einmal zusammenfassen. Bei dieser Art von Satzzugehörigkeitstestproblemen sind in den meisten Fällen mehr Lesevorgänge und weniger Schreibvorgänge erforderlich, und das Löschen des Kuckucksfilters ist zwar nicht perfekt, aber es gibt auch bessere Abfragen und eine bessere Speichereffizienz Es sollte gesagt werden, dass es in den meisten Fällen eine kostengünstigere Wahl ist.
Praktische Anleitung
Detaillierte Implementierung
Lassen Sie uns zunächst über das Konzept des Kuckucksfilters sprechen. Jeder Bucket speichert den Wert des eingefügten Elements nach der Hash-Berechnung Anzahl der Ziffern wird gespeichert.
Der Filter enthält n Eimer und die Anzahl der Eimer wird basierend auf der Anzahl der zu lagernden Artikel berechnet. Mithilfe des Hash-Algorithmus können wir berechnen, in welchem Bucket ein Element gespeichert werden soll. Darüber hinaus kann jeder zusätzliche Hash-Algorithmus einen Kandidaten-Bucket für ein Element generieren. Bei wiederholten Einfügungen wird das aktuell gespeicherte Element in den Kandidaten-Bucket verschoben . Geh rein. Theoretisch ist die Speicherplatzauslastung umso höher, je mehr Hash-Algorithmen vorhanden sind. In tatsächlichen Tests wurden jedoch k=2 Hash-Funktionen verwendet, um eine Auslastungsrate von 98 % zu erreichen.
Jeder Bucket speichert mehrere Fingerabdrücke. Dies hängt von der Größe des Buckets ab. Verschiedene Fingerabdrücke können demselben Bucket zugeordnet werden. Je größer der Bucket, desto höher ist die Speicherplatzauslastung, aber gleichzeitig werden bei jeder Abfrage mehr Fingerabdrücke im selben Bucket gescannt, sodass die Wahrscheinlichkeit, dass falsch positive Ergebnisse generiert werden, zu diesem Zeitpunkt höher ist Anzahl der gespeicherten Fingerabdrücke, um die Konfliktrate zu reduzieren.
In dem Papier werden mehrere Parameter erwähnt, die zur Implementierung des Kuckucksfilters erforderlich sind, hauptsächlich
- Anzahl der Hash-Funktionen (k): Anzahl der Hashes, 2 reicht aus
- Bucket-Größe (b): Wie viele Fingerabdrücke werden darin gespeichert Jeder Eimer
- Fingerabdruckgröße (f): Wie viele Bits des Hash-Werts jedes Fingerabdruckspeicherschlüssels
Lesen Sie den Artikel im Detail. In Kapitel 5 stützt sich der Autor auf experimentelle Daten, um uns zu sagen, wie wir den am besten geeigneten auswählen können Zu den Konstruktionsparametern können wir folgende Schlussfolgerung ziehen
- Der Filter kann nicht zu 100 % gefüllt werden, es gibt einen maximalen Belastungsfaktor α, dann beträgt der jedem Artikel zugewiesene Speicherplatz f/α
- Bei Beibehaltung der Gesamtgröße von Der Filter ändert sich nicht: Je größer der Bucket, desto höher der Auslastungsfaktor, d Bei gleicher Falsch-Positiv-Rate gilt: Je größer der Bucket, desto höher der Auslastungsfaktor.
Gemäß der obigen theoretischen Grundlage sind die relevanten experimentellen Daten:
- Wenn k=2 Hash-Funktionen verwendet werden Wenn die Bucket-Größe b = 1 ist (d. h. direkte Zuordnung der Hash-Tabelle), beträgt der Auslastungsfaktor α 50 %, bei Verwendung der Bucket-Größe b = 2, 4 oder 8 erhöht er sich jedoch auf 84 %, 95 % bzw. 98 %
- Um die Falsch-Positiv-Rate r sicherzustellen, muss $2b/2 ^fleq r$ sichergestellt werden, dann beträgt die Größe des Fingerabdrucks f ungefähr $f ≥ log_2(2b/r)=log_2( 1/r) + log_2(2b)$, dann betragen die amortisierten Anschaffungskosten jedes Artikels $C ≤ [log_2(1 /r) + log_2(2b)]/α$
- Die experimentellen Daten zeigen, dass bei r>0,002. Zwei Einträge pro Bucket führen zu etwas besseren Ergebnissen als die Verwendung von vier Einträgen pro Bucket. Wenn r auf 0,00001
0,002 ist, können Sie b = 4 verwenden, um halbsortierte Buckets zu aktivieren. Anschließend können wir die Größe von f berechnen, die wir benötigen, um die angestrebte Falsch-Positiv-Rate basierend auf b zu erreichen, sodass alle Filterparameter bestimmt sind. Wenn wir die obige Schlussfolgerung mit $1,44log_2(1/r)$ für jedes Element des Bloom-Filters vergleichen, können wir feststellen, dass der Kuckucksfilterraum kleiner ist, wenn die halbe Sortierung aktiviert ist und r<0,03 nicht aktiviert, Sortierung, es verschlechtert sich auf etwa r<0,003.
Einige erweiterte Erklärungen
Optimierung des Hash-Algorithmus
Obwohl wir angegeben haben, dass zwei Hash-Algorithmen erforderlich sind, reicht es für uns in der tatsächlichen Implementierung aus, einen Hash-Algorithmus zu verwenden, da dieser im Artikel als erwähnt wird Bei einer alternativen Bucket-Berechnungsmethode kann der zweite Hash-Wert durch XOR-Verknüpfung des ersten Hash-Werts mit dem an diesem Ort gespeicherten Fingerabdruck berechnet werden. Wenn Sie befürchten, dass wir den Hash des Fingerabdrucks und den Hash des Standorts immer noch separat berechnen müssen, können wir einfach einen Algorithmus verwenden, um einen 64-Bit-Hash zu erstellen, wobei die hohen 32 Bit zur Berechnung des Standorts und die niedrigen verwendet werden Zur Berechnung des Fingerabdrucks werden 32 Bit verwendet.
Warum kann ein halbsortierter Eimer nur bei b=4 verwendet werden?
Die Essenz der Halbsortierung besteht darin, vier Ziffern jedes Fingerabdrucks zu erfassen. Die vierstellige Speicherung von b-Fingerabdrücken kann als b-Hexadezimalzahl ausgedrückt werden In dieser Reihenfolge kann die entsprechende Anordnung gefunden werden, indem ihre Position indiziert wird, um den tatsächlich gespeicherten Wert zu erhalten. Wir können die Anzahl aller Situationstypen mit der folgenden Funktion berechnen
func getNum(base, k, b, f int, cnt *int) { for i := base; i < 1<
> 1 n |= n >> 2 n |= n >> 4 n |= n >> 8 n |= n >> 16 n |= n >> 32 n++ return uint(n)}func getNumOfKindAndBit(b, f int) { cnt := 0 getNum(0, 0, b, f, &cnt) fmt.Printf("Num of kinds: %v, Num of needed bits: %v\n", cnt, math.Log2(float64(getNextPow2(uint64(cnt)))))} Wenn b = 4, gibt es insgesamt 3786 Permutationen, was weniger als 4096 ist. Das heißt, 12 Bits können zum Speichern aller Permutationsindizes verwendet werden Wenn alle Fingerabdrücke direkt gespeichert werden, werden 4 x 4 = 16 Bit benötigt, wodurch 4 Bit eingespart werden, d. h. für jeden Fingerabdruck wird ein Bit gespeichert.
Es kann festgestellt werden, dass, wenn b 2 ist, die gleiche Anzahl gespeicherter Bits erforderlich ist, um die Halbsortierung zu aktivieren, was bedeutungslos ist. Wenn b zu groß ist, wird auch der zu speichernde Index schnell erweitert, was zu einem großen Verlust an Abfrageleistung führt. Daher ist b = 4 die kostengünstigste Option.
Darüber hinaus liegt die Wahl der Codierung zum Speichern vierstelliger Fingerabdrücke darin begründet, dass sie durch ein Hexadezimalsystem dargestellt werden kann, was für die Speicherung praktisch ist.
Parameterauswahl bei Verwendung der Halbsortierung
Bei Verwendung der Halbsortierung sollten Sie dies tun Stellen Sie sicher, dass $ceil(b (f-1)/8)
f/8)$, andernfalls ist der von der Halbsortierung belegte Platz derselbe Auswahl der Filtergröße
Der Gesamteimer Die Größe des Filters muss Exponentiell mal 2 sein. Versuchen Sie daher beim Festlegen der Filtergröße, $size/α ~=(<) 2^n$ zu erfüllen. Größe ist die Datenmenge, die ein Filter speichern soll, und Sie sollten bei Bedarf einen kleineren Wert wählen. Verwenden Sie mehrere Filter, um den Zieleffekt zu erzielen.
Golang-Implementierung stellte fest, dass die vorhandenen Implementierungen einige Mängel aufweisen:
Die meisten Bibliotheken haben feste b und f, das heißt, die Falsch-Positiv-Rate ist ebenfalls behoben und die Anpassungsfähigkeit ist nicht gutAlle Bibliotheken f sind in Bytes und können nur Wenn die Anpassung in Vielfachen von 8 ausgedrückt wird, ist es unpraktisch, die Falsch-Positiv-Rate anzupassen.- Alle Bibliotheken implementieren keine halbsortierten Buckets, was die Vorteile im Vergleich zu Bloom-Filtern erheblich verringert. Da Ihre eigenen Szenarien mehr Platz erfordern und angepasst werden müssen Falsch-Positiv-Rate, daher wurde die C++-Implementierung des Originalpapiers übertragen und einige Optimierungen vorgenommen, hauptsächlich einschließlich
- Unterstützung für die Anpassung von Parametern
- komprimierter Raum in ein kompaktes Bit Array und gespeicherte Fingerabdrücke Stück für Stück
- Unterstützt binäre Serialisierung
Das obige ist der detaillierte Inhalt vonSo implementieren Sie eine umfassendere Golang-Version des Kuckucksfilters. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Heiße KI -Werkzeuge

Undresser.AI Undress
KI-gestützte App zum Erstellen realistischer Aktfotos

AI Clothes Remover
Online-KI-Tool zum Entfernen von Kleidung aus Fotos.

Undress AI Tool
Ausziehbilder kostenlos

Clothoff.io
KI-Kleiderentferner

Video Face Swap
Tauschen Sie Gesichter in jedem Video mühelos mit unserem völlig kostenlosen KI-Gesichtstausch-Tool aus!

Heißer Artikel

Heiße Werkzeuge

Notepad++7.3.1
Einfach zu bedienender und kostenloser Code-Editor

SublimeText3 chinesische Version
Chinesische Version, sehr einfach zu bedienen

Senden Sie Studio 13.0.1
Leistungsstarke integrierte PHP-Entwicklungsumgebung

Dreamweaver CS6
Visuelle Webentwicklungstools

SublimeText3 Mac-Version
Codebearbeitungssoftware auf Gottesniveau (SublimeText3)

Heiße Themen





Das sichere Lesen und Schreiben von Dateien in Go ist von entscheidender Bedeutung. Zu den Richtlinien gehören: Überprüfen von Dateiberechtigungen, Schließen von Dateien mithilfe von Verzögerungen, Validieren von Dateipfaden, Verwenden von Kontext-Timeouts. Das Befolgen dieser Richtlinien gewährleistet die Sicherheit Ihrer Daten und die Robustheit Ihrer Anwendungen.

Wie konfiguriere ich Verbindungspooling für Go-Datenbankverbindungen? Verwenden Sie den DB-Typ im Datenbank-/SQL-Paket, um eine Datenbankverbindung zu erstellen. Legen Sie MaxOpenConns fest, um die maximale Anzahl gleichzeitiger Verbindungen festzulegen. Legen Sie ConnMaxLifetime fest, um den maximalen Lebenszyklus der Verbindung festzulegen.

Der Unterschied zwischen dem GoLang-Framework und dem Go-Framework spiegelt sich in der internen Architektur und den externen Funktionen wider. Das GoLang-Framework basiert auf der Go-Standardbibliothek und erweitert deren Funktionalität, während das Go-Framework aus unabhängigen Bibliotheken besteht, um bestimmte Zwecke zu erreichen. Das GoLang-Framework ist flexibler und das Go-Framework ist einfacher zu verwenden. Das GoLang-Framework hat einen leichten Leistungsvorteil und das Go-Framework ist skalierbarer. Fall: Gin-Gonic (Go-Framework) wird zum Erstellen der REST-API verwendet, während Echo (GoLang-Framework) zum Erstellen von Webanwendungen verwendet wird.

JSON-Daten können mithilfe der gjson-Bibliothek oder der json.Unmarshal-Funktion in einer MySQL-Datenbank gespeichert werden. Die gjson-Bibliothek bietet praktische Methoden zum Parsen von JSON-Feldern, und die Funktion json.Unmarshal erfordert einen Zieltypzeiger zum Unmarshalieren von JSON-Daten. Bei beiden Methoden müssen SQL-Anweisungen vorbereitet und Einfügevorgänge ausgeführt werden, um die Daten in der Datenbank beizubehalten.

Die FindStringSubmatch-Funktion findet die erste Teilzeichenfolge, die mit einem regulären Ausdruck übereinstimmt: Die Funktion gibt ein Segment zurück, das die passende Teilzeichenfolge enthält, wobei das erste Element die gesamte übereinstimmende Zeichenfolge und die nachfolgenden Elemente einzelne Teilzeichenfolgen sind. Codebeispiel: regexp.FindStringSubmatch(text,pattern) gibt einen Ausschnitt übereinstimmender Teilzeichenfolgen zurück. Praktischer Fall: Es kann verwendet werden, um den Domänennamen in der E-Mail-Adresse abzugleichen, zum Beispiel: email:="user@example.com", pattern:=@([^\s]+)$, um die Übereinstimmung des Domänennamens zu erhalten [1].

Backend Learning Path: Die Erkundungsreise von Front-End zu Back-End als Back-End-Anfänger, der sich von der Front-End-Entwicklung verwandelt, Sie haben bereits die Grundlage von Nodejs, ...

Die Verwendung vordefinierter Zeitzonen in Go umfasst die folgenden Schritte: Importieren Sie das Paket „time“. Laden Sie eine bestimmte Zeitzone über die LoadLocation-Funktion. Verwenden Sie die geladene Zeitzone für Vorgänge wie das Erstellen von Zeitobjekten, das Analysieren von Zeitzeichenfolgen und das Durchführen von Datums- und Uhrzeitkonvertierungen. Vergleichen Sie Daten mit unterschiedlichen Zeitzonen, um die Anwendung der vordefinierten Zeitzonenfunktion zu veranschaulichen.

Häufig gestellte Fragen zur Go-Framework-Entwicklung: Framework-Auswahl: Hängt von den Anwendungsanforderungen und Entwicklerpräferenzen ab, z. B. Gin (API), Echo (erweiterbar), Beego (ORM), Iris (Leistung). Installation und Verwendung: Verwenden Sie den Befehl gomod, um das Framework zu installieren, zu importieren und zu verwenden. Datenbankinteraktion: Verwenden Sie ORM-Bibliotheken wie gorm, um Datenbankverbindungen und -operationen herzustellen. Authentifizierung und Autorisierung: Verwenden Sie Sitzungsverwaltungs- und Authentifizierungs-Middleware wie gin-contrib/sessions. Praktischer Fall: Verwenden Sie das Gin-Framework, um eine einfache Blog-API zu erstellen, die POST, GET und andere Funktionen bereitstellt.
