Compartir a través de


Uso de hll () y tdigest ()

Se aplica a: ✅Microsoft FabricAzure Data Explorer✅Azure MonitorMicrosoft 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, tdigesty 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 bigobjectde 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, , PageViewsHllTDigestque 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, PageViewsHllTDigestusar 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().