Uso di hll() e tdigest()

Si supponga di voler calcolare il numero di utenti distinti ogni giorno negli ultimi sette giorni. È possibile eseguire summarize dcount(user) una volta al giorno con un intervallo filtrato negli ultimi sette giorni. Questo metodo è inefficiente, perché ogni volta che il calcolo viene eseguito, è presente una sovrapposizione di sei giorni con il calcolo precedente. È anche possibile calcolare un'aggregazione per ogni giorno e quindi combinare queste aggregazioni. Questo metodo richiede di "ricordare" gli ultimi sei risultati, ma è molto più efficiente.

Le query di partizionamento come descritto sono facili per semplici aggregazioni, ad esempio count() e sum(). Può anche essere utile per aggregazioni complesse, ad esempio dcount() e percentiles(). Questo articolo illustra come Kusto supporti tali calcoli.

Negli esempi seguenti viene illustrato come usare e dimostrare che l'uso hll/tdigest di questi comandi è altamente efficiente in alcuni scenari:

Importante

I risultati di hll, hll_if, hll_mergetdigest, e tdigest_merge sono oggetti di tipo dynamic che possono quindi essere elaborati da altre funzioni (dcount_hll, percentile_tdigestpercentiles_array_tdigest, e percentrank_tdigest). La codifica di questo oggetto potrebbe cambiare nel tempo (ad esempio, a causa di un aggiornamento software); Tuttavia, tali modifiche verranno eseguite in modo compatibile con le versioni precedenti, in modo da poter archiviare tali valori in modo permanente e farvi riferimento nelle query in modo affidabile.

Nota

In alcuni casi, gli oggetti dinamici generati dalle hlltdigest funzioni di aggregazione possono essere grandi e superare la proprietà MaxValueSize predefinita nei criteri di codifica. In tal caso, l'oggetto verrà inserito come Null. Ad esempio, quando si mantiene l'output della hll funzione con accuratezza livello 4, le dimensioni dell'oggetto hll superano il valore predefinito di MaxValueSize, ovvero 1 MB. Per evitare questo problema, modificare i criteri di codifica della colonna, come illustrato negli esempi seguenti.

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

Output

sizeInMb
1.0000524520874

L'inserimento di questo oggetto in una tabella prima di applicare questo tipo di criterio inserisce null:

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

Output

Colonna 1
1

Per evitare l'inserimento di null, usare il tipo di bigobjectcriterio di codifica speciale , che esegue l'override di MaxValueSize su 2 MB come indicato di seguito:

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

Inserimento di un valore nella stessa tabella precedente:

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

inserisce correttamente il secondo valore:

MyTable
| project isempty(hll_x)

Output

Colonna 1
1
0

Esempio: Conteggio con timestamp bined

È presente una tabella, , PageViewsHllTDigestcontenente hll i valori di Pages visualizzati in ogni ora. Si desidera che questi valori vengano binati in 12h. Unire i hll valori usando la hll_merge() funzione di aggregazione, con il timestamp bined in 12h. Utilizzare la funzione dcount_hll per restituire il valore finale dcount :

PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 12h)
| project Timestamp , dcount_hll(merged_hll)

Output

Timestamp 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

Per bin timestamp per 1d:

PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 1d)
| project Timestamp , dcount_hll(merged_hll)

Output

Timestamp 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 stessa query può essere eseguita sui valori di tdigest, che rappresentano l'oggetto BytesDelivered in ogni ora:

PageViewsHllTDigest
| summarize merged_tdigests = merge_tdigest(tdigestBytesDel) by bin(Timestamp, 12h)
| project Timestamp , percentile_tdigest(merged_tdigests, 95, typeof(long))

Output

Timestamp 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

Esempio: Tabella temporanea

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 dcount() superare set di dati di grandi dimensioni.

Per risolvere questo problema, i dati appena aggiunti possono essere aggiunti a una tabella temporanea come hll o valori usando hll() quando l'operazione necessaria è o tdigest() quando l'operazione necessaria è dcount percentile usando set/append o update policytdigest . In questo caso, i risultati intermedi di o tdigest vengono salvati in un altro set di dcount dati, che deve essere inferiore a quello di destinazione di grandi dimensioni.

Per risolvere questo problema, i dati appena aggiunti possono essere aggiunti a una tabella temporanea come hll o valori usando hll() quando l'operazione necessaria è dcounttdigest . In questo caso, i risultati intermedi di vengono salvati in un altro set di dcount dati, che deve essere inferiore a quello di destinazione di grandi dimensioni.

Quando è necessario ottenere i risultati finali di questi valori, le query possono usare hll/tdigest fusioni: . hll-merge()/tdigest_merge() Quindi, dopo aver ottenuto i valori uniti, percentile_tdigest() / dcount_hll() può essere richiamato su questi valori uniti per ottenere il risultato finale di dcount o percentile.

Supponendo che sia presente una tabella, PageViews, in cui i dati vengono inseriti ogni giorno, ogni giorno in cui si vuole calcolare il numero distinto di pagine visualizzate al minuto più tardi della data = datetime(2016-05-01 18:00:00.000000000).

Eseguire la query seguente:

PageViews
| where Timestamp > datetime(2016-05-01 18:00:00.0000000)
| summarize percentile(BytesDelivered, 90), dcount(Page,2) by bin(Timestamp, 1d)

Output

Timestamp 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

Questa query aggrega tutti i valori ogni volta che si esegue questa query, ad esempio se si vuole eseguirla più volte al giorno.

Se si salvano i hll valori e (ovvero i risultati intermedi di e tdigest percentile) in una tabella temporanea, , PageViewsHllTDigestusando un criterio di dcount aggiornamento o i comandi set/accodamento, è possibile unire solo i valori e quindi usare dcount_hll/percentile_tdigest la query seguente:

PageViewsHllTDigest
| summarize  percentile_tdigest(merge_tdigest(tdigestBytesDel), 90), dcount_hll(hll_merge(hllPage)) by bin(Timestamp, 1d)

Output

Timestamp percentile_tdigest_merge_tdigests_tdigestBytesDel dcount_hll_hll_merge_hllPage
2016-05-01 00:00:00.0000000 84224 20056275
2016-05-02 00:00:00.0000000 83486 64135183
2016-05-03 00:00:00.0000000 72247 13685621

Questa query dovrebbe essere più efficiente, poiché viene eseguita su una tabella più piccola. In questo esempio la prima query viene eseguita su ~215M record, mentre la seconda esegue solo 32 record:

Esempio: Risultati intermedi

Query di conservazione. Si supponga di avere una tabella che riepiloga quando ogni pagina di Wikipedia è stata visualizzata (dimensioni di esempio è 10M) e si vuole trovare per ogni data1 data2 la percentuale di pagine esaminate in data1 e data2 relative alle pagine visualizzate in data1 (data1 < data2).

Il modo semplice usa operatori di join e riepilogo:

// 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

Output

Giorno 1 Giorno 2 Percentuale
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 query precedente ha richiesto circa 18 secondi.

Quando si usano le hll()funzioni , hll_merge()e dcount_hll() , la query equivalente termina dopo circa 1,3 secondi e mostra che le funzioni accelerano la hll query precedente per ~14 volte:

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

Output

giorno1 giorno2 Percentuale
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

I risultati delle query non sono accurati del 100% a causa dell'errore delle hll funzioni. Per altre informazioni sugli errori, vedere dcount().