Что это вообще такое?

Под этим термином понимаются такие структуры данных или алгоритмы, результатом которых является не детерминированное «да» или «нет», а вероятностные ответы, например, «точно нет» и «возможно». Как правило, такие структуры позволяют существенно сэкономить вычислительные ресурсы в задачах, где допустимо получить примерный ответ.

В этой статье я сделаю обзор таких структур данных и расскажу, какую пользу они могут принести на практике. К базовым вероятностным структурам данных можно отнести фильтр Блума, HyperLogLog и Count-Min Sketch.

Фильтр Блума

Зачем нужен: чтобы проверить, принадлежит ли заданный элемент к множеству. Фильтр Блума довольно быстро обрабатывает большие объёмы данных и возвращает ответ в виде «нет»/«возможно». Стоит отметить, что фильтр Блума широко используется при поиске слов в тексте.

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

Добавление элемента в множество происходит по следующему алгоритму:

  1. Для нового элемента Х вычисляем все k хэш-функций

  2. Берём получившиеся значения h1, h2, …, hk и устанавливаем биты с этими номерами в 1

Добавление элемента в множество (изменившиеся биты обозначены красным)
Добавление элемента в множество (изменившиеся биты обозначены красным)

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

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

HyperLogLog

Зачем нужен: помогает оценить количество уникальных элементов в больших наборах данных, при этом оценка множества в 109 элементов при использовании ~1.5 КБ памяти имеет погрешность около 2%.

HyperLogLog основан на двух математических фактах:

  1. У «хороших» хэш-функций значения распределены равномерно.

  2. В случайном потоке двоичных чисел фиксированной длины (например, 32 или 64-битных чисел) суффикс из нулей длины k встречается в среднем раз в 2k элементов: поскольку вероятность встретить ноль на каждой позиции равна ½, вероятность встретить k нулей будет равна (½)k.

Теперь мы можем построить простой эстиматор: для каждого элемента множества посчитаем хэш и запомним длину максимального нулевого суффикса k. Тогда в нашем множестве будет примерно 2k элементов.

В реальности такая оценка нам не понравится – между 230 и 231 довольно большая разница, да и закон больших чисел нам говорит, что если ждать достаточно долго, то можно встретить суффикс любого размера.

Для того чтобы сделать более точную оценку, можно взять m независимых хэш-функций, затем для каждого элемента подсчитать длины нулевых суффиксов R1,R2,...,RN и усреднить результат:

Так как считать значения хэш-функций для каждого элемента дорого и элементов в множестве много, то в LogLog (пока что без Hyper) придумали такой трюк: давайте откусим первые M бит у хэша и назовём их номером нашей хэш-функции, а оставшаяся часть будет хэшем. Тогда достаточно посчитать всего 1 хэш, а точность не изменится.

В качестве последнего шага авторы HyperLogLog предлагают использовать гармоническое среднее и добавить множитель для поправки, чтобы увеличить точность:

Где HyperLogLog можно встретить в реальной жизни:

Count-Min Sketch

Зачем нужен: используется для приближенного подсчёта частоты элементов в потоке данных. Эта структура данных представляет поток данных в компактном виде, тем самым позволяя ему быстро отвечать на запросы о частоте встречаемости элементов. Count-Min Sketch задействуется в различных областях: от машинного обучения до обработки естественного языка.

Как и две предыдущие структуры данных, Count-Min Sketch использует несколько (D) хэш функций, для каждой из которых заводится массив счетчиков длины W:

Затем для каждого входящего элемента вычисляются D хэшей h1,h2,...,hD, соответствующие позициям в массивах, после чего счётчики в каждом массиве увеличиваются на 1.

При запросе частоты встречаемости элемента процесс повторяется – вычисляются D хэшей, а частота вычисляется как min(f1, …, fD), чтобы избежать коллизий.

Основная идея Count-Min Sketch заключается в том, что он хранит только минимальное количество элементов, которое необходимо для подсчёта частоты каждого элемента.

Где это используется на практике:

  • в приложениях по анализу сетевого трафика, частотности слов или обработке событий;

  • в Redis

Комментарии (7)


  1. begemot_sun
    26.06.2023 06:28
    +8

    Мой вопрос на тостере с сылками на кучу разных вероятностных алгоритмов: https://qna.habr.com/q/91971


  1. PrinceKorwin
    26.06.2023 06:28
    +6

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

    Хочется добавить, что вероятностная логика и структуры активно используются также и в системах автонавигации. Т.к. там все данные имеют свои вероятности как по показателям, так и по времени. И пока ты общитываешь ситуацию на их основе реальность за это время меняется и это тоже нужно учитывать перед принятием решения.

    Вообще это очень интересная тема!

    Даже наш мозг постоянно так работает.


    1. Zara6502
      26.06.2023 06:28
      -2

      какой у матча щёт?

      мама купила щёты.

      козлёнок всех пощитал. )


  1. domix32
    26.06.2023 06:28
    +1

    Первым в голову пришли списки с пропусками (skip list) в базах данных, позволяющих делать резервирование/репликацию.


  1. xakep666
    26.06.2023 06:28
    +3

    Можно еще добавить, что фильтр Блума дает возможность свести объединение и пересечение множеств к побитовому "или" и побитовому "и" соответственно. Но при условии, что наборы хеш-функций и длины векторов одинаковы.


  1. istreb
    26.06.2023 06:28

    Я так понимаю APPROX_COUNT_DISTINCT в Oracle построен на этом.


  1. flange
    26.06.2023 06:28

    Ссылка на HyperLogLog в Redis не работает.