HyperLogLog es un algoritmo para el problema de recuento de elementos distintos , que aproxima el número de elementos distintos en un multiconjunto . [1] Calcular la cardinalidad exacta de los elementos distintos de un multiconjunto requiere una cantidad de memoria proporcional a la cardinalidad, lo que no es práctico para conjuntos de datos muy grandes. Los estimadores de cardinalidad probabilísticos, como el algoritmo HyperLogLog, utilizan significativamente menos memoria que esto, pero solo pueden aproximar la cardinalidad. El algoritmo HyperLogLog puede estimar cardinalidades de > 10 9 con una precisión típica (error estándar) del 2%, utilizando 1,5 kB de memoria. [1] HyperLogLog es una extensión del algoritmo LogLog anterior, [2] que a su vez deriva del algoritmo Flajolet-Martin de 1984. [3]
En el artículo original de Flajolet et al. [1] y en la literatura relacionada sobre el problema de recuento distinto , el término "cardinalidad" se utiliza para referirse al número de elementos distintos en un flujo de datos con elementos repetidos. Sin embargo, en la teoría de multiconjuntos, el término se refiere a la suma de multiplicidades de cada miembro de un multiconjunto. Este artículo opta por utilizar la definición de Flajolet para mantener la coherencia con las fuentes.
La base del algoritmo HyperLogLog es la observación de que la cardinalidad de un multiconjunto de números aleatorios distribuidos uniformemente se puede estimar calculando el número máximo de ceros iniciales en la representación binaria de cada número del conjunto. Si el número máximo de ceros iniciales observado es n , una estimación del número de elementos distintos en el conjunto es 2 n . [1]
En el algoritmo HyperLogLog, se aplica una función hash a cada elemento del multiconjunto original para obtener un multiconjunto de números aleatorios distribuidos uniformemente con la misma cardinalidad que el multiconjunto original. La cardinalidad de este conjunto distribuido aleatoriamente se puede estimar utilizando el algoritmo anterior.
La estimación simple de cardinalidad obtenida con el algoritmo anterior tiene la desventaja de una gran varianza . En el algoritmo HyperLogLog, la varianza se minimiza dividiendo el multiconjunto en numerosos subconjuntos, calculando la cantidad máxima de ceros iniciales en los números de cada uno de estos subconjuntos y utilizando una media armónica para combinar estas estimaciones para cada subconjunto en una estimación de la cardinalidad de todo el conjunto. [4]
El HyperLogLog tiene tres operaciones principales: add para añadir un nuevo elemento al conjunto, count para obtener la cardinalidad del conjunto y merge para obtener la unión de dos conjuntos. Algunas operaciones derivadas se pueden calcular utilizando el principio de inclusión-exclusión como la cardinalidad de la intersección o la cardinalidad de la diferencia entre dos HyperLogLogs combinando las operaciones merge y count.
Los datos del HyperLogLog se almacenan en una matriz M de m contadores (o "registros") que se inicializan a 0. La matriz M inicializada a partir de un multiconjunto S se denomina boceto HyperLogLog de S.
La operación de suma consiste en calcular el hash de los datos de entrada v con una función hash h , obteniendo los primeros b bits (donde b es ), y sumándoles 1 para obtener la dirección del registro a modificar. Con los bits restantes se calcula que devuelve la posición del 1 más a la izquierda, donde la posición más a la izquierda es 1 (en otras palabras: número de ceros a la izquierda más 1). El nuevo valor del registro será el máximo entre el valor actual del registro y .
El algoritmo de conteo consiste en calcular la media armónica de los m registros y utilizar una constante para derivar una estimación del conteo:
La intuición es que, al ser n la cardinalidad desconocida de M , cada subconjunto tendrá elementos. Entonces debería estar cerca de . La media armónica de 2 para estas cantidades es que debería estar cerca de . Por lo tanto, debería ser n aproximadamente.
Finalmente, se introduce la constante para corregir un sesgo multiplicativo sistemático presente debido a las colisiones hash.
La constante no es sencilla de calcular y se puede aproximar con la fórmula [1]
Sin embargo, la técnica HyperLogLog está sesgada para cardinalidades pequeñas por debajo de un umbral de . El artículo original propone utilizar un algoritmo diferente para cardinalidades pequeñas conocido como conteo lineal. [5] En el caso en que la estimación proporcionada anteriormente sea menor que el umbral , se puede utilizar el cálculo alternativo:
Además, para cardinalidades muy grandes que se acercan al límite del tamaño de los registros ( para registros de 32 bits), la cardinalidad se puede estimar con:
Con las correcciones anteriores para los límites inferior y superior, el error se puede estimar como .
La operación de fusión de dos HLL ( ) consiste en obtener el máximo para cada par de registros
Para analizar la complejidad se utiliza el modelo de streaming de datos [6] , que analiza el espacio necesario para obtener una aproximación con una probabilidad de éxito fija . El error relativo de HLL es y necesita espacio, donde n es la cardinalidad establecida y m es el número de registros (normalmente de tamaño inferior a un byte).
La operación de suma depende del tamaño de la salida de la función hash. Como este tamaño es fijo, podemos considerar que el tiempo de ejecución de la operación de suma es .
Las operaciones de conteo y fusión dependen del número de registros m y tienen un costo teórico de . En algunas implementaciones ( Redis ) [7] el número de registros es fijo y el costo se considera en la documentación.
El algoritmo HyperLogLog++ propone varias mejoras en el algoritmo HyperLogLog para reducir los requisitos de memoria y aumentar la precisión en algunos rangos de cardinalidades: [6]
Cuando los datos llegan en un solo flujo, el estimador de probabilidad inversa histórica o martingala [8] [9] mejora significativamente la precisión del esquema HLL y utiliza un 36 % menos de memoria para alcanzar un nivel de error determinado. Este estimador es demostrablemente óptimo para cualquier esquema de recuento aproximado distinto e insensible a los duplicados en un solo flujo.
El escenario de flujo único también genera variantes en la construcción del boceto HLL. HLL-TailCut+ utiliza un 45 % menos de memoria que el boceto HLL original, pero a costa de depender del orden de inserción de datos y no poder fusionar bocetos. [10]