87
Считаем уникальные элементы Константин Игнатов 7 ноября 2016

Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

  • Upload
    ontico

  • View
    137

  • Download
    3

Embed Size (px)

Citation preview

Page 1: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Считаем уникальныеэлементы

Константин Игнатов

7 ноября 2016

Page 2: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Имеем поток элементов∙ Хотим знать, сколько их было, без повторов∙ Не хотим хранить поток целиком

Что ищем

2

Page 3: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

SELECT COUNT DISTINCT . . .

∙ при оптимизации и планировании запросов к БД∙ при оценке количества уникальных пар SRC-DST

в роутере∙ при поиске паттернов в больших графах или

массивах данных∙ при web-аналитике

Где нужно

3

Page 4: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

U множество всех возможных элементов, n = |U|

S ⊂ U множество уникальных элементов в потоке

F0 = |S | количество элементов в этом множестве

ut ∈ S элемент на позиции t в потоке

Ut ⊂ S множество уникальных элементов, которые мы видели к моменту t

Считаем точно

4

Page 5: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Сколько стоит добавить один элемент вмножество?

∙ сортированный список∙ битовая маска из n = |U | бит

∙ Сколько стоит посчитать количество элементов?∙ А если элементов много? Очень?

Считаем точно

4

Page 6: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ F̃0 = (1 ± 𝜀)F0, 𝜀 > 0, 𝜀 ≪ 1∙ Как гарантировать, что ошибка будет меньше 𝜀?∙ Насколько меньше памяти можно использовать?

∙ Можно добиться линейного уменьшения∙ Ценой экспоненциального увеличения ошибки

∙ Как быть?

Считаем приблизительно

5

Page 7: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ F̃0 = (1 ± 𝜀)F0, 𝜀 > 0, 𝜀 ≪ 1∙ Как гарантировать, что ошибка будет меньше 𝜀?∙ Насколько меньше памяти можно использовать?

∙ Можно добиться линейного уменьшения∙ Ценой экспоненциального увеличения ошибки

∙ Как быть?

Считаем приблизительно

5

Page 8: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

1983 Flajolet, Martin Probabilistic Counting Algorithms for Data BaseApplications

1996 Alon, Matias, Szegedy The Space Complexity of Approximating theFrequency Moments

2002 Bar-Yossef, Jayram, Kumar, Sivakumar, Trevisan Counting DistinctElements in a Data Stream

2003 Durand, Flajolet LogLog Counting of Large Cardinalities

2003 Indyk, Woodruff Tight Lower Bounds for the Distinct Elements Problem

State of art

6

Page 9: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

2007 Flajolet, Fusy, Gandouet, Meunier HyperLogLog: the analysis of anear-optimal cardinality estimation algorithm

2010 Kane, Nelson, Woodruff Optimal Algorithm for the Distinct ElementsProblem

2012 Helmi, Lumbroso, Martinez, Viola Data Streams as Random Permutations:the Distinct Element Problem

State of art

6

Page 10: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Кратко об этапах работы алгоритма∙ Подробно об элементах алгоритмов

∙ Хэш-функции∙ Разделение потока∙ Статистики

∙ Подробно о том, почему всё это работает

План

7

Page 11: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

bloom filter: встречался ли этот элемент в потоке?

heavy hiters: какие элементы встречались чаще всего?

F∞moment: как часто встречался самый распространённый элемент

online pattern discovery: какие элементы чаще всего встречалисьвместе?

Связанные задачи

8

Page 12: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Bloom Filter

9

Page 13: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Bloom Filter

9

Page 14: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Bloom Filter

9

Page 15: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Bloom Filter

9

Page 16: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Bloom Filter

9

Page 17: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Bloom Filter

9

Page 18: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Sketch

10

Page 19: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Идея: храним не всю информацию, а только то, что необходимо для ответа

∙ В случае вероятностного алгоритма (вариант):∙ Храним и обновляем несколько значений x ,

вычисленных из увиденного потока∙ E [f (x)] асимптотически равно оцениваемой

величине∙ Var [f (x)] должно быть мало

Sketch

10

Page 20: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Sketch

10

Page 21: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Инициализация(для 𝜀 = 0.32)Выбрать большое простое число p, например 5247972723348490517Выбрать три функции, например:h(x) = (3813295331020233847x + 2061310418014472126) mod pg1(x) = (4905134244493838961x + 339751972700966608) mod p mod 1000g2(x) = (3462845419123084402x3+2920301559511116865x2+4398447080453503003x+1489413524815015911) mod p mod 10Создать сжатый массив C из m = 10 элементов, равных 0.

Вариант алгоритма

11

Page 22: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Для каждого объекта x

1 r = lsb (h(x)) — количество нулей справа вбинарном представлении хеша + 1

2 i = g(x)3 C [i ] = max (C [i ], r)

Вариант алгоритма

11

Page 23: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Получение результата

1 r = min(C )2 T — количество элементов в C , которые больше r

3 Ответ: 2r+1 log(1−Tm)

log(1− 1m)

Вариант алгоритма

11

Page 24: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Будем рассматривать алгоритм, который:∙ Отвечает с некоторой точностью 𝜀F0,𝜀 = F0 · (1 ± 𝜀)

∙ Может ответить с большей ошибкой свероятностью (1 − 𝛿) < 1

2

(𝜀, 𝛿)-аппроксимация

Вероятностные алгоритмы

12

Page 25: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Вероятность ошибки: 𝛿 < 12

∙ Вероятность не допустить ошибку: 1 − 𝛿 > 12

∙ При R повторах:∙ Биноминальное распределение∙ Нужно R

2 + 1 или больше верных ответов

∙R∑︀

i=R2+1

(︀Ri

)︀(1 − 𝛿)i 𝛿R−i

Уменьшение вероятности ошибки

13

Page 26: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

h : U → {0, 1, 2, 3, . . . ,m − 1}

или

h : U →{︂0,

1m,2m,3m, . . . , 1

}︂как правило, m 6 |U|

∙ В современных реализациях потоковыхалгоритмов, как правило:

∙ logm = 64 (64-битные хэш-функции).

Хэш-функции

14

Page 27: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Теоретически нам нужно, чтобы вероятностьувидеть любой элемент была одинаковой

∙ На практике так не бывает∙ Используем хэш-функции (теория):

∙ вероятность встретить определённый хэш 1m

∙ даже если исходные объекты «скучкованны»

Хэш-функции и случайные величины

15

Page 28: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Абсолютно случайная хэш-функция:∙ Для каждого элемента в U генерируем

случайное число от 0 до m∙ Храним n = |U | хэшей в массиве (векторе)∙ O (n logm) места в памяти

∙ Часто нам нужно несколько хэш-функций...

Память для хэш-функций

16

Page 29: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ На практике:∙ используется быстрая детерминистическая

функция от нескольких переменных∙ фиксируются все переменные кроме одной∙ нужно хранить только параметры функции∙ как правило,O (logm)

Память для хэш-функций

16

Page 30: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 31: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 32: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 33: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 34: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 35: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 36: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

435839x + 117959 mod 567857

Хэш-функции

17

Page 37: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 38: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 39: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 40: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 41: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 42: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Хэш-функции

17

Page 43: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ При абсолютно случайной хэш-функции всезначения не зависят друг от друга:Pr (h (x1) = c1, h (x2) = c2, . . . , h (xm) = cm) =

1mm

∀{︀ci ∈ 0,m − 1

}︀

Семейства хэш-функций

18

Page 44: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ На практике нам достаточно независимоститолько для небольшого числа хэшей k

∙ Выбираем хэш-функцию случайно изнекоторого семейства H

∙ например, для k = 2,(ax + b) mod p mod m,0 < a < p, 0 6 b < p:Prh∈H

(h (x1) = c1 ∧ h (x2) = c2) =1m2

∀x1, x2 ∈ U ,∀c1, c2 ∈ 0,m − 1

Семейства хэш-функций

18

Page 45: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Для произвольного k

h (x) =

[︂(︂k−1∑︀i=0

aix i)︂

mod p

]︂mod m

Pr (h (x1) = c1 ∧ h (x2) = c2 ∧ . . . ∧ h (xk) = ck) =1mk

∀x1 . . . xk ∈ U, ∀c1, . . . ck ∈ 0,m − 1

Семейства хэш-функций

18

Page 46: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Вероятность верного ответа (1 − 𝛿) и память∙ Вероятность и сложность (время выполнения)∙ Точность 𝜀 и память:

∙ теоретически 𝜀 = 1√M

∙ M — количество используемых хэш-функций

Компромиссы

19

Page 47: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ В некоторый момент переключаем выполнениеалгоритма с одного исполнителя (Алиса) кдругому (Боб)

∙ Алиса при этом должна отправить Бобусообщение. Дальше поток видит только Боб

∙ В конце Боб должен сказать, сколько былоэлементов в потоке с (𝜀, 𝛿) аппроксимацией

∙ Размер сообщения и есть потребление памяти

Теоретическое потребление памяти

20

Page 48: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Теоретический предел: O(︀

1𝜀2 + log n

)︀∙ Наиболее распространённый на практике

алгоритм: O(︀

1𝜀2 log log n

)︀n = |U | — количество возможных объектов (e.g. 264)

log n — количество бит в бинарном представлении n (e.g. 64)

log log n — количество бит, нужных для записи количества бит в n (e.g. 6)

Теоретическое потребление памяти

20

Page 49: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Сколько элементов в bloom-фильтре?

21

Page 50: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Сколько элементов в bloom-фильтре?

21

Page 51: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Сколько элементов в bloom-фильтре?

21

Page 52: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Сколько элементов в bloom-фильтре?

21

Page 53: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Переделываем bloom

22

Page 54: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Переделываем bloom

22

Page 55: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Переделываем bloom

22

Page 56: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Сколько чисел из 0,m имеют∙ k нулей в конце бинарного представления?∙ k нулей в начале?∙ k нулей или единиц подряд?

Вероятность «редкой птицы»

23

Page 57: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Pr (0 zeros) = 12

Pr (1 zero) = 12

Pr(2 zeros) = 14

Pr(k zeros) = 12k

∙ А после N увиденныхэлементов?

∙ 1 −(︀1 − 1

2k)︀N

Вероятность «редкой птицы»

23

Page 58: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Pr (0 zeros) = 12

Pr (1 zero) = 12

Pr(2 zeros) = 14

Pr(k zeros) = 12k

∙ А после N увиденныхэлементов?

∙ 1 −(︀1 − 1

2k)︀N

Вероятность «редкой птицы»

23

Page 59: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Pr (0 zeros) = 12

Pr (1 zero) = 12

Pr(2 zeros) = 14

Pr(k zeros) = 12k

∙ А после N увиденныхэлементов?

∙ 1 −(︀1 − 1

2k)︀N

Вероятность «редкой птицы»

23

Page 60: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Итого: в «сломанном» bloom-фильтре примерно2r𝜑 элементов

∙ r — номер первого бита 1 справа∙ 𝜑 — константа∙ Нужно объединить результаты нескольких

экспериментов (иначе будут ответы, кратныестепеням 2)

Вероятность «редкой птицы»

23

Page 61: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

𝜑 = 2−12 e𝛾

23

∞∏︁𝜌=1

[︂(4𝜌+ 1)(4𝜌+ 2)(4𝜌)(4𝜌+ 3)

]︂(−1)𝜈(𝜌)

≈ 0.77351

𝜈(𝜌) — количество 1-бит в бинарном представлении 𝜌

𝛾 = −∞́

0

ln xex dx — постоянная Эйлера

Интересная константа

24

Page 62: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Плохо: ответы, кратные степеням 2∙ Плохо: высокий разброс ошибки∙ Хотим провести M независимых экспериментов,

не дублируя поток∙ Заводим M корзинок и раскладываем элементы в

них при помощи ещё одной хэш-функции∙ как при балансировке нагрузки∙ одинаковые элементы всегда попадают в один

«подпоток»

Разделение потока

25

Page 63: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ NB: Первые элементы (K ∼ m) потока:∙ NB: Сколько останется пустых корзинок?

∙ Pr (bi) =1m Pr (∼ bi) =

(︀1 − 1

m

)︀∙ Pr (∼ bi after K ) =

(︀1 − 1

m

)︀K∙ Pr (bi after K ) = 1 −

(︀1 − 1

m

)︀K∙ Все корзинки одинаковые:E (emty) = m

(︁1 −

(︀1 − 1

m

)︀K)︁

Разделение потока

25

Page 64: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ применяем «сломанный bloom-фильтр» длякаждой корзинки, считаем среднее

∙ Точность: 𝜀 = 0.78√M

∙ Память: O(︀

1𝜀2 log n

)︀∙ Заменив арифметическое среднее на

гармоническое, получим 𝜀 = 1.02√M

Разделение потока

25

Page 65: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Нам не нужно хранить сами значения в«регистрах»

∙ Достаточно индекса нужного бита∙ вот тут и получается O

(︀1𝜀2 log log n

)︀

Наблюдение 1

26

Page 66: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ В получившемся массиве почти все числа будутодинаковыми

∙ Можно хранить минимальное значение отдельно,а остальное — сжать

∙ Существуют компактные структуры данных сбыстрым обновлением и запросами

∙ Память: O (sum (C )) (на практике: 3–4 1𝜀2)

∙ E (#bucket ≈ log F0) = m(︁1 −

(︀1 − 1

m

)︀F0)︁

∙ остаётся выразить F0

Наблюдение 2

27

Page 67: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

∙ Храним sketch за каждые несколько секунд∙ При запросе объединяем все затронутые

интервалы∙ учитываем, что min хранится отдельно

∙ Запускаем последний шаг алгоритма∙ Можем получить оценку не только за

произвольный интервал времени,∙ но и за объединение любых произвольных

интервалов

Я всё-таки хочу знать...

28

Page 68: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Redis∙ Специальная структура данных∙ Специальные команды для этой

структуры∙ Удобно для работы с небольшим

количеством множеств

Реализации

29

Page 69: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Clickhouse∙ Умеет делать запросы с использованием

вероятностных алгоритмов∙ По-умолчанию uniq() использует

вероятностный алгоритм∙ Понятие состояния алгоритма и

специальный тип данных

Реализации

29

Page 70: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

СпасибоКонстантин Игнатов@[email protected]

Page 71: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

2r (r — количество 1 в конце слова x):0 1 0 1 0 1 1 1 x

1 0 1 0 1 0 0 0 ∼ x

0 1 0 1 1 0 0 0 x + 10 0 0 0 1 0 0 0 ∼ x&(x + 1) = 2r

Bit tricks

31

Page 72: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

x mod y (нам не нужен результат деления)

∙ x % p = ( x >> 61) + ( x & p )

(если p = 261 − 1)∙ ( ( u i n t 1 2 8 ) x * ( u i n t 1 2 8 ) p ) >> 64

Bit tricks

31

Page 73: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

CRCCLMULPOPCNT

Bit tricks

31

Page 74: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 75: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 76: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 77: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 78: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 79: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 80: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 81: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 82: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 83: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 84: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 85: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 86: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32

Page 87: Хочу знать, сколько уникальных посетителей было на моём сайте за произвольный интервал времени в прошлом

Порядковая статистика

32