Uso de hll () y tdigest ()
Se aplica a: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
Supongamos que desea calcular el recuento de usuarios distintos todos los días durante los últimos siete días. Puede ejecutarse summarize dcount(user)
una vez al día con un intervalo filtrado a los últimos siete días. Este método es ineficaz, porque cada vez que se ejecuta el cálculo, hay una superposición de seis días con el cálculo anterior. También puede calcular un agregado para cada día y, a continuación, combinar estos agregados. Este método requiere que "recuerde" los últimos seis resultados, pero es mucho más eficaz.
Las consultas de creación de particiones como se describe son fáciles para agregados simples, como count()
y sum()
. También puede ser útil para agregados complejos, como dcount()
y percentiles()
. En este artículo se explica cómo Kusto admite estos cálculos.
En los ejemplos siguientes se muestra cómo usar hll
/tdigest
y demostrar que el uso de estos comandos es muy eficaz en algunos escenarios:
Importante
Los resultados de hll
, hll_if
, hll_merge
, tdigest
y tdigest_merge
son objetos de tipo dynamic
que otras funciones (dcount_hll
, percentile_tdigest
, percentiles_array_tdigest
, y percentrank_tdigest
). La codificación de este objeto puede cambiar con el tiempo (por ejemplo, debido a una actualización de software); sin embargo, estos cambios se realizarán de forma compatible con versiones anteriores, por lo que uno puede almacenar estos valores de forma persistente y hacer referencia a ellos en consultas de forma confiable.
Nota:
En algunos casos, los objetos dinámicos generados por o hll
las tdigest
funciones de agregado pueden ser grandes y superar la propiedad MaxValueSize predeterminada en la directiva de codificación. Si es así, el objeto se ingerirá como null.
Por ejemplo, al conservar la salida de la hll
función con el nivel de precisión 4, el tamaño del hll
objeto supera el valor predeterminado MaxValueSize, que es 1 MB.
Para evitar este problema, modifique la directiva de codificación de la columna como se muestra en los ejemplos siguientes.
range x from 1 to 1000000 step 1
| summarize hll(x,4)
| project sizeInMb = estimate_data_size(hll_x) / pow(1024,2)
Salida
sizeInMb |
---|
1.0000524520874 |
La ingesta de este objeto en una tabla antes de aplicar este tipo de directiva ingerirá null:
.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)
MyTable
| project isempty(hll_x)
Salida
Columna 1 |
---|
1 |
Para evitar la ingesta de null, use el tipo bigobject
de directiva de codificación especial , que invalida a MaxValueSize
2 MB de la siguiente manera:
.alter column MyTable.hll_x policy encoding type='bigobject'
Ingesta de un valor ahora en la misma tabla anterior:
.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)
ingiere el segundo valor correctamente:
MyTable
| project isempty(hll_x)
Salida
Columna 1 |
---|
1 |
0 |
Ejemplo: Recuento con marca de tiempo binned
Hay una tabla, , PageViewsHllTDigest
que contiene hll
valores de Pages vistos en cada hora. Desea que estos valores se binned en 12h
. Combine los hll
valores mediante la hll_merge()
función de agregado, con la marca de tiempo binned en 12h
. Use la función dcount_hll
para devolver el valor final dcount
:
PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 12h)
| project Timestamp , dcount_hll(merged_hll)
Salida
Marca de tiempo | dcount_hll_merged_hll |
---|---|
2016-05-01 12:00:00.0000000 | 20056275 |
2016-05-02 00:00:00.0000000 | 38797623 |
2016-05-02 12:00:00.0000000 | 39316056 |
2016-05-03 00:00:00.0000000 | 13685621 |
Para bin la marca de tiempo de 1d
:
PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 1d)
| project Timestamp , dcount_hll(merged_hll)
Salida
Marca de tiempo | dcount_hll_merged_hll |
---|---|
2016-05-01 00:00:00.0000000 | 20056275 |
2016-05-02 00:00:00.0000000 | 64135183 |
2016-05-03 00:00:00.0000000 | 13685621 |
La misma consulta se puede realizar en los valores de tdigest
, que representan en BytesDelivered
cada hora:
PageViewsHllTDigest
| summarize merged_tdigests = merge_tdigest(tdigestBytesDel) by bin(Timestamp, 12h)
| project Timestamp , percentile_tdigest(merged_tdigests, 95, typeof(long))
Salida
Marca de tiempo | percentile_tdigest_merged_tdigests |
---|---|
2016-05-01 12:00:00.0000000 | 170200 |
2016-05-02 00:00:00.0000000 | 152975 |
2016-05-02 12:00:00.0000000 | 181315 |
2016-05-03 00:00:00.0000000 | 146817 |
Ejemplo: Tabla temporal
Los límites de Kusto se alcanzan con conjuntos de datos demasiado grandes, en los que es necesario ejecutar consultas periódicas sobre el conjunto de datos, pero ejecutar las consultas normales para calcular percentile()
o dcount()
sobre grandes conjuntos de datos.
Para solucionar este problema, los datos recién agregados se pueden agregar a una tabla temporal como hll
o tdigest
valores que usan hll()
cuando la operación necesaria es dcount
o tdigest()
cuando la operación necesaria es percentil mediante set/append
o update policy
. En este caso, los resultados intermedios de o tdigest
se guardan en otro conjunto de dcount
datos, que debe ser menor que el de destino grande.
Para solucionar este problema, los datos recién agregados se pueden agregar a una tabla temporal como hll
valores o tdigest
utilizando hll()
cuando la operación necesaria es dcount
. En este caso, los resultados intermedios de se guardan en otro conjunto de dcount
datos, que debe ser menor que el de destino grande.
Cuando necesite obtener los resultados finales de estos valores, las consultas pueden usar hll
/tdigest
fusiones: . hll-merge()
/tdigest_merge()
A continuación, después de obtener los valores combinados, percentile_tdigest()
/ dcount_hll()
se puede invocar en estos valores combinados para obtener el resultado final de dcount
o percentiles.
Suponiendo que hay una tabla, PageViews, en la que los datos se ingieren diariamente, todos los días en los que desea calcular el recuento distinto de páginas vistas por minuto más tarde que datetime(2016-05-01 18:00:00.00000000).
Ejecute la siguiente consulta:
PageViews
| where Timestamp > datetime(2016-05-01 18:00:00.0000000)
| summarize percentile(BytesDelivered, 90), dcount(Page,2) by bin(Timestamp, 1d)
Salida
Marca de tiempo | percentile_BytesDelivered_90 | dcount_Page |
---|---|---|
2016-05-01 00:00:00.0000000 | 83634 | 20056275 |
2016-05-02 00:00:00.0000000 | 82770 | 64135183 |
2016-05-03 00:00:00.0000000 | 72920 | 13685621 |
Esta consulta agrega todos los valores cada vez que ejecuta esta consulta (por ejemplo, si desea ejecutarla muchas veces al día).
Si guarda los hll
valores y tdigest
(que son los resultados intermedios de dcount
y percentil) en una tabla temporal, , con una directiva de actualización o comandos set/append, solo puede combinar los valores y, a continuación, PageViewsHllTDigest
usar dcount_hll
/percentile_tdigest
con la consulta siguiente:
PageViewsHllTDigest
| summarize percentile_tdigest(merge_tdigest(tdigestBytesDel), 90), dcount_hll(hll_merge(hllPage)) by bin(Timestamp, 1d)
Salida
Marca de tiempo | percentile_tdigest_merge_tdigests_tdigestBytesDel |
dcount_hll_hll_merge_hllPage |
---|---|---|
2016-05-01 00:00:00.0000000 | 84,224 | 20056275 |
2016-05-02 00:00:00.0000000 | 83486 | 64135183 |
2016-05-03 00:00:00.0000000 | 72247 | 13685621 |
Esta consulta debe ser más eficaz, ya que se ejecuta en una tabla más pequeña. En este ejemplo, la primera consulta se ejecuta en ~215M, mientras que la segunda se ejecuta en solo 32 registros:
Ejemplo: Resultados intermedios
Consulta de retención. Supongamos que tiene una tabla que resume cuándo se ha visto cada página de Wikipedia (el tamaño de la muestra es de 10 M) y desea encontrar para cada fecha1 fecha2 el porcentaje de páginas revisadas en fecha1 y fecha2 con respecto a las páginas vistas en fecha1 (fecha1 < fecha2).
La manera trivial usa operadores de combinación y resumen:
// Get the total pages viewed each day
let totalPagesPerDay = PageViewsSample
| summarize by Page, Day = startofday(Timestamp)
| summarize count() by Day;
// Join the table to itself to get a grid where
// each row shows foreach page1, in which two dates
// it was viewed.
// Then count the pages between each two dates to
// get how many pages were viewed between date1 and date2.
PageViewsSample
| summarize by Page, Day1 = startofday(Timestamp)
| join kind = inner
(
PageViewsSample
| summarize by Page, Day2 = startofday(Timestamp)
)
on Page
| where Day2 > Day1
| summarize count() by Day1, Day2
| join kind = inner
totalPagesPerDay
on $left.Day1 == $right.Day
| project Day1, Day2, Percentage = count_*100.0/count_1
Salida
Día 1 | Día 2 | Porcentaje |
---|---|---|
2016-05-01 00:00:00.0000000 | 2016-05-02 00:00:00.0000000 | 34,0645725975255 |
2016-05-01 00:00:00.0000000 | 2016-05-03 00:00:00.0000000 | 16,618368960101 |
2016-05-02 00:00:00.0000000 | 2016-05-03 00:00:00.0000000 | 14,6291376489636 |
La consulta anterior tardó aproximadamente 18 segundos.
Cuando se usan las hll()
funciones , hll_merge()
y dcount_hll()
, la consulta equivalente finalizará después de ~1,3 segundos y mostrará que las hll
funciones aceleran la consulta por encima de ~14 veces:
let Stats=PageViewsSample | summarize pagehll=hll(Page, 2) by day=startofday(Timestamp); // saving the hll values (intermediate results of the dcount values)
let day0=toscalar(Stats | summarize min(day)); // finding the min date over all dates.
let dayn=toscalar(Stats | summarize max(day)); // finding the max date over all dates.
let daycount=tolong((dayn-day0)/1d); // finding the range between max and min
Stats
| project idx=tolong((day-day0)/1d), day, pagehll
| mv-expand pidx=range(0, daycount) to typeof(long)
// Extend the column to get the dcount value from hll'ed values for each date (same as totalPagesPerDay from the above query)
| extend key1=iff(idx < pidx, idx, pidx), key2=iff(idx < pidx, pidx, idx), pages=dcount_hll(pagehll)
// For each two dates, merge the hll'ed values to get the total dcount over each two dates,
// This helps to get the pages viewed in both date1 and date2 (see the description below about the intersection_size)
| summarize (day1, pages1)=arg_min(day, pages), (day2, pages2)=arg_max(day, pages), union_size=dcount_hll(hll_merge(pagehll)) by key1, key2
| where day2 > day1
// To get pages viewed in date1 and also date2, look at the merged dcount of date1 and date2, subtract it from pages of date1 + pages on date2.
| project pages1, day1,day2, intersection_size=(pages1 + pages2 - union_size)
| project day1, day2, Percentage = intersection_size*100.0 / pages1
Salida
day1 | day2 | Porcentaje |
---|---|---|
2016-05-01 00:00:00.0000000 | 2016-05-02 00:00:00.0000000 | 33.2298494510578 |
2016-05-01 00:00:00.0000000 | 2016-05-03 00:00:00.0000000 | 16.9773830213667 |
2016-05-02 00:00:00.0000000 | 2016-05-03 00:00:00.0000000 | 14.5160020350006 |
Nota:
Los resultados de las consultas no son 100% precisos debido al error de las hll
funciones. Para obtener más información sobre los errores, vea dcount()
.