Яка перевага у використанні фільтрів цвітіння?


108

Я читаю фільтри цвітіння, і вони просто здаються дурними. Все, що ви можете виконати за допомогою фільтра цвітіння, ви могли б досягти за менший простір, ефективніше, використовуючи одну функцію хешу, а не множину, або саме так здається. Чому б ви використовували фільтр цвітіння і чим він корисний?


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

Відповіді:


155

З Вікіпедії :

Фільтри Bloom мають сильну перевагу в просторі перед іншими структурами даних для представлення наборів, таких як самоврівноважувані двійкові дерева пошуку, спроби, хеш-таблиці або прості масиви або пов'язані списки записів. Більшість із них вимагає зберігання принаймні самих даних даних, для чого може знадобитися будь-яка кількість від невеликої кількості біт, для малих цілих чисел, до довільної кількості бітів, наприклад для рядків (спроби є винятком, оскільки вони можуть поділяти сховище між елементи з рівними префіксами). Пов'язані структури містять додатковий лінійний простір накладних для покажчиків. Фільтр Bloom з похибкою 1% та оптимальним значенням k, з іншого боку, вимагає лише близько 9,6 біт на елемент - незалежно від розміру елементів. Ця перевага частково походить від її компактності, успадкованої від масивів, і частково від його імовірнісного характеру Якщо 1% помилково позитивна ставка здається занадто високою, кожен раз, коли ми додаємо приблизно 4,8 біт на елемент, ми зменшуємо її в десять разів.

Досить зрозуміло мені.

Фільтруючий фільтр не зберігає самі елементи, це вирішальний момент. Ви не використовуєте фільтр цвітіння, щоб перевірити наявність елемента, ви використовуєте його для перевірки того, чи його немає , оскільки він не гарантує помилкових негативів. Це дозволяє вам не зайву роботу з елементами, які не існують у наборі (наприклад, дисковий ввід для їх пошуку).

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

Отже, прикладом використання може бути:

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

Тепер у вас є фільтр в оперативній пам'яті. Коли вам потрібно обробити якийсь елемент, ви запитаєте свій фільтр, щоб перевірити, чи є він у вашому наборі даних. Якщо цього не відбувається, додаткова робота не проводиться. Жоден диск не читає тощо (що б вам довелося зробити, якби це був хеш або дерево тощо).

В іншому випадку, якщо фільтр каже "Так, це там", є 1% шансів на те, що він неправильний, тому ви зробите необхідну роботу, щоб дізнатися це. 99% часу це дійсно буде там, тому робота була не дарма.


2
Якщо це зрозуміло, будь ласка, дайте відповідь. Як це може бути більш просторовим, ніж одна хеш-функція на одному розмірі? Це просто створить більше зіткнень. Ви підкажете пошук окремих хеш-функцій, щоб переконатися, що у вас є 1 на всіх хеш-функціях. Я не розумію, що це перевага перед використанням однієї хеш-функції.
головний біль

19
Хеш-функція - це код, а не дані. З чим ви маєте намір використовувати хеш-функцію? Хеш-таблиця? У такому випадку у вашій таблиці потрібно буде зберігати ключі, які можуть бути довільного розміру, на відміну від фільтра цвітіння. Про це згадується уривок.
Олексій Будовський

3
Розглянемо фільтр цвітіння лише з однією хеш-функцією, а не k. Яка перевага в додаванні більше хеш-функцій? Це просто створить більше зіткнень. Або я помиляюся?
головний біль

2
На це відповідає останній абзац у статті «Переваги простору та часу» у статті Вікіпедії та розділ «Ймовірність помилкових позитивних результатів».
Олексій Будовський

4
Це просто натиснуло. Дякую тобі, це мене надовго набридло. Він зменшує кількість помилкових позитивних результатів, оскільки хибний позитив повинен бути або: а) бути зіткненням усіх ваших хеш-функцій, або б) всі пробіли заповнені іншими значеннями. Тоді, я думаю, вибір розміру повинен бути складним процесом. Виправте мене, якщо я помиляюся, але, думаю, я це зрозумію. Дякую всім
головний біль

156

Алекс це досить добре пояснив. Для тих, хто ще не зрозумів це, сподіваємось, цей приклад допоможе вам зрозуміти:

Скажімо, я працюю в Google, в команді Chrome, і я хочу додати в браузер функцію, яка повідомляє користувача, якщо URL-адреса, яку він ввів, є шкідливою URL-адресою. Тож у мене є набір даних близько 1 мільйона шкідливих URL-адрес, розмір цього файлу - близько 25 МБ. Оскільки розмір досить великий, (великий порівняно з розміром самого браузера), я зберігаю ці дані на віддаленому сервері.

Випадок 1: Я використовую хеш-функцію з хеш-таблицею. Я вирішую ефективну функцію хешування та запускаю всі 1 мільйон URL-адрес через хеш-функцію, щоб отримати хеш-ключі. Потім я складаю хеш-таблицю (масив), де хеш-ключ дасть мені індекс для розміщення цієї URL-адреси. Отож тепер, коли я хешировав і заповнив хеш-таблицю, я перевіряю її розмір. Я зберігав усі 1 мільйон URL-адрес у хеш-таблиці разом з їх ключами. Тож розмір становить не менше 25 Мб. Ця хеш-таблиця через свій розмір буде зберігатися на віддаленому сервері. Коли користувач приходить і вводить URL-адресу в адресний рядок, мені потрібно перевірити, чи є він шкідливим. Таким чином я запускаю URL-адресу через хеш-функцію (сам браузер може це зробити), і я отримую хеш-ключ для цієї URL-адреси. Тепер я повинен зробити запит на віддалений сервер за допомогою цього хеш-ключа, перевірити, чи вказана конкретна URL-адреса в моїй хеш-таблиці з цим конкретним ключем відповідає тому, що вказав користувач. Якщо так, то це шкідливо, а якщо ні, то це не шкідливо. Таким чином, кожен раз, коли користувач вводить URL-адресу, повинен бути зроблений запит на віддалений сервер, щоб перевірити, чи це зловмисна URL-адреса. Це займе багато часу і, таким чином, зробить браузер повільним.

Випадок 2: Я використовую фільтр цвітіння. Весь список з 1 мільйона URL-адрес проходить через фільтр цвітіння за допомогою декількох хеш-функцій, а відповідні позиції позначені як 1, у величезному масиві 0. Скажімо, ми хочемо отримати помилково позитивну ставку 1%, використовуючи калькулятор фільтра цвітіння ( http://hur.st/bloomfilter?n=1000000&p=0.01), ми отримуємо необхідний розмір фільтра розпускання лише 1,13 Мбайт. Цей невеликий розмір очікується, оскільки, хоча розмір масиву величезний, ми зберігаємо лише 1s або 0s, а не URL-адреси, як у випадку з хеш-таблицею. Цей масив можна розглядати як бітовий масив. Тобто, оскільки у нас є лише два значення 1 і 0, ми можемо встановлювати окремі біти замість байтів. Це дозволило б зменшити простір, зайнятий у 8 разів. Цей фільтр для цвітіння 1,13 Мб, завдяки малому розміру, може зберігатися у самому веб-браузері !! Таким чином, коли користувач приходить і вводить URL-адресу, ми просто застосовуємо необхідні хеш-функції (у самому браузері) та перевіряємо всі позиції у фільтрі розквітання (який зберігається у браузері). Значення 0 у будь-якій з позицій говорить про те, що ця URL-адреса ВИЗНАЧЕНО НЕ в списку шкідливих URL-адрес, і користувач може вільно діяти. Таким чином, ми не телефонували на сервер, а значить, економили час. Значення 1 говорить нам, що URL-адреса МОЖЕ бути у списку шкідливих URL-адрес. У цих випадках ми здійснюємо дзвінок на віддалений сервер і там ми можемо використовувати якусь іншу хеш-функцію з якоюсь хеш-таблицею, як у першому випадку, щоб отримати та перевірити, чи справді є URL-адреса. Оскільки в більшості випадків URL-адреса, мабуть, не є шкідливою, малий фільтр цвітіння у веб-переглядачі показує, що це і, отже, економить час, уникаючи дзвінків на віддалений сервер. Лише в деяких випадках, якщо фільтр цвітіння повідомляє нам, що URL-адреса МОЖЕ бути зловмисною, лише в цих випадках ми здійснюємо дзвінок на сервер. Це "МОЖЕ" на 99%. У цих випадках ми здійснюємо дзвінок на віддалений сервер і там ми можемо використовувати якусь іншу хеш-функцію з якоюсь хеш-таблицею, як у першому випадку, щоб отримати та перевірити, чи справді є URL-адреса. Оскільки в більшості випадків URL-адреса, мабуть, не є шкідливою, малий фільтр цвітіння у веб-переглядачі показує, що це і, отже, економить час, уникаючи дзвінків на віддалений сервер. Лише в деяких випадках, якщо фільтр цвітіння повідомляє нам, що URL-адреса МОЖЕ бути шкідливою, лише в тих випадках ми здійснюємо дзвінок на сервер. Це "МОЖЕ" на 99%. У цих випадках ми здійснюємо дзвінок на віддалений сервер і там ми можемо використовувати якусь іншу хеш-функцію з якоюсь хеш-таблицею, як у першому випадку, щоб отримати та перевірити, чи справді є URL-адреса. Оскільки в більшості випадків URL-адреса, мабуть, не є шкідливою, малий фільтр цвітіння у веб-переглядачі показує, що це і, отже, економить час, уникаючи дзвінків на віддалений сервер. Лише в деяких випадках, якщо фільтр цвітіння повідомляє нам, що URL-адреса МОЖЕ бути зловмисною, лише в цих випадках ми здійснюємо дзвінок на сервер. Це "МОЖЕ" на 99%. малий фільтр цвітіння у веб-переглядачі показує, що це дозволяє економити час, уникаючи дзвінків на віддалений сервер. Лише в деяких випадках, якщо фільтр цвітіння повідомляє нам, що URL-адреса МОЖЕ бути зловмисною, лише в цих випадках ми здійснюємо дзвінок на сервер. Це "МОЖЕ" на 99%. малий фільтр цвітіння у веб-переглядачі показує, що це дозволяє економити час, уникаючи дзвінків на віддалений сервер. Лише в деяких випадках, якщо фільтр цвітіння повідомляє нам, що 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. Сподіваюся, це очистило ваші сумніви.
Тарун

1
Звичайний хештел, такий як C #, HashSet<String>буде використовувати 16 байт на елемент елемента в найкращому сценарії, в якому хешбел повністю заповнений: 4 байти відображаються від "відра" до запису в таблиці записів (масив, упакований окремо, пов'язаний список), 4 байти для кешованого хеш-коду, 4 байти для вказівника "наступний", 4 байти для вказівника на ключ. І це не враховуючи розміри рядків. У гіршому випадку це 40 байт: половина записів не використовується, а 20 байтів за запис, як тільки Stringвказівник розширюється до 8 байт для 64-бітних архітектур.
Qwertie

Вам не доведеться зберігати сам String в наборі хешу. Ви можете зберегти хеш його як значення, зробивши хеш-пакет набагато меншим. Тоді ви можете грати з розміром хеша - чим він більший, тим меншою буде хибна позитивна швидкість.
користувач1028741

24

Почну з пояснення, що таке фільтр цвітіння, що він може, а що не може робити, навіщо він нам потрібен, покажу інтуїтивний опис, як він працює, а потім наведу приклад, коли вони можуть бути корисними.

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


  • додати елемент до набору
  • перевірити, чи є елемент у наборі, сказавши definitely not in the setабоpossibly in the set

Саме possibly in the setтому його називають імовірнісним. Використання розумних слів означає, що помилковий позитив можливі (можуть бути випадки, коли він помилково вважає, що елемент є позитивним), але хибнонегативний неможливий.

Але це не може * :

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

* Цей набір can / can призначений для базового фільтра цвітіння. Оскільки це корисна структура даних, створена давно, люди знайшли, як її доповнити іншими корисними функцій.


Але зачекайте хвилину: ми вже знаємо структуру даних, яка може відповісти на все це без розпливчастих "можливих", а також без усіх обмежень (не можна видалити, не можу показати все). І це називається безліччю . Ось тут головна перевага фільтра цвітіння: він є просторовим та постійним простором .

Це означає, що не важливо, скільки елементів ми зберігаємо там, простір буде однаковим. Так, фільтр цвітіння з 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 - значення хеш-функцій, що використовуються у фільтрі розпускання


Я не буду описувати, як працюють фільтри цвітіння (стаття wikipedia дуже добре пояснює все). Тут я лише коротко розповім основи.

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

Навіть цього опису достатньо, щоб зрозуміти, чому ми не можемо бути впевнені (ви можете отримати всі біти, встановлені з різних інших значень). Ось дуже приємна візуалізація того, як це працює .

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


Тож коли можуть бути корисними фільтри? Коротка відповідь - це скрізь, де помилкові позитивні є прийнятними і де ви хочете перевірити, чи є щось у наборі , але навіть якщо їх немає, це може бути першою лінією захисту, щоб виключити дорогі дзвінки перевіряючих.

Ось перелік більш конкретних описів:

  • стандартний приклад шкідливих веб-сайтів і браузера описаний майже в будь-якому місці де люди говорять про фільтри цвітіння
  • це слабкі паролі: замість того, щоб мати величезний набір усіх можливих слабких паролів, ви можете просто перевірити, чи пароль, безумовно, не слабкий, маючи фільтр меншого розміру
  • якщо у вас є список статей та список користувачів, ви можете використовувати фільтр цвітіння, щоб показувати статті, які вони не читали. Цікавим є те, що у вас може бути лише один фільтр (ви перевіряєте, чи існує комбінація user_id + article_id)
  • bitcoin використовує фільтр розквіту для синхронізації гаманця
  • Веб-сервери Akamai використовують фільтри Bloom, щоб запобігти збереженню "дива-вражень" у своїх дискових кешах. Чудо-враження - це веб-об’єкти, які запитуються користувачами лише один раз, і те, що виявилося Akamai, застосовано до майже трьох четвертин інфраструктури кешування. Використання фільтра Bloom для виявлення другого запиту для веб-об’єкта та кешування цього об’єкта лише за його другим запитом запобігає потрапляння дива-удару в кеш диска, значно скорочуючи робоче навантаження диска та збільшуючи частоту звернень кеш-диска (взяті з прикладів у фільтрі Bloom стаття на wiki)

13

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

Редагувати:

Кілька хеш-функцій використовуються для мінімізації помилкових позитивних результатів. Сподіваємось, що між усіма k-хеш-функціями кожне значення матиме унікальну підпис у бітовому масиві порівняно з будь-яким іншим можливим значенням. Однак помилкові позитиви існують, але їх можна мінімізувати до керованого рівня. Використовуючи цю техніку, ви маєте хеш-елементи незалежно від їх розміру. Коли ви шукаєте їх, ви використовуєте кожну хеш-функцію та перевіряєте, чи всі їхні бітові значення 1.

Порівняйте це з геномом людини, де збільшення розміру елемента значно збільшує розмір хеш-таблиці (Розмір таблиці - 4 * 4 к ). Це передбачає, що ви кодуєте елементи, використовуючи 2 біти / букви.


1
Вибачте, можливо я нерозумію, але як вони можуть бути більш просторовими в порівнянні зі звичайним хешем? Хеш рядка має вихідну фіксовану довжину, і ви просто встановите це значення на 0 або 1. Це також те, що робили б фільтри розквітання, але фільтри розцвіту роблять це на кількох хеш-функціях. Де я непорозуміння?
головний біль

Не дуже корисно просто зберігати один хеш. Тоді б не було можливості впоратися з хеш-зіткненнями. У більшості реалізацій хеш-таблиць є спосіб вирішення цього питання, який виникає накладні витрати. Наприклад, словники Python зберігають ключ поряд із хешем і починають лінійно зондувати при зіткненні. Фільтр цвітіння вирізає це і намагається мінімізувати збитки, притаманні цьому, використовуючи кілька хешей.
Bret Fontecchio

1
Чому б не створити фільтр цвітіння, але лише з однією хеш-функцією? можливо "відносно велика" хеш-функція. Але один замість багатьох
giorgim

7

Якщо фільтр Bloom повертає, що елемент є набором, існує певна ймовірність помилкового додатного. Якби для позначення членства в наборі використовувалася лише одна хеш-функція, ймовірність помилкового додатника була б вищою, ніж використання декількох хеш-функцій.


Потрібна серйозна деталізація щодо м'яса відповіді: " ймовірність помилкового позитиву була б вищою, ніж використання декількох хеш-функцій " ...
Pacerier
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.