предисловие
О лавине кеша, проникновении и выходе из строя Redis мы уже говорили. В статье мы говорили, что одним из способов решения проблемы проникновения в кэш является布隆过滤器
, но в прошлый раз я не говорил о том, как использовать фильтр Блума.
Как теплый человек, я восполню тебя, пожалуйста, позвони мнеIT老暖男
.
Что такое фильтр Блума
Фильтр Блума был предложен молодым человеком по имени Блум в 1970 году. С тех пор прошло пятьдесят лет, и он так же стар, как мой брат.
На самом деле это длинный двоичный вектор и ряд функций случайного отображения.Каждый должен знать, что двоичные данные равны либо 0, либо 1, а значение по умолчанию равно 0.
В основном используется для определения того, находится ли элемент в наборе, 0 означает不存在
Некоторые данные, 1 представляет存在
некоторые данные.
понимать? в виде暖男
Мой брат рисует для вас картинку, чтобы вы поняли:
Фильтр Блума использует
-
Устранение проникновения в кэш Redis (сосредоточьтесь на сегодняшнем дне)
-
При сканировании URL-адрес поискового робота фильтруется. URL-адрес, который уже существует в Bloom, не сканируется.
-
Фильтрация спама, чтобы определить, находится ли каждый адрес, с которого отправляются электронные письма, в черный список Блума, и если да, то он считается спамом.
Вышеупомянутое является лишь простым примером использования, вы можете сделать выводы из одного случая и гибко использовать его в своей работе.
Принцип фильтра Блума
процесс депозита
Как упоминалось выше, фильтр Блума представляет собой набор бинарных данных. Когда в эту коллекцию добавляется кусок данных, он подвергается следующим крещениям (здесь есть минусы, о которых речь пойдет ниже):
-
Вычислить данные с помощью K хеш-функций и вернуть K вычисленных хеш-значений.
-
Эти K хэш-значений сопоставляются с соответствующими K индексами двоичного массива.
-
Измените двоичные данные, соответствующие индексам K, на 1.
Например, если первая хэш-функция возвращает x, а вторая и третья хеш-функции возвращают y и z, то: двоичный код, соответствующий X, Y и Z, изменяется на 1.
как показано на рисунке:
процесс запроса
Основная функция фильтра Блума — запрос части данных, если ее нет в этом бинарном наборе, то процесс запроса выглядит следующим образом:
-
Данные рассчитываются с помощью K хэш-функций, соответствующих рассчитанным K хеш-значениям.
-
Найдите соответствующий индекс двоичного массива по хэш-значению
-
Суждение: если есть позиция, где двоичные данные равны 0, то данные не существуют. Если оба равны 1, данные существуют в коллекции. (Здесь есть недостатки, о которых будет сказано ниже)
удалить процесс
Как правило, данные в фильтре Блума нельзя удалить, это один из недостатков, который мы разберем ниже.
Преимущества и недостатки фильтров Блума
преимущество
-
Поскольку он хранит двоичные данные, он занимает очень мало места.
-
Скорость вставки и запроса очень высока, а временная сложность O (K). Вы можете думать о процессе HashMap.
-
Конфиденциальность хороша тем, что не хранит никаких необработанных данных, только двоичные данные.
недостаток
Это возвращает нас к упомянутым выше недостаткам.
Добавление данных осуществляется путем вычисления хеш-значения данных, поэтому весьма вероятно, что существует ситуация, когда вычисляются два разных данных для получения одного и того же хеш-значения.
Например, "你好
"и"hello
", если хэш-значение, наконец, будет рассчитано как то же самое, то они изменят двоичные данные того же индекса на 1.
В настоящее время вы не знаете, представляет ли двоичный индекс 2 "你好
"еще"hello
".
Это приводит к следующим недостаткам:
1. Неверное суждение
Если изображение выше не существует"hello
", только сохранено"你好
", затем используйте"hello
«Когда вы придете спрашивать, вы будете судить»hello
"Есть в коллекции.
потому что"你好
"и"hello
«Значение хеш-функции такое же, через одно и то же значение хеш-функции, найденные двоичные данные одинаковы, все 1.
2. Сложность удаления
Я не буду говорить это здесь, все должны понять, почему, как вы暖男老哥
, Давайте поговорим об этом.
Все еще используя приведенный выше пример, потому что "你好
"и"hello
"имеет такое же хэш-значение, и соответствующий индекс массива также одинаков.
В это время мой брат хочет удалить "你好
», нижний индекс — это двоичные данные в 2, которые изменяются с 1 на 0.
Так мы даже "hello
"Удалил все вместе. (0 значит есть эти данные, 1 значит нет таких данных)
На данный момент вы поняли фильтр Блума, и все они сказали, что я теплый человек.
Реализовать фильтр Блума
Существует множество реализаций, одна из которых — реализация, предоставляемая Guava.
1. Представьте конфигурацию Guava pom
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>
Во-вторых, реализация кода
Кстати, здесь мы измеряем уровень ложных срабатываний.
import com.google.common.hash.BloomFilter;
import com.google.common.hash.Funnels;
public class BloomFilterCase {
/**
* 预计要插入多少数据
*/
private static int size = 1000000;
/**
* 期望的误判率
*/
private static double fpp = 0.01;
/**
* 布隆过滤器
*/
private static BloomFilter<Integer> bloomFilter = BloomFilter.create(Funnels.integerFunnel(), size, fpp);
public static void main(String[] args) {
// 插入10万样本数据
for (int i = 0; i < size; i++) {
bloomFilter.put(i);
}
// 用另外十万测试数据,测试误判率
int count = 0;
for (int i = size; i < size + 100000; i++) {
if (bloomFilter.mightContain(i)) {
count++;
System.out.println(i + "误判了");
}
}
System.out.println("总共的误判数:" + count);
}
}
результат операции:
На 100 000 данных приходится 947 ложных срабатываний, что составляет около 0,01%, что является частотой ложных срабатываний, установленной в нашем коде: fpp = 0,01.
Копайте глубже в код
основнойBloomFilter.create
метод
@VisibleForTesting
static <T> BloomFilter<T> create(
Funnel<? super T> funnel, long expectedInsertions, double fpp, Strategy strategy) {
。。。。
}
Здесь четыре параметра:
-
funnel
: тип данных (обычно вызывается в классе инструментов Funnels) -
expectedInsertions
: ожидаемое количество значений для вставки -
fpp
: частота ложных срабатываний (по умолчанию 0,03) -
strategy
: хеш-алгоритм
Давайте сосредоточимся наfpp
параметр
частота ложных срабатываний fpp
Сценарий 1:fpp = 0.01
-
Количество ложных срабатываний: 947
-
Занять объем памяти: 9585058 цифр
Сценарий второй:fpp = 0.03
(параметр по умолчанию)
-
Количество ложных срабатываний: 3033
-
Занимаемый объем памяти: 7298440 цифр
Резюме сценария
-
Ложноположительный показатель может быть передан через
fpp
параметры для настройки -
Чем меньше fpp, тем больше требуется памяти: для 0,01 требуется более 9 миллионов цифр, а для 0,03 требуется более 7 миллионов цифр.
-
Чем меньше fpp, тем больше нужно хеш-функций для вычисления большего количества хэш-значений при добавлении данных в коллекцию и сохранения их в соответствующих индексах массива. (Забыл посмотреть на процесс фильтрации Блума и хранения данных выше)
надnumBits
, что означает, что для хранения одного миллиона чисел типа int необходимо количество цифр 7298440, более 7 миллионов цифр. Теоретически хранится один миллион чисел.Int составляет 4 байта и 32 бита, что требует 481000000 = 32 миллиона бит. Если для хранения используется HashMap, согласно 50-процентной эффективности хранения HashMap требуется 64 миллиона битов. Видно, что место для хранения BloomFilter очень мало, всего около 1/10 от HashMap.
надnumHashFunctions
Указывает, что требуется несколько операций хэш-функции для сопоставления различных индексов, чтобы сохранить, существуют ли эти числа (0 или 1).