Condividi tramite


Uso di hll() e tdigest()

Si applica a: ✅Microsoft Fabric✅Azure Esplora dati Azure MonitorMicrosoft Sentinel

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 viene eseguito il calcolo, si verifica 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.

Il partizionamento delle query come descritto è semplice per le aggregazioni semplici, ad esempio count() e sum(). Può anche essere utile per aggregazioni complesse, ad esempio dcount() e percentiles(). Questo articolo illustra come Kusto supporta tali calcoli.

Gli esempi seguenti illustrano come usare hll/tdigest e dimostrare che l'uso di questi comandi è estremamente efficiente in alcuni scenari:

Importante

I risultati di hll, hll_ifhll_merge, tdigest, e tdigest_merge sono oggetti di tipo dynamic che possono quindi essere elaborati da altre funzioni (dcount_hll, percentile_tdigest, percentiles_array_tdigeste 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 che sia possibile archiviare tali valori in modo permanente e farvi riferimento in modo affidabile nelle query.

Nota

In alcuni casi, gli oggetti dinamici generati dalle hll funzioni di aggregazione o tdigest 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 rende persistente l'output della hll funzione con livello di accuratezza 4, le dimensioni dell'oggetto hll superano il valore predefinito 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 dell'applicazione di questo tipo di criteri ingestirà null:

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

Output

Colonna1
1

Per evitare l'inserimento di valori Null, usare il tipo di criterio di bigobjectcodifica speciale , che esegue l'override di MaxValueSize su 2 MB come segue:

.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

Colonna1
1
0

Esempio: Conteggio con timestamp binned

È presente una tabella, PageViewsHllTDigest, contenente 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 binned in 12h. Usare 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 binare il 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

È possibile eseguire la stessa query 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 Kusto vengono raggiunti con set di dati troppo grandi, in cui è necessario eseguire query periodiche sul set di dati, ma eseguire le normali query 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 valori o tdigest usando hll() quando l'operazione richiesta è dcount o tdigest() quando l'operazione richiesta è percentile usando set/append o update policy. 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 richiesta è 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 percentili.

Supponendo che sia presente una tabella, PageViews, in cui i dati vengono inseriti ogni giorno, ogni giorno in cui si desidera calcolare il numero distinto di pagine visualizzate al minuto dopo date = datetime(2016-05-01 18:00:00.00.0000000).

Eseguire la query riportata di seguito:

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 la query, ad esempio se si vuole eseguirla più volte al giorno.

Se si salvano i hll valori e tdigest (ovvero i risultati intermedi di dcount e percentile) in una tabella temporanea, , PageViewsHllTDigestusando un criterio di aggiornamento o i comandi set/append, è 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, perché viene eseguita su una tabella più piccola. In questo esempio la prima query viene eseguita su ~215M record, mentre la seconda viene eseguita su soli 32 record:

Esempio: Risultati intermedi

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

Il modo semplice usa operatori join e summarize:

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

Giorno1 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 terminerà dopo circa 1,3 secondi e mostrerà che le hll funzioni accelerano la query precedente di circa 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

day1 day2 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 al 100% a causa dell'errore delle hll funzioni. Per altre informazioni sugli errori, vedere dcount().