Uso di hll() e tdigest()Using hll() and tdigest()

Si supponga di voler calcolare il numero di utenti distinti ogni giorno negli ultimi sette giorni.Suppose you want to calculate the count of distinct users every day over the last seven days. È possibile eseguire una summarize dcount(user) volta al giorno con un intervallo filtrato negli ultimi sette giorni.You can run summarize dcount(user) once a day with a span filtered to the last seven days. Questo metodo è inefficiente, perché ogni volta che viene eseguito il calcolo, si verifica una sovrapposizione di sei giorni con il calcolo precedente.This method is inefficient, because each time the calculation is run, there's a six-day overlap with the previous calculation. È anche possibile calcolare un'aggregazione per ogni giorno, quindi combinare le aggregazioni.You can also calculate an aggregate for each day, and then combine these aggregates. Questo metodo richiede di "ricordare" gli ultimi sei risultati, ma è molto più efficiente.This method requires you to "remember" the last six results, but it's much more efficient.

Il partizionamento delle query come descritto è facile per le aggregazioni semplici, ad esempio count() e sum() .Partitioning queries as described is easy for simple aggregates, such as count() and sum(). Può essere utile anche per le aggregazioni complesse, ad esempio dcount() e percentiles() .It can also be useful for complex aggregates, such as dcount() and percentiles(). In questo argomento viene illustrato il modo in cui kusto supporta questi calcoli.This topic explains how Kusto supports such calculations.

Gli esempi seguenti illustrano come usare hll / tdigest e dimostrare che l'uso di questi comandi è molto efficiente in alcuni scenari:The following examples show how to use hll/tdigest and demonstrate that using these commands is highly performant in some scenarios:

Nota

In alcuni casi, gli oggetti dinamici generati dalle hll tdigest funzioni di aggregazione o possono essere di grandi dimensioni e superare la proprietà MaxValueSize predefinita nei criteri di codifica.In some cases, the dynamic objects generated by the hll or the tdigest aggregate functions may be big and exceed the default MaxValueSize property in the encoding policy. In tal caso, l'oggetto verrà inserito come null.If so, the object will be ingested as null. Ad esempio, quando si rende permanente l'output della hll funzione con il livello di accuratezza 4, le dimensioni dell' hll oggetto superano il valore predefinito di MaxValueSize, che è 1 MB.For example, when persisting the output of hll function with accuracy level 4, the size of the hll object exceeds the default MaxValueSize, which is 1MB. Per evitare questo problema, modificare i criteri di codifica della colonna come illustrato negli esempi seguenti.To avoid this issue, modify the encoding policy of the column as shown in the following examples.

range x from 1 to 1000000 step 1
| summarize hll(x,4)
| project sizeInMb = estimate_data_size(hll_x) / pow(1024,2)
sizeInMbsizeInMb
1,00005245208741.0000524520874

L'inserimento di questo oggetto in una tabella prima dell'applicazione di questo tipo di criteri comporterà l'inserimento di valori null:Ingesting this object into a table before applying this kind of policy will ingest null:

.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)
MyTable
| project isempty(hll_x)
Colonna1Column1
11

Per evitare l'inserimento di valori null, utilizzare il tipo di criteri di codifica speciale bigobject , che sostituisce MaxValueSize a 2 MB come il seguente:To avoid ingesting null, use the special encoding policy type bigobject, which overrides the MaxValueSize to 2 MB like this:

.alter column MyTable.hll_x policy encoding type='bigobject'

Inserimento di un valore ora nella stessa tabella precedente:Ingesting a value now to the same table above:

.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)

inserisce il secondo valore correttamente:ingests the second value successfully:

MyTable
| project isempty(hll_x)
Colonna1Column1
11
00

EsempioExample

È presente una tabella, PageViewsHllTDigest , che contiene hll i valori delle pagine visualizzate ogni ora.There is a table, PageViewsHllTDigest, containing hll values of Pages viewed in each hour. Si desidera che questi valori vengano suddivisi in contenitori 12h .You want these values binned to 12h. Unire i hll valori usando la hll_merge() funzione di aggregazione, con il timestamp suddiviso in contenitori 12h .Merge the hll values using the hll_merge() aggregate function, with the timestamp binned to 12h. Usare la funzione dcount_hll per restituire il dcount valore finale:Use the function dcount_hll to return the final dcount value:

PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 12h)
| project Timestamp , dcount_hll(merged_hll)
TimestampTimestamp dcount_hll_merged_hll
2016-05-01 12:00:00.00000002016-05-01 12:00:00.0000000 2005627520056275
2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 3879762338797623
2016-05-02 12:00:00.00000002016-05-02 12:00:00.0000000 3931605639316056
2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 1368562113685621

Per eseguire il contenitore timestamp per 1d :To bin timestamp for 1d:

PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 1d)
| project Timestamp , dcount_hll(merged_hll)
TimestampTimestamp dcount_hll_merged_hll
2016-05-01 00:00:00.00000002016-05-01 00:00:00.0000000 2005627520056275
2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 6413518364135183
2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 1368562113685621

La stessa query può essere eseguita sui valori di tdigest , che rappresentano BytesDelivered in ogni ora:The same query may be done over the values of tdigest, which represent the BytesDelivered in each hour:

PageViewsHllTDigest
| summarize merged_tdigests = merge_tdigests(tdigestBytesDel) by bin(Timestamp, 12h)
| project Timestamp , percentile_tdigest(merged_tdigests, 95, typeof(long))
TimestampTimestamp percentile_tdigest_merged_tdigests
2016-05-01 12:00:00.00000002016-05-01 12:00:00.0000000 170200170200
2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 152975152975
2016-05-02 12:00:00.00000002016-05-02 12:00:00.0000000 181315181315
2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 146817146817

EsempioExample

I limiti di Kusto vengono raggiunti con set di dati troppo grandi, in cui è necessario eseguire query periodiche sul set di dati, ma eseguire le query regolari per calcolare percentile() o su set di dati di dcount() grandi dimensioni.Kusto limits are reached with datasets that are too large, where you need to run periodic queries over the dataset, but run the regular queries to calculate percentile() or dcount() over large datasets.

Per risolvere questo problema, è possibile aggiungere i dati appena aggiunti a una tabella temporanea hll come tdigest valori o utilizzando hll() quando l'operazione richiesta è dcount o tdigest() quando l'operazione richiesta è percentile utilizzando set/append o update policy .To solve this problem, newly added data may be added to a temp table as hll or tdigest values using hll() when the required operation is dcount or tdigest() when the required operation is percentile using set/append or update policy. In questo caso, i risultati intermedi di dcount o tdigest vengono salvati in un altro set di dati, che deve essere minore di quello di destinazione di grandi dimensioni.In this case, the intermediate results of dcount or tdigest are saved into another dataset, which should be smaller than the target large one.

Per risolvere questo problema, è possibile aggiungere i dati appena aggiunti a una tabella temporanea hll come tdigest valori o utilizzando hll() quando l'operazione necessaria è dcount .To solve this problem, newly added data may be added to a temp table as hll or tdigest values using hll() when the required operation is dcount. In questo caso, i risultati intermedi di dcount vengono salvati in un altro set di dati, che deve essere inferiore a quello di grandi dimensioni di destinazione.In this case, the intermediate results of dcount are saved into another dataset, which should be smaller than the target large one.

Quando è necessario ottenere i risultati finali di questi valori, le query possono usare hll / tdigest fusioni: hll-merge() / tdigest_merge() .When you need to get the final results of these values, the queries may use hll/tdigest mergers: hll-merge()/tdigest_merge(). Quindi, dopo avere ottenuto i valori Uniti, percentile_tdigest() / dcount_hll() può essere richiamato su questi valori Uniti per ottenere il risultato finale di dcount o percentile.Then, after getting the merged values, percentile_tdigest() / dcount_hll() may be invoked on these merged values to get the final result of dcount or percentiles.

Supponendo che esista una tabella, le pagine di visualizzazione, in cui i dati vengono inseriti quotidianamente, ogni giorno in cui si desidera calcolare il conteggio distinto di pagine visualizzate al minuto successive a Date = DateTime (2016-05-01 18:00:00.0000000).Assuming there's a table, PageViews, into which data is ingested daily, every day on which you want to calculate the distinct count of pages viewed per minute later than date = datetime(2016-05-01 18:00:00.0000000).

Eseguire la query riportata di seguito:Run the following query:

PageViews   
| where Timestamp > datetime(2016-05-01 18:00:00.0000000)
| summarize percentile(BytesDelivered, 90), dcount(Page,2) by bin(Timestamp, 1d)
TimestampTimestamp percentile_BytesDelivered_90percentile_BytesDelivered_90 dcount_Pagedcount_Page
2016-05-01 00:00:00.00000002016-05-01 00:00:00.0000000 8363483634 2005627520056275
2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 8277082770 6413518364135183
2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 7292072920 1368562113685621

Questa query consente di aggregare tutti i valori ogni volta che si esegue la query, ad esempio se si desidera eseguirla molte volte al giorno.This query will aggregate all the values every time you run this query (for example, if you want to run it many times a day).

Se si salvano hll i tdigest valori e (ovvero i risultati intermedi di dcount e percentile) in una tabella temporanea, PageViewsHllTDigest , utilizzando un criterio di aggiornamento o i comandi set/Append, è possibile unire i valori solo dcount_hll / percentile_tdigest utilizzando la query seguente:If you save the hll and tdigest values (which are the intermediate results of dcount and percentile) into a temp table, PageViewsHllTDigest, using an update policy or set/append commands, you may only merge the values and then use dcount_hll/percentile_tdigest using the following query:

PageViewsHllTDigest
| summarize  percentile_tdigest(merge_tdigests(tdigestBytesDel), 90), dcount_hll(hll_merge(hllPage)) by bin(Timestamp, 1d)
TimestampTimestamp percentile_tdigest_merge_tdigests_tdigestBytesDel dcount_hll_hll_merge_hllPage
2016-05-01 00:00:00.00000002016-05-01 00:00:00.0000000 8422484224 2005627520056275
2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 8348683486 6413518364135183
2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 7224772247 1368562113685621

Questa query dovrebbe essere più efficiente, in quanto viene eseguita su una tabella più piccola.This query should be more performant, as it runs over a smaller table. In questo esempio, la prima query viene eseguita su un record di ~ 215M, mentre il secondo viene eseguito solo su 32 record:In this example, the first query runs over ~215M records, while the second one runs over just 32 records:

EsempioExample

Query di conservazione.The Retention Query. Si supponga di disporre di una tabella che riepiloga quando è stata visualizzata ogni pagina di Wikipedia (le dimensioni del campione sono 10M) e si desidera trovare per ogni date1 date2 la percentuale di pagine esaminate in date1 e Date2 rispetto alle pagine visualizzate in date1 (date1 < date2).Assume you have a table that summarizes when each Wikipedia page was viewed (sample size is 10M), and you want to find for each date1 date2 the percentage of pages reviewed in both date1 and date2 relative to the pages viewed on date1 (date1 < date2).

Il modo più semplice consiste nell'usare gli operatori join e riepilogatore:The trivial way uses join and summarize operators:

// 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
Giorno 1Day1 Giorno 2Day2 PercentualePercentage
2016-05-01 00:00:00.00000002016-05-01 00:00:00.0000000 2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 34.064572597525534.0645725975255
2016-05-01 00:00:00.00000002016-05-01 00:00:00.0000000 2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 16.61836896010116.618368960101
2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 14.629137648963614.6291376489636

La query precedente ha richiesto circa 18 secondi.The above query took ~18 seconds.

Quando si usano le hll() hll_merge() funzioni, e dcount_hll() , la query equivalente termina dopo ~ 1,3 secondi e indica che le hll funzioni accelerano la query precedente di ~ 14 volte:When you use the hll(), hll_merge(), and dcount_hll() functions, the equivalent query will end after ~1.3 seconds and show that the hll functions speeds up the query above by ~14 times:

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
day1day1 Day2day2 PercentualePercentage
2016-05-01 00:00:00.00000002016-05-01 00:00:00.0000000 2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 33.229849451057833.2298494510578
2016-05-01 00:00:00.00000002016-05-01 00:00:00.0000000 2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 16.977383021366716.9773830213667
2016-05-02 00:00:00.00000002016-05-02 00:00:00.0000000 2016-05-03 00:00:00.00000002016-05-03 00:00:00.0000000 14.516002035000614.5160020350006

Nota

I risultati delle query non sono accurati al 100% a causa dell'errore delle hll funzioni.The results of the queries are not 100% accurate due to the error of the hll functions. Per ulteriori informazioni sugli errori, vedere dcount() .For more information about the errors, see dcount().