Lassen Sie mich versuchen, dies zu versuchen, um zu sehen, wie viel ich es schlachten kann. :-)
Zu Beginn müssen Sie also in der Lage sein, einen regulären Bloom-Filter zu erstellen, der eine begrenzte Anzahl von Elementen mit einer maximalen Wahrscheinlichkeit für ein falsches Positiv zulässt. Das Hinzufügen dieser Funktionen zu Ihrem Basisfilter ist erforderlich, bevor Sie versuchen, eine skalierbare Implementierung zu erstellen.
Bevor wir versuchen, die Wahrscheinlichkeit zu steuern und zu optimieren, ermitteln wir die Wahrscheinlichkeit für eine bestimmte Bloom-Filtergröße.
Zuerst teilen wir das Bitfeld nach der Anzahl der verfügbaren Hash-Funktionen (Gesamtzahl der Bits / Anzahl der Hash-Funktionen = Slices) auf, um k Slices von Bits zu erhalten, die jede Hash-Funktion darstellen, sodass jedes Element immer durch k Bits beschrieben wird.
Wenn Sie die Anzahl der Slices oder die Anzahl der Bits pro Slice erhöhen, verringert sich die Wahrscheinlichkeit von Fehlalarmen.
Daraus folgt auch, dass beim Hinzufügen von Elementen mehr Bits auf 1 gesetzt werden, so dass falsch-positive Ergebnisse zunehmen. Wir bezeichnen dies als das "Füllverhältnis" jeder Scheibe.
Wenn der Filter eine große Datenmenge enthält, können wir davon ausgehen, dass die Wahrscheinlichkeit falsch positiver Ergebnisse für diesen Filter das Füllungsverhältnis ist, das auf die Anzahl der Schichten angehoben wurde eine Permutation mit Wiederholungsproblem).
Wie können wir also herausfinden, wie eine Wahrscheinlichkeit für falsch positive Ergebnisse in einem Bloom-Filter ermittelt werden kann? Wir können die Anzahl der Slices ändern (was sich auf den Füllungsgrad auswirkt).
Um herauszufinden, wie viele Slices wir haben sollten, müssen wir zunächst den optimalen Füllgrad für ein Slice ermitteln. Da das Füllverhältnis durch die Anzahl der Bits in einem Slice bestimmt wird, die 1 gegenüber der Anzahl der Bits, die 0 sind, können wir bestimmen, dass jedes Bit mit einer Wahrscheinlichkeit von (100% - (1 / Bits in einem Slice) nicht gesetzt wird. ). Da wir mehrere Elemente einfügen werden, haben wir eine weitere Permutation mit Reputationsproblemen und erweitern die Dinge auf den erwarteten Füllungsgrad, der (100% - ((100% - (1 / Bit in einem Slice)) ^ beträgt "Elemente eingefügt")). Nun, es stellt sich heraus, dass dies einer anderen Gleichung sehr ähnlich ist. In der Arbeit wird der Füllgrad mit einer anderen Gleichung in Beziehung gesetzt, sodass er gut in eine Taylor-Reihe (1-e ^ (-n / m)) passt. Nach einigem Nachdenken stellt sich heraus, dass der optimale Füllgrad immer bei ca. 50% liegt.
Da also die Wahrscheinlichkeit eines Filters ist, dass der Füllgrad auf die Anzahl der Schichten angehoben wird, können wir 50% ausfüllen und P = (50%) ^ k oder k = log_2 (1 / P) erhalten. Mit dieser Funktion können wir dann die Anzahl der Schichten berechnen, die für einen bestimmten Filter in der Filterliste für einen skalierbaren Bloom-Filter generiert werden sollen.
def slices_count(false_positive_probability):
return math.ceil(math.log(1 / false_positive_probability, 2))
Bearbeiten: Nachdem ich dies geschrieben hatte, stieß ich auf eine Erwähnung der "Fünfzig-Prozent-Regel", als ich in TAoCP Vol. 1, S. 442-445 über die dynamische Speicherzuweisung auf Buddy-System-Basis nachlas -e ^ (-n / m)). Knuth verweist auch auf ein Papier "Die Fünfzig-Prozent-Regel überarbeitet" mit ein wenig Hintergrundinformationen zum Konzept ( pdf hier verfügbar ).
Ein Element befindet sich im skalierbaren Bloom-Filter, wenn ein Filter true zurückgibt. Daher können Sie Filter hinzufügen, ohne die Mitgliedschaftsabfragen für vorherige Elemente zu beeinflussen.
Um sicherzustellen, dass Sie immer noch eine Worst-Case-Falsch-Positiv-Garantie haben, werden neue Filter mit geometrisch abnehmenden Falsch-Positiv-Raten hinzugefügt. Beispielsweise weist der erste Filter falsch positive Rate
p
, die zweiterp
, die dritter^2p
, usw. Die Wahrscheinlichkeit eines falsch positiv in den skalierbaren Bloom - Filter wird dann von der Union begrenzt gebunden:sum_{k>=0} r^k p = p/(1-r)
.quelle
Hallo,
die Grundidee ist, zum ersten Filter hinzuzufügen, bis das Bitfeld des Filters der ersten Ebene gesättigt ist. Gesättigt zu sein bedeutet nicht, dass jedes Bit verwendet wird, aber es bedeutet, dass der Filter so viele Einträge enthält, dass zusätzliche Einträge zu viele Fehlalarme verursachen würden.
Ab dem Zeitpunkt der Sättigung wird kein neues Element zum gesättigten Filter hinzugefügt, sondern zu einem neuen und größeren Unterfilter (dem Filter der zweiten Ebene).
Um einen Wert zu finden, schlagen Sie ihn im Filter der ersten Ebene nach. Wenn Sie ihn dort nicht finden, schlagen Sie ihn im Filter der zweiten Ebene nach. Wenn Sie es in einem dieser Filter finden, ist es dem Filter (mit großer Wahrscheinlichkeit) "bekannt" (aufgrund der Art der Bloom-Filter können Fehlalarme auftreten). Wenn Sie den Wert in keinem der Filter finden können, hat der Filter ihn garantiert nicht gesehen. Dies kann natürlich als rekursive Datenstruktur ausgedrückt werden.
Vielleicht möchten Sie meinen Blog-Beitrag lesen , der eine skalierbare Bloom-Filter-Implementierung in Java und eine detaillierte Erklärung zu ihrer Funktionsweise enthält.
quelle