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

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


person headache    schedule 26.11.2010    source источник
comment
вы читали статью в Википедии? Это довольно хорошо объясняет преимущества. en.wikipedia.org/wiki/Bloom_filter   -  person Alex Budovski    schedule 26.11.2010
comment
@david, хотя это кажется маловероятным. k хеш-функций в постоянном пространстве будут иметь намного больше конфликтов, чем одна хеш-функция в постоянном пространстве.   -  person headache    schedule 26.11.2010
comment
@Alex Я прочитал статью в Википедии. Я понимаю, о чем там говорится, но не понимаю, почему это вообще лучше. Почему это работает, понятно. Почему это полезно - нет.   -  person headache    schedule 26.11.2010
comment
Этот писатель отлично справляется с этим michaelnielsen .org / ddi / why-bloom-filters-work-the-way-they-do   -  person dranxo    schedule 03.03.2014
comment
@dranxo, Связанная статья jasondavies.com/bloomfilter лучше.   -  person Pacerier    schedule 09.02.2015


Ответы (5)


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

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

Для меня это довольно ясно.

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

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

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

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

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

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

person Alex Budovski    schedule 26.11.2010
comment
Если понятно, ответьте. Как это может быть более эффективным с точки зрения пространства, чем одна хеш-функция на наборе того же размера? Это просто создаст больше столкновений. Вы будете бегать по поиску отдельных хэш-функций, чтобы убедиться, что у вас есть 1 во всех хэш-функциях. Я не понимаю этого преимущества перед использованием одной хеш-функции. - person headache; 26.11.2010
comment
Хеш-функция - это код, а не данные. С чем вы собираетесь использовать хеш-функцию? Хеш-таблица? В этом случае ваша таблица должна будет хранить ключи, которые могут иметь произвольный размер, в отличие от фильтра Блума. Об этом говорится в отрывке. - person Alex Budovski; 26.11.2010
comment
Рассмотрим фильтр Блума только с одной хэш-функцией, а не с k. В чем преимущество добавления дополнительных хэш-функций? Это просто создаст больше столкновений. Или я не прав? - person headache; 26.11.2010
comment
На это отвечает последний абзац «Пространственно-временные преимущества» в статье Википедии и раздел «Вероятность ложных срабатываний». - person Alex Budovski; 26.11.2010
comment
@headache: но обычно вы не столкнетесь со всеми хэш-функциями. - person Michael Burr; 26.11.2010
comment
Он просто щелкнул. Большое вам спасибо, это меня какое-то время беспокоило. Это уменьшает количество ложных срабатываний, потому что ложное срабатывание должно либо а) быть коллизией для всех ваших хэш-функций, либо б) все пробелы были заполнены другими значениями. Думаю, выбор размера должен быть непростым делом. Поправьте меня, если я ошибаюсь, но я думаю, что понимаю. Спасибо всем. - person headache; 26.11.2010
comment
@headache, Выбор размера должен быть сложным процессом, я думаю - не совсем, оптимальная формула уже дана в статье Википедии для k и m в условия n. - person Alex Budovski; 26.11.2010
comment
@AlexBudovski, во втором-последнем абзаце вы заявили, что нам пришлось бы выполнять [чтение с диска], если бы это был хеш. Однако зачем нам чтение с диска, если hash(item) даже не соответствует ни одному ключу в хеш-таблице? - person Pacerier; 14.08.2014
comment
@Pacerier Я собираюсь нанести удар. Если ваша хеш-таблица хранится на диске (например, база данных k / v, которая использует mmap), вам нужно будет нажать на диск, чтобы даже увидеть, существует ли вообще ключ. С фильтром Блума вы загружаете в память меньший набор информации о своих элементах и ​​выполняете поиск по нему. Я прав, Алекс? - person Kyle; 18.08.2014
comment
@Kyle, если бы у нас была хеш-таблица с 65536 ведрами, нам нужно было бы только 65536 бит (это всего лишь 64 КБ оперативной памяти, как бы фильтр Блума мог победить это?) - чтобы отслеживать все существующие или ... не состояние. Это так же просто, как boolean bucket_exist = state[hash(item, 0, 65536)], что требует ровно нулевых операций с диском. - person Pacerier; 18.08.2014
comment
Одно из лучших объяснений, зачем нужен фильтр цветения. Отличный ответ! - person seeker; 12.09.2014
comment
@Pacerier Это одна коллизия на каждые 65536 значений - довольно нетривиальная ошибка. Однако правильно, что значения не нужно хранить в хеш-таблице, достаточно логического поля. - person user3467349; 06.02.2015
comment
@ user3467349, ошибка 1/65536 в 655,36 раза меньше, чем коэффициент ошибок 1%: что вы имеете в виду под довольно нетривиальной? - person Pacerier; 06.05.2017
comment
@headache, AlexBudovski. Re Вы не используете фильтр цветения для проверки наличия элемента, вы используете его, чтобы проверить, действительно ли он отсутствует ... Обратите внимание, что это в точности то же самое, что и хеш-таблица. На самом деле, я никогда не понимал этого: Чем таблица с фильтром Блума отличается от таблицы с несколькими хешами? Разве это не одно и то же? - person Pacerier; 06.05.2017

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

Допустим, я работаю в 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-адресов в Python. Код можно найти здесь - https://github.com/tarunsharma1/Bloom-Filter код очень прост для понимания, а подробное описание содержится в файле readme.

person Tarun    schedule 14.05.2015
comment
Спасибо за сценарий использования. - person Squiggs.; 30.06.2015
comment
Я не получил часть хеширования и связывания значения 0 или 1. Если мы используем массив и сохраняем в нем 0 и 1, как нам искать хеш-значение URL-адреса, когда мы выполняем тест ? - person divinedragon; 12.08.2015
comment
Итак, в основном мы используем то, что называется хеш-функцией ... которая принимает URL-адрес в виде строки ... и выдает число ... мы используем это число и устанавливаем соответствующее значение индекса массива равным 1. Существует ряд различных хеш-функций, но важно то, что каждый раз, когда один и тот же URL-адрес передается через хеш-функцию, он должен генерировать одно и то же число. Примером хеш-функции может быть сложение значений ascii всех символов в URL-адресе. В фильтрах Блума мы используем множество хэш-функций и устанавливаем все значения индекса массива равными 1. Надеюсь, это развеяло ваши сомнения. - person Tarun; 16.08.2015
comment
Обычная хэш-таблица, такая как C # HashSet<String>, будет использовать 16 байтов на элемент элемента в лучшем случае, когда хеш-таблица полностью заполнена: 4 байта отображаются из сегмента в запись в таблице записей (односвязный список с массивом ), 4 байта для кэшированного хэш-кода, 4 байта для следующего указателя, 4 байта для указателя на ключ. И это не считая размеров строк. В худшем случае это 40 байтов: половина записей не используется и 20 байтов на запись после того, как указатель String расширится до 8 байтов для 64-битных архитектур. - person Qwertie; 31.10.2017
comment
Вам не нужно сохранять саму строку в хеш-наборе. Вы можете сохранить его хэш как значение, что значительно уменьшит размер хеш-набора. Затем вы можете поиграть с размером хеша - чем он больше, тем меньше будет вероятность ложных срабатываний. - person user1028741; 29.05.2019

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

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


  • добавить элемент в набор
  • проверьте, входит ли элемент в набор, сообщив 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, применимо почти к трем четвертям их инфраструктуры кэширования. Использование фильтра Блума для обнаружения второго запроса веб-объекта и кэширование этого объекта только по его второму запросу предотвращает попадание чудес с одним попаданием в дисковый кеш, значительно снижая нагрузку на диск и увеличивая частоту попаданий в дисковый кеш (взято из примеров в фильтре Блума. статья в вики)
person Salvador Dali    schedule 26.01.2016

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

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

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

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

person GWW    schedule 26.11.2010
comment
Извините, может я неправильно понял, но как они могут быть более эффективными по сравнению с обычным хешем? Хэш строки - это вывод фиксированной длины, и вы просто устанавливаете это значение на 0 или 1. То же самое и с фильтрами Блума, но с фильтрами Блума для нескольких хэш-функций. Где я недоразумение? - person headache; 26.11.2010
comment
Бесполезно хранить только один хеш. Тогда у него не было бы возможности обрабатывать хеш-коллизии. В большинстве реализаций хэш-таблиц есть способ справиться с этим, влекущий за собой накладные расходы. Словари Python, например, хранят ключ вместе с хешем и начинают линейное зондирование при столкновении. Фильтр Блума устраняет это и пытается минимизировать ущерб, связанный с этим, используя несколько хешей. - person Bret Fontecchio; 27.06.2014
comment
Почему бы не создать фильтр цветения, но с одной хэш-функцией? возможно, относительно большая хеш-функция. Но один вместо многих - person Giorgi Moniava; 08.08.2016

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

person Michael Burr    schedule 26.11.2010
comment
Требуется серьезная проработка сути ответа: вероятность ложного срабатывания будет выше, чем при использовании нескольких хеш-функций ... - person Pacerier; 06.05.2017