에서 : https://www.cnblogs.com/linguanh/p/10460421.html
디렉토리
- 질문 프로토 타입
- 조건 선택
- HyperLogLog
- 베르누이 시행
- 예상 최적화
- 뭔가해야 할 일
- 비트 문자열
- 포인트 배럴
- 통신
- HyperLogLog의 응용 프로그램에서 레디 스
- 레디 스의 HyperLogLog 원리
- 드리프트 보정
- 거인의 어깨
질문 프로토 타입
당신은 이러한 기능을 구현하려면 :
있는 페이지 통계 APP 또는 웹 페이지는 사용자가 매일 입력합니다 얼마나 많은 수 있습니다. 동일한 사용자가 반복적으로 한 번 입력을 클릭 함.
스마트 즉시 사용의 생각 HashMap
이 될 수있는이 데이터 구조를,뿐만 아니라 디엠 퍼시스를 충족 할 수 있습니다. 사실, 이것은 다른 솔루션들 사이에서 솔루션입니다.
문제가 어려운 것은 아니지만, 그러나 변수에 참여는 일정 크기에 도달 한 후 간단한 질문이 문제가 될 것입니다. APP는 도달 니 카츠 사용자를 가정 百万
또는 千万以上级别
우리가 채택 할 경우 HashMap
관행, 프로그램이 메모리를 많이 차지 이어질 것입니다.
여기에서 우리는에서 추정하려고 HashMap
메모리 풋 프린트의 문제를 해결하는 시간. 정의 가정 HashMap
에 Key
는 AS string
유형 value
의 bool
. key
사용자에 해당하는 Id
, value
그것은이다 是否点击进入
. 물론, 경우 다른 사용자의 액세스 시간의 수백만. 이 HashMap
메모리 공간은 다음과 같습니다 100万 * (string + bool)
.
조건 선택
현재 솔루션을 기존의 상술 한 문제를, 말할 수 HashMap
는 최대 규모의 메모리 공간 중 하나입니다. 통계가 많이없는 경우, 당신은 문제를 해결하기 위해이 방법을 사용할 수 있습니다, 또한 달성 간단하다.
또한 B+ 树
, Bitmap 位图
및 이 문서는 소개 HyperLogLog
알고리즘 솔루션을.
특정 조건이 허락하에 통계 에러율 천만 뷰를 허용하는 이런 이만 이하의 최종 통계, 허용 범위 내에서 많은 양의 데이터를 허용하기 전에 채용 할 수있는 경우, HyperLogLog
알고리즘을 상기 카운트를 해결 유사한 문제.
HyperLogLog
HyperLogLog
이하에서는라고도 HLL
그것이 LogLog
알고리즘의 업그레이드 된 버전이 부정확 중량 계수를 제공하는 것이다. 다음과 같은 기능 :
- 코드는 달성하기 어렵습니다.
- 통계 데이터 메모리에, 약간의 엄청난 금액을 사용할 수 있도록
Redis
구현HyperLogLog
만12K
메모리는 통계가 될 수2^64
데이터입니다. - 특정 오류 수는 전체 오류 비율이 낮습니다. 0.81 %의 표준 오류입니다.
- 오류가 설정 될 수 있습니다
辅助计算因子
감소시킬 수 있습니다.
기본 데이터 형 메모리 풋 프린트에서 약간의 프로그램은 학생들의 이해를 가지고, 당신은 단지 필요합니다 12K
메모리 셀 수 2^64
데이터를 놀라게했다. 당신이 말하는 이유는 무엇입니까,의 다음 예제를 제공하자 :
가라 Java
일반적 언어 long
= 8 비트 1 바이트, 즉 : 바이트, 즉 8 비트이고, 8 바이트를 사용 long
가능한 데이터 유형의 최대 개수로 표현된다 2^63-1
. 위의에 해당 2^64
이 있다고 가정 수 2^63-1
에서, 많은 숫자 0 ~ 2^63-1
, 따라 long
와 1k = 1024字节
메모리의 총량을 계산하는 규칙이 있습니다 : ((2^63-1) * 8/1024)K
그것은 훨씬 더 많은 저장 공간보다, 매우 많은 수입니다 12K
. 그리고 HyperLogLog
당신은 수있는 12K
통계를 완료 할 수 있습니다.
베르누이 시행
왜 이해를 HyperLogLog
먼저 이해에서, 통계의 거대한 양의 매우 작은 데이터 메모리를 사용하기 전에 伯努利试验
.
伯努利试验
수학은概率论
이 이야기에서 유래이다, 내용의 일부抛硬币
.
코인은 양극과 음극을 모두 가지고 드로의 앞에 남중 떨어져 위로 확률 50 %있다. 그것은 지금까지 긍정적, 우리는 전체 재판으로 기록 나타날 때까지 가정은 항상 긍정적 인 표시 네 번 던질 수, 간 나타난 긍정적를 던질 수 있습니다, 동전 뒤집기있다. 여러 번만큼 긍정적이 있었다으로, 던지는 방법에 상관없이, 그것은 실험으로 기록됩니다. 이 테스트입니다 伯努利试验
.
그래서 많은 시간에 伯努利试验
이 가설에 대한 여러 번 n
번. 그것은이었다가 있다는 것을 의미 n
배 긍정적. 각 가정하면 伯努利试验
여러 번 던질 경험 k
. 우선 伯努利试验
, 수 설정된 k1
제 있도록 n
시간에 대응 kn
.
그 중,이에 대한 n
시간을 伯努利试验
던졌습니다, 우리는 확실히 최대 수있을 것이다 k
12 시간 후 우리는이 전화를 긍정적 인 표시 던지고, 예를 들어, k_max
토스의 가장 높은 숫자 대신.
伯努利试验
쉬운 다음과 같은 결론을 도출하기 :
- N 토스 베르누이 프로세스 k_max의 수보다 더 크다.
- 베르누이 프로세스 N 번, 적어도 한번 던지고 k_max들의 수와 동일
최대 우도 추정의 최종 접합 방법은, 그것이 발견 된 n
한 k_max
관계를 추정하는 존재 : n = 2^(k_max)
. 이 로컬 방식으로 정보의 기본적인 이해 우리가 전체 데이터 흐름 특성을 추정 이상 보일 수는 도출하고 확률 통계의 방법에 의해이 관계를 테스트 할 필요가있다.
예를 들어, 다음과 같이 :
第一次试验: 抛了3次才出现正面,此时 k=3,n=1
第二次试验: 抛了2次才出现正面,此时 k=2,n=2
第三次试验: 抛了6次才出现正面,此时 k=6,n=3
第n 次试验:抛了12次才出现正面,此时我们估算, n = 2^12
위의 예에서 실험군의 수가 3 개 그룹의 총 후 k_max = 6, 최종 N = 3 가정, 우리는 크게, 추정 식에 들어가는 3 ≠ 2 ^ 6. 이 추정 방법의 오차가 큰 경우 실험의 수가 작은 경우 즉,이다.
예상 최적화
예를 들어 위의 세 그룹에서, 우리는 추정했다. 하나의 둥근 경우, n이 큰 충분 다음 때, 추정 오류율은 여전히 작은 충분하지 감소하지만됩니다.
그것은 여러 라운드를 수행 할 수 있습니까? 예를 들어, 100 개 이상의 시험의 라운드, 다음은 각 라운드를 k_max 가지고, 다음 즉, 평균을 복용 : k_mx/100
. 그런 다음 최종 추정 N. 여기서 인 LogLog
추정 공식은 :
상기 화학식 DVLL
것과 대응 n
, constant
보정 계수, 및 특정 값의 불확실성은, 브랜치는 실제 상황에 따라 설정 될 수있다. m
이 시험 라운드의 수를 나타냅니다. 에 십자가와 헤드 R
평균 : (k_max_1 + ... + k_max_m)/m
.
이 테스트 라운드를 증가 시키면, 다음 걸릴 k_max
알고리즘의 평균 최적화 LogLog
방법을. 그리고 HyperLogLog
와 LogLog
의 차이는 그렇지 사용한다는 것입니다 平均数
,하지만 调和平均数
. 调和平均数
보다 平均数
장점 큰 충격 값이 쉽지 않다. 다음은 예입니다 :
임금을 평균 :
A는 B에 1,000 / 월 30,000 / 월입니다 평균 방법을 사용하다 : (30000 + 1000) / 2 = 15500
조화 평균에 의해 인 2 / (+ 1/1000 1/30000) ≈ 1935.484
물론, 调和平均数
비 平均数
효과가 더 좋을 것입니다. 다음은 인 调和平均数
계산의 방법, ∑
요약 기호.
뭔가해야 할 일
우리가 이미 알고보다도, 동전 던지기의 예에서, 베르누이 재판의 출현은 수 k_max
를 추정 할 n
.
그렇다면이 추정 방법 및 다음과 같은 문제는 그것과 관련이있다?
있는 페이지 통계 APP 또는 웹 페이지는 사용자가 매일 입력합니다 얼마나 많은 수 있습니다. 동일한 사용자가 반복적으로 1 회 기록 맞을
HyperLogLog
나는 일을하고 있습니다. 입력 데이터의 다음 단계는 :
1. 비트 문자열
으로 hash
기능, 데이터가 변환되고, 比特串
차례로, 예를 들어, 5 입력 : 101. 왜 변환해야합니까?
동전 던지기 및 서신으로 인해 比特串
최종 데이터가 변환되면 0 포지티브 네거티브 1이고, 10010000
볼 로우에서 하이, 후 오른쪽에서 왼쪽으로, 우리 때 처음 1, 말할 수 그것은 긍정적이다.
그래서 위의 추정 결론에 따라, 우리가 할 수있는 최대의 수를 실험의 수의 합계를 추정하는 실험 토스 동전의 앞을 던져 수 있으며, 같은가에 저장된 데이터를 기반으로합니다 그들의 가장 큰 일을 변환 k_max 위치가 저장되는 데이터의 양을 추정한다.
2. 포인트 배럴
얼마나 많은 포인트 버킷 휠을 구분됩니다. 저장소에 컴퓨터 추상, 비트 ( '비트) 단위로 저장되고, 길이 L (S)의 큰 배열이 S 동등이 그룹 m 기, m 관심들로 분할되고, 숫자는 각각이 대응하는 휠이며 손잡이의 비트들의 평균 개수를 P.이며 쉬운 다음과 같은 관계를 그리려면
- L = S.length
- L = 선택된 M과 P *
- K에서 S 메모리 점유 = L / 1,024분의 8
에서는 Redis
제 1, HyperLogLog
설정 : m = 16,834, p = 6 , L = 16,834 * 6. 점유에 메모리 = 16834 * 1024년 6월 8일 = 12K
같은 시각 :
第0组 第1组 .... 第16833组
[000 000] [000 000] [000 000] [000 000] .... [000 000]
3. 대응
이제 다시 우리의 원래 질문 APP 페이지의 사용자 통계로 이동합니다.
- APP는 설정 홈 키는 다음 주
- 사용자 ID는 다음과 같습니다 IDN, N-> 0, 1, 2, 3 ....
이 문제에 통계적으로 상이한 사용자 ID를 식별하는 사용자는, 우리는 같은 사용자 ID를 넣을 수 hash
입력. 즉 :
해시 (ID) = 비트 열
다른 사용자 ID는 필연적으로 다른 것입니다 比特串
. 각각은 比特串
, 위치 한 번도 최소한에 바인딩됩니다. 우리의 비유의 각 比特串
한 번 伯努利试验
.
이제 分轮
, 즉 分桶
. 우리는 서로를 설정할 수 있습니다 그래서 比特串
얼마나 많은 소수에 비트 배럴에있는 레이블 값에 해당한다 전에. 가정 比特串
사용자 ID가 존재하는 경우, 하부 두 비트하는 마커 배럴을 계산하는데 사용된다 比特串
1,001,011,000,011 :이다. 그것은 여기서 첨자 욕조 : 11(2) = 1*2^1 + 1*2^0 = 3
첫 번째 세 번째 배럴, 즉,이다.
위의 예에서, 상기 터브의 계산 된 수 및 나머지 比特串
인 : 10,010,110,000 로우에서 하이로 참조 (1)의 첫번째 발생의 위치는 5이다. 즉, 경우에 제 배럴 처음 세 시험 k_max = 5
. 도 5는 대응하는 이진 : 101, 각 비트는 P-욕조 때문이다. 이 P> = 3 (101)에 저장 될 수있는 경우.
상기 과정을 모방 다른 사용자 ID의 복수, 그것은 상이한 버킷 분산 각 버킷은 k_max를 갖는다. 당신이 계산 할 때 그리고 mian
사용자의 수를 하나의 추정치가있는 경우 페이지에 맞았습니다. , 추정 식을 대체 추정치를 제공 할 수있을 것입니다 k_max 모든 버킷의 최종 조합.
다음은 인 HyperLogLog
변수 및 의역의 조화 평균 추정 식의 조합 LogLog
같은 것의을 :
HyperLogLog의 응용 프로그램에서 레디 스
첫째, 레디 스에서, HyperLogLog는 고급 데이터 구조 중 하나입니다. 이 명령은 다음을 포함하여 제공하지만, 이에 국한되지 않습니다 :
- pfadd 키 값에 대응 저장된 키값
- pfcount 키 값의 수의 주요 통계
리콜 원래 APP 통계 페이지에서 사용자의 문제가. 키가 페이지 이름에 해당하는 경우, 값은 사용자 ID에 해당. 대응에 문제 다음 바로.
레디 스의 HyperLogLog 원리
前面我们已经认识到,它的实现中,设有 16384 个桶,即:2^14 = 16384,每个桶有 6 位,每个桶可以表达的最大数字是:2^5+2^4+...+1 = 63 ,二进制为: 111 111
。
对于命令:pfadd key value
在存入时,value 会被 hash 成 64 位,即 64 bit 的比特字符串,前 14 位用来选择这个 value 的比特串中从右往左
第一个 1 出现的下标位置数值要存到那个桶中去,即前 14 位用来分桶。设第一个1出现位置的数值为 index 。当 index=5 时,就是: ....10000 [01 0000 0000 0000]
之所以选 14位
来表达桶编号是因为,分了 16384 个桶,而 2^14 = 16384,刚好地,最大的时候可以把桶利用完,不造成浪费。假设一个字符串的前 14 位是:00 0000 0000 0010 (从右往左看) ,其十进制值为 2。那么 index 将会被转化后放到编号为 2 的桶。
index 的转化规则:
首先因为完整的 value 比特字符串是 64 位形式,减去 14 后,剩下 50 位,那么极端情况,出现 1 的位置,是在第 50 位,即位置是 50。此时 index = 50。此时先将 index 转为 2 进制,它是:110010 。
因为16384 个桶中,每个桶是 6 bit 组成的。刚好 110010 就被设置到了第 2 号桶中去了。请注意,50 已经是最坏的情况,且它都被容纳进去了。那么其他的不用想也肯定能被容纳进去。
因为 fpadd 的 key 可以设置多个 value。例如下面的例子:
pfadd lgh golang
pfadd lgh python
pfadd lgh java
根据上面的做法,不同的 value,会被设置到不同桶中去,如果出现了在同一个桶的,即前 14 位值是一样的,但是后面出现 1 的位置不一样。那么比较原来的 index 是否比新 index 大。是,则替换。否,则不变。
最终地,一个 key 所对应的 16384 个桶都设置了很多的 value 了,每个桶有一个k_max
。此时调用 pfcount 时,按照前面介绍的估算方式,便可以计算出 key 的设置了多少次 value,也就是统计值。
value 被转为 64 位的比特串,最终被按照上面的做法记录到每个桶中去。64 位转为十进制就是:2^64,HyperLogLog
仅用了:16384 * 6 /8 / 1024 K
存储空间就能统计多达 2^64 个数。
偏差修正
在估算的计算公式中,constant
变量不是一个定值,它会根据实际情况而被分支设置,例如下面的样子。
假设:m为分桶数,p是m的以2为底的对数。
// m 为桶数
switch (p) {
case 4:
constant = 0.673 * m * m; case 5: constant = 0.697 * m * m; case 6: constant = 0.709 * m * m; default: constant = (0.7213 / (1 + 1.079 / m)) * m * m; }
巨人的肩膀
由简单的抛硬币试验可以引导出如此的震撼的算法,数学之强大。
感谢下面两遍博文的指引:
本文所有图片来源于:
https://www.jianshu.com/p/55defda6dcd2
本文内容参考于:
手动直观观察 LogLog
和 HyperLogLog
变化的网站: