В чем преимущество использования фильтров Блума?


109

Я читаю фильтры Блума, и они кажутся глупыми. Все, что вы можете сделать с помощью фильтра цветения, вы можете сделать с меньшим объемом пространства и более эффективно, используя одну хеш-функцию, а не несколько, или это то, что кажется. Зачем использовать фильтр цветения и чем он полезен?


5
вы читали статью в Википедии? Это довольно хорошо объясняет преимущества. en.wikipedia.org/wiki/Bloom_filter
Алекс Будовски,

@david, хотя это кажется маловероятным. k хеш-функций в постоянном пространстве будут иметь намного больше конфликтов, чем одна хеш-функция в постоянном пространстве.
головная боль

1
@Alex Я прочитал статью в Википедии. Я понимаю, о чем там говорится, но не понимаю, почему это вообще лучше. Почему это работает, понятно. Почему это полезно - нет.
головная боль

Этот писатель отлично справляется с этим michaelnielsen.org/ddi/why-bloom-filters-work-the-way-they-do
dranxo

2
@dranxo, лучше связанная статья jasondavies.com/bloomfilter .
Pacerier

Ответы:


157

Из Википедии :

Фильтры Блума имеют сильное преимущество в пространстве перед другими структурами данных для представления наборов, таких как самобалансирующиеся двоичные деревья поиска, попытки, хэш-таблицы или простые массивы или связанные списки записей. Большинство из них требует хранения как минимум самих элементов данных, что может потребовать от небольшого количества бит для небольших целых чисел до произвольного количества бит, например для строк (попытки являются исключением, поскольку они могут совместно использовать хранилище между элементы с одинаковыми префиксами). Связанные структуры влекут за собой дополнительные линейные накладные расходы на пространство для указателей. С другой стороны, для фильтра Блума с ошибкой 1% и оптимальным значением k требуется всего около 9,6 бит на элемент - независимо от размера элементов. Это преимущество частично связано с компактностью, унаследованной от массивов, и отчасти из-за его вероятностного характера. Если 1% ложных срабатываний кажется слишком высоким, каждый раз, когда мы добавляем около 4,8 бит на элемент, мы уменьшаем его в десять раз.

Мне довольно ясно.

Фильтр Блума не хранит сами элементы, это ключевой момент. Вы не используете фильтр цветения для проверки наличия элемента, вы используете его, чтобы проверить, действительно ли он отсутствует , поскольку он гарантирует отсутствие ложноотрицательных результатов. Это позволяет не выполнять дополнительную работу для элементов, которых нет в наборе (например, ввода-вывода диска для их поиска).

И все это занимает значительно меньше места, чем что-то вроде хеш-таблицы (которая, вероятно, будет частично находиться на диске для больших наборов данных). Хотя вы можете использовать фильтр цветения в сочетании с такой структурой, как хеш-таблица, если вы уверены, что элемент имеет шанс присутствовать.

Итак, пример использования может быть таким:

У вас много данных на диске - вы решаете, какую границу ошибки вы хотите (например, 1%), которая предписывает значение m . Затем определяется оптимальное k (по формуле, приведенной в статье). Вы заполняете свой фильтр из этих привязанных к диску данных один раз.

Теперь у вас есть фильтр в ОЗУ. Когда вам нужно обработать какой-либо элемент, вы запрашиваете свой фильтр, чтобы узнать, есть ли у него шансы на существование в вашем наборе данных. Если этого не произойдет, никаких дополнительных действий не будет. Нет чтения с диска и т. Д. (Что вам пришлось бы сделать, если бы это был хэш, дерево и т. Д.).

В противном случае, если фильтр говорит: «Да, это там», вероятность того, что это неправильно, составляет 1%, поэтому вы выполняете необходимую работу, чтобы выяснить это. В 99% случаев он действительно будет там, поэтому работа была не зря.


2
Если понятно, ответьте. Как это может быть более эффективным с точки зрения пространства, чем одна хеш-функция на наборе того же размера? Это просто создаст больше столкновений. Вы будете бегать по поиску отдельных хэш-функций, чтобы убедиться, что у вас есть 1 для всех хэш-функций. Я не понимаю этого преимущества перед использованием одной хеш-функции.
головная боль

19
Хеш-функция - это код, а не данные. С чем вы собираетесь использовать хеш-функцию? Хеш-таблица? В этом случае ваша таблица должна будет хранить ключи, которые могут быть произвольного размера, в отличие от фильтра Блума. Об этом говорится в отрывке.
Alex Budovski

3
Рассмотрим фильтр Блума только с одной хэш-функцией, а не k. В чем преимущество добавления дополнительных хеш-функций? Это просто создаст больше столкновений. Или я не прав?
головная боль

2
На это отвечает последний абзац «Пространственно-временные преимущества» статьи в Википедии и раздел «Вероятность ложных срабатываний».
Alex Budovski

4
Он просто щелкнул. Большое вам спасибо, это меня какое-то время беспокоило. Это уменьшает количество ложных срабатываний, потому что ложное срабатывание должно быть либо а) конфликтом для всех ваших хэш-функций, либо б) все пробелы были заполнены другими значениями. Думаю, выбор размера - непростой процесс. Поправьте меня, если я ошибаюсь, но я думаю, что понял. Спасибо всем.
головная боль

156

Алекс объяснил это довольно хорошо. Для тех, кто еще не совсем понял это, надеюсь, этот пример поможет вам понять:

Допустим, я работаю в Google в команде Chrome, и я хочу добавить в браузер функцию, которая уведомляет пользователя, если введенный им URL-адрес является вредоносным. Итак, у меня есть набор данных примерно из 1 миллиона вредоносных URL-адресов, размер этого файла составляет около 25 МБ. Поскольку размер довольно большой (большой по сравнению с размером самого браузера), я храню эти данные на удаленном сервере.

Случай 1: я использую хеш-функцию с хеш-таблицей. Я выбираю эффективную функцию хеширования и пропускаю все 1 миллион URL-адресов через функцию хеширования, чтобы получить хеш-ключи. Затем я создаю хеш-таблицу (массив), где хеш-ключ дает мне индекс для размещения этого URL-адреса. Итак, теперь, когда я хешировал и заполнил хеш-таблицу, я проверяю ее размер. Я сохранил все 1 миллион URL-адресов в хеш-таблице вместе с их ключами. Так что размер не менее 25 МБ. Эта хеш-таблица из-за своего размера будет храниться на удаленном сервере. Когда пользователь приходит и вводит URL-адрес в адресную строку, мне нужно проверить, не является ли он вредоносным. Таким образом, я пропускаю URL-адрес через хеш-функцию (сам браузер может это делать) и получаю хеш-ключ для этого URL-адреса. Теперь мне нужно сделать запрос на мой удаленный сервер с этим хеш-ключом, чтобы проверить, совпадает ли конкретный URL-адрес в моей хэш-таблице с этим конкретным ключом с тем, что ввел пользователь. Если да, то это злонамеренно, если нет, то не злонамеренно. Таким образом, каждый раз, когда пользователь вводит URL-адрес, должен выполняться запрос к удаленному серверу, чтобы проверить, является ли это вредоносным URL-адресом. Это займет много времени и замедлит работу моего браузера.

Случай 2: я использую фильтр цветения. Весь список из 1 миллиона URL-адресов пропускается через фильтр Блума с использованием нескольких хэш-функций, и соответствующие позиции помечаются как 1 в огромном массиве нулей. Допустим, мы хотим получить 1% ложных срабатываний, используя калькулятор фильтра Блума ( http://hur.st/bloomfilter?n=1000000&p=0.01), мы получаем размер необходимого фильтра Блума всего 1,13 МБ. Этот небольшой размер ожидается, поскольку, хотя размер массива огромен, мы храним только единицы или нули, а не URL-адреса, как в случае с хеш-таблицей. Этот массив можно рассматривать как битовый массив. То есть, поскольку у нас есть только два значения 1 и 0, мы можем установить отдельные биты вместо байтов. Это уменьшит занимаемое пространство в 8 раз. Этот цветной фильтр размером 1,13 МБ, из-за своего небольшого размера, может храниться в самом веб-браузере !! Таким образом, когда пользователь приходит и вводит URL-адрес, мы просто применяем необходимые хеш-функции (в самом браузере) и проверяем все позиции в фильтре цветения (который хранится в браузере). Значение 0 в любой из позиций говорит нам, что этот URL-адрес ОПРЕДЕЛЕННО НЕ входит в список вредоносных URL-адресов, и пользователь может свободно действовать. Таким образом, мы не обращались к серверу и, следовательно, экономили время. Значение 1 говорит нам, что URL МОЖЕТ быть в списке вредоносных URL. В этих случаях мы вызываем удаленный сервер, и там мы можем использовать другую хеш-функцию с некоторой хеш-таблицей, как в первом случае, чтобы получить и проверить, действительно ли присутствует URL-адрес. Поскольку в большинстве случаев URL-адрес вряд ли является вредоносным, фильтр small bloom в браузере обнаруживает это и, следовательно, экономит время, избегая вызовов удаленного сервера. Только в некоторых случаях, если фильтр bloom сообщает нам, что URL-адрес МОЖЕТ быть вредоносным, только в этих случаях мы обращаемся к серверу. Это «МОЖЕТ» на 99% верно. В этих случаях мы вызываем удаленный сервер, и там мы можем использовать другую хеш-функцию с некоторой хеш-таблицей, как в первом случае, чтобы получить и проверить, действительно ли присутствует URL-адрес. Поскольку в большинстве случаев URL-адрес вряд ли является вредоносным, фильтр small bloom в браузере обнаруживает это и, следовательно, экономит время, избегая вызовов удаленного сервера. Только в некоторых случаях, если фильтр bloom сообщает нам, что URL-адрес МОЖЕТ быть вредоносным, только в этих случаях мы обращаемся к серверу. Это «МОЖЕТ» на 99% верно. В этих случаях мы вызываем удаленный сервер, и там мы можем использовать другую хеш-функцию с некоторой хеш-таблицей, как в первом случае, чтобы получить и проверить, действительно ли присутствует URL-адрес. Поскольку в большинстве случаев URL-адрес вряд ли является вредоносным, фильтр small bloom в браузере обнаруживает это и, следовательно, экономит время, избегая вызовов удаленного сервера. Только в некоторых случаях, если фильтр bloom сообщает нам, что URL-адрес МОЖЕТ быть вредоносным, только в этих случаях мы обращаемся к серверу. Это «МОЖЕТ» на 99% верно. фильтр small bloom в браузере определяет это и, следовательно, экономит время, избегая обращений к удаленному серверу. Только в некоторых случаях, если фильтр bloom сообщает нам, что URL-адрес МОЖЕТ быть вредоносным, только в этих случаях мы обращаемся к серверу. Это «МОЖЕТ» на 99% верно. фильтр small bloom в браузере определяет это и, следовательно, экономит время, избегая обращений к удаленному серверу. Только в некоторых случаях, если фильтр bloom сообщает нам, что URL-адрес МОЖЕТ быть вредоносным, только в этих случаях мы обращаемся к серверу. Это «МОЖЕТ» на 99% верно.

Таким образом, используя небольшой фильтр цветения в браузере, мы сэкономили много времени, поскольку нам не нужно выполнять запросы к серверу для каждого введенного URL.

Мы видим, что хеш-таблица с единственной хеш-функцией используется совсем для другой цели, чем фильтр Блума. Надеюсь, это развеет ваши сомнения :)

редактировать :

Я реализовал фильтр цветения для задачи тестирования вредоносных URL-адресов в Python. Код можно найти здесь - https://github.com/tarunsharma1/Bloom-Filter . Код очень прост для понимания, а подробное описание содержится в файле readme.


3
Спасибо за сценарий использования.
Сквиггс.

1
Я не получил часть хеширования и связывания значения 0 или 1. Если мы используем массив и сохраняем в нем 0 и 1, как нам искать хеш-значение URL-адреса при выполнении теста? ?
divinedragon

1
Итак, в основном мы используем что-то, называемое хеш-функцией ... которая принимает URL-адрес в виде строки ... и выдает число ... мы используем это число и устанавливаем соответствующее значение индекса массива равным 1. Существует ряд различных хеш-функций, но важно то, что каждый раз, когда один и тот же URL-адрес передается через хеш-функцию, он должен генерировать одно и то же число. Примером хеш-функции может быть сложение значений ascii всех символов в URL-адресе. В фильтрах Блума мы используем множество функций хеширования и устанавливаем все значения индекса массива равными 1. Надеюсь, это развеяло ваши сомнения.
Tarun

1
Обычная хеш-таблица, такая как C #, HashSet<String>будет использовать 16 байтов на элемент элемента в лучшем случае, когда хеш-таблица полностью заполнена: 4 байта сопоставляются от «корзины» к записи в таблице записей (односвязная односвязная list), 4 байта для кэшированного хэш-кода, 4 байта для указателя «следующий», 4 байта для указателя на ключ. И это не считая размеров строк. В худшем случае это 40 байтов: половина записей не используется и 20 байтов на запись после того, как Stringуказатель расширится до 8 байтов для 64-битных архитектур.
Qwertie

Вам не нужно сохранять саму строку в хеш-наборе. Вы можете сохранить его хеш как значение, что значительно уменьшит размер хеш-набора. Затем вы можете поиграть с размером хэша - чем он больше, тем меньше будет ложных срабатываний.
user1028741

24

Я начну с объяснения того, что такое фильтр цветения, что он может и не может делать, зачем он нам нужен, покажу интуитивно понятное описание того, как он работает, а затем приведу несколько примеров, когда они могут быть полезны.

Итак, стандартный фильтр Блума - это вероятностная структура данных, которая может * :


  • добавить элемент в набор
  • проверьте, входит ли элемент в набор, сообщив definitely not in the setилиpossibly in the set

Именно possibly in the setпоэтому он называется вероятностным. Используя умные слова, это означает, что возможны ложные срабатывания (могут быть случаи, когда он ошибочно думает, что элемент положительный), но ложноотрицательные невозможны.

Но не может * :

  • убрать предмет из набора
  • дать вам список всех элементов, которые в настоящее время находятся в вашем наборе

* Этот набор банок / нельзя предназначен для базового фильтра цветения. Поскольку это полезная структура данных, которая была создана много лет назад, люди нашли, как дополнить ее другими полезными функциями.


Но подождите минутку: мы уже знаем структуру данных, которая может ответить на все это без расплывчатого «возможного», а также без всех ограничений (невозможно удалить, не может показать все). И это называется набором . И вот главное преимущество фильтра Блума: он занимает мало места и остается неизменным .

Это означает, что неважно, сколько элементов мы там храним, пространство будет одинаковым. Да, фильтр Блума с 10^6элементами (бесполезный фильтр Блума) займет такое же количество места, как фильтр Блума с 10^20элементами, и такое же пространство, как фильтр Блума с 0элементами. Так сколько места это займет? Вам решать (но есть обмен: чем больше у вас элементов, тем более неуверенным в своем possible in the setответе вы будете .

Еще одна крутая вещь - это то, что это пространственная постоянная. Когда вы сохраняете данные в набор, вы должны действительно сохранить эти данные. Поэтому, если вы храните, this long string in the setвам нужно использовать как минимум 27 байт пространства. Но для ошибки 1% и оптимального значения k ** вам понадобится ~ 9,6 бит (<2 байта) на любой элемент (будь то короткий int или огромная стена текста).

Другое свойство состоит в том, что все операции выполняются за постоянное время, что абсолютно не то же самое, что амортизированное постоянное время в случае наборов (помните, что если набор имеет коллизии, он может ухудшиться со O(n)временем).

** k - значение хэш-функций, используемых в фильтре Блума.


Я не буду описывать, как работают фильтры цветения (статья в википедии очень хорошо объясняет все). Здесь я кратко расскажу об основах.

  • вы инициируете пустой битовый массив длины m
  • вы выбираете kразные хэш-функции (чем независимее, тем лучше)
  • если вы хотите добавить элемент, вы вычисляете все kхэши этого значения и устанавливаете соответствующие биты в 1
  • если вы хотите проверить, существует ли элемент, вы также вычисляете все kхэши, и если хотя бы один из них не установлен, его наверняка нет в наборе. В противном случае это может быть в комплекте.

Даже этого описания достаточно, чтобы понять, почему мы не можем быть уверены (вы можете получить все биты из различных других значений). Вот очень хорошая визуализация того, как это работает .

введите описание изображения здесь


Итак, когда могут быть полезны фильтры Блума? Короткий ответ - везде, где допустимы ложные срабатывания и где вы хотите проверить, есть ли что-то в наборе , но даже если это не так, это может быть первой линией защиты, чтобы исключить дорогостоящие вызовы верификаторам.

Вот список более конкретных описаний:

  • стандартный пример вредоносных сайтов и браузер описан практически в любом месте , где люди говорят о цветении фильтрах
  • является слабым паролем: вместо того, чтобы иметь огромный набор всех возможных слабых паролей, вы можете просто проверить, действительно ли пароль не слабый, с гораздо меньшим фильтром Блума
  • если у вас есть список статей и список пользователей, вы можете использовать фильтр Блума, чтобы показать статьи пользователей, которые они не читали. Интересно то, что у вас может быть только один фильтр (вы проверяете, есть ли там комбинация user_id + article_id)
  • биткойн использует фильтр Блума для синхронизации кошелька
  • Веб-серверы Akamai используют фильтры Блума, чтобы не допустить сохранения в его дисковых кэшах «чудеса одного удара». Одноразовые чудеса - это веб-объекты, запрошенные пользователями только один раз, что, как обнаружил Akamai, применимо почти к трем четвертям их инфраструктуры кэширования. Использование фильтра Блума для обнаружения второго запроса веб-объекта и кэширования этого объекта только по его второму запросу предотвращает попадание чудеса одного попадания в дисковый кеш, значительно снижая нагрузку на диск и увеличивая частоту попаданий в дисковый кеш (взяты из примеров в фильтре Блума. статья в вики)

13

Фильтры Блума весьма полезны в биоинформатике. Они могут занимать больше места по сравнению с использованием обычного хеша, особенно когда размер строк, с которыми вы работаете, может составлять сотни миллионов букв с очень маленьким алфавитом, например {A, G, T, C}. Обычно они используются для оценки наличия или отсутствия определенного k-мер в геноме. Там пример , который используется для чего - то соответствующего здесь .

РЕДАКТИРОВАТЬ:

Множественные хеш-функции используются для минимизации ложных срабатываний. Есть надежда, что между всеми k-хэш-функциями каждое значение будет иметь уникальную подпись в битовом массиве по сравнению с любым другим возможным значением. Однако ложные срабатывания действительно существуют, но их можно свести к минимуму до приемлемого уровня. Используя эту технику, вы хешируете элементы независимо от их размера. При их поиске вы используете каждую хеш-функцию и проверяете, все ли их битовые значения равны 1.

Сравните это с геномом человека, где увеличение размера элемента значительно увеличивает размер хеш-таблицы (размер таблицы составляет 4 * 4 k ). Предполагается, что вы кодируете элементы, используя 2 бита на букву.


1
Извините, может я неправильно понял, но как они могут быть более эффективными по сравнению с обычным хешем? Хэш строки - это вывод фиксированной длины, и вы просто устанавливаете это значение на 0 или 1. Это то же самое, что и фильтры Блума, но фильтры Блума будут делать это с несколькими хеш-функциями. Где я недопонимаю?
головная боль

Бесполезно хранить только один хеш. Тогда у него не было бы возможности обрабатывать хеш-коллизии. В большинстве реализаций хэш-таблиц есть способ справиться с этим, влекущий за собой накладные расходы. Словари Python, например, хранят ключ вместе с хешем и начинают линейное зондирование при столкновении. Фильтр Блума отсекает это и пытается минимизировать ущерб, связанный с этим, используя несколько хешей.
Брет Фонтеккио,

1
Почему бы не создать фильтр цветения, но с одной хеш-функцией? возможно, «относительно большая» хеш-функция. Но один вместо многих
giorgim 08

7

Если фильтр Блума возвращает, что элемент является членом набора, существует определенная вероятность ложного срабатывания. Если бы для указания принадлежности к набору использовалась только одна хеш-функция, вероятность ложного срабатывания была бы выше, чем при использовании нескольких хэш-функций.


Нужна серьезная проработка
сути
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.