Použití funkcí hll() a tdigest()
Platí pro: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
Předpokládejme, že chcete vypočítat počet jedinečných uživatelů každý den za posledních 7 dnů. Můžete spustit summarize dcount(user)
jednou denně s rozsahem filtrovaným na posledních 7 dnů. Tato metoda je neefektivní, protože při každém spuštění výpočtu se šestidenní překrývání s předchozím výpočtem. Můžete také vypočítat agregaci pro každý den a pak tyto agregace zkombinovat. Tato metoda vyžaduje, abyste si "vzpomněli" na posledních šest výsledků, ale je mnohem efektivnější.
Dělení dotazů, jak je popsáno, je snadné pro jednoduché agregace, například count()
a sum()
. Může být také užitečné pro komplexní agregace, například dcount()
a percentiles()
. Tento článek vysvětluje, jak Kusto podporuje takové výpočty.
Následující příklady ukazují, jak používat hll
/tdigest
a demonstrovat, že použití těchto příkazů je v některých scénářích vysoce výkonné:
Důležité
Výsledky hll
, , hll_merge
hll_if
, tdigest
a tdigest_merge
jsou objekty typudynamic
, které pak mohou být zpracovány jinými funkcemi (dcount_hll
, percentile_tdigest
, percentiles_array_tdigest
a percentrank_tdigest
). Kódování tohoto objektu se může v průběhu času změnit (například kvůli upgradu softwaru); Tyto změny se však budou provádět zpětně kompatibilním způsobem, takže je můžete trvale ukládat a odkazovat na ně v dotazech spolehlivě.
Poznámka:
V některých případech můžou být dynamické objekty generované hll
agregačními tdigest
funkcemi velké a překračují výchozí vlastnost MaxValueSize v zásadách kódování. Pokud ano, objekt se ingestuje jako null.
Například při zachování výstupu hll
funkce s přesností úrovně 4 překračuje velikost hll
objektu výchozí MaxValueSize, což je 1 MB.
Chcete-li se tomuto problému vyhnout, upravte zásady kódování sloupce, jak je znázorněno v následujících příkladech.
range x from 1 to 1000000 step 1
| summarize hll(x,4)
| project sizeInMb = estimate_data_size(hll_x) / pow(1024,2)
Výstup
sizeInMb |
---|
1.0000524520874 |
Ingestování tohoto objektu do tabulky před použitím tohoto typu zásady bude ingestovat hodnotu null:
.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)
MyTable
| project isempty(hll_x)
Výstup
Column1 |
---|
0 |
Pokud se chcete vyhnout ingestování hodnoty null, použijte speciální typ bigobject
zásad kódování, který přepíše MaxValueSize
hodnotu 2 MB takto:
.alter column MyTable.hll_x policy encoding type='bigobject'
Ingestování hodnoty teď do stejné tabulky výše:
.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)
ingestuje druhou hodnotu úspěšně:
MyTable
| project isempty(hll_x)
Výstup
Column1 |
---|
0 |
0 |
Příklad: Count with binned timestamp
Existuje tabulka, PageViewsHllTDigest
která obsahuje hll
hodnoty stránek zobrazených v každé hodině. Chcete, aby 12h
tyto hodnoty byly přihrádky . Sloučí hll
hodnoty pomocí hll_merge()
agregační funkce s časovým razítkem v 12h
intervalu . dcount_hll
Funkce slouží k vrácení konečné dcount
hodnoty:
PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 12h)
| project Timestamp , dcount_hll(merged_hll)
Výstup
Časové razítko | 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 |
Časové razítko přihrádky intervalu pro 1d
:
PageViewsHllTDigest
| summarize merged_hll = hll_merge(hllPage) by bin(Timestamp, 1d)
| project Timestamp , dcount_hll(merged_hll)
Výstup
Časové razítko | 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 |
Stejný dotaz může být proveden v hodnotách tdigest
, které představují BytesDelivered
za každou hodinu:
PageViewsHllTDigest
| summarize merged_tdigests = merge_tdigest(tdigestBytesDel) by bin(Timestamp, 12h)
| project Timestamp , percentile_tdigest(merged_tdigests, 95, typeof(long))
Výstup
Časové razítko | 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 |
Příklad: Dočasná tabulka
Limity Kusto jsou dosaženy u datových sad, které jsou příliš velké, kde potřebujete spouštět pravidelné dotazy na datovou sadu, ale spouštět běžné dotazy pro výpočet percentile()
nebo dcount()
nad velkými datovými sadami.
Chcete-li tento problém vyřešit, mohou být nově přidaná data přidána do dočasné tabulky jako hll
nebo hodnoty pomocíhll()
, pokud je dcount
požadovaná operace nebo tdigest()
pokud je požadovaná operace percentil pomocí set/append
nebo update policy
tdigest
. V tomto případě se přechodné výsledky dcount
nebo tdigest
uloží do jiné datové sady, které by měly být menší než cílové velké.
Chcete-li tento problém vyřešit, mohou být nově přidaná data přidána do dočasné tabulky jako hll
nebo hodnoty pomocíhll()
, pokud je dcount
požadovaná tdigest
operace . V tomto případě se přechodné výsledky dcount
uloží do jiné datové sady, která by měla být menší než cílová velká.
Pokud potřebujete získat konečné výsledky těchto hodnot, mohou dotazy použít hll
/tdigest
fúze: . hll-merge()
/tdigest_merge()
Po získání sloučených hodnot percentile_tdigest()
/ dcount_hll()
je pak možné u těchto sloučených hodnot vyvolat výsledek konečného výsledku dcount
nebo percentilů.
Za předpokladu, že existuje tabulka PageViews, do které se data ingestují denně, každý den, kdy chcete vypočítat jedinečný počet stránek zobrazených za minutu než datum = datetime(2016-05-01 18:00:00,00,000000).
Spusťte tento dotaz:
PageViews
| where Timestamp > datetime(2016-05-01 18:00:00.0000000)
| summarize percentile(BytesDelivered, 90), dcount(Page,2) by bin(Timestamp, 1d)
Výstup
Časové razítko | 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 |
Tento dotaz agreguje všechny hodnoty při každém spuštění tohoto dotazu (například pokud ho chcete spustit mnohokrát denně).
Pokud uložíte hll
hodnoty a tdigest
hodnoty (což jsou přechodné výsledky dcount
a percentil) do dočasné tabulky, PageViewsHllTDigest
pomocí aktualizačních zásad nebo příkazů set/append, můžete sloučit pouze hodnoty a pak použít dcount_hll
/percentile_tdigest
následující dotaz:
PageViewsHllTDigest
| summarize percentile_tdigest(merge_tdigest(tdigestBytesDel), 90), dcount_hll(hll_merge(hllPage)) by bin(Timestamp, 1d)
Výstup
Časové razítko | 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 |
Tento dotaz by měl být výkonnější, protože běží přes menší tabulku. V tomto příkladu první dotaz běží přes přibližně 215M záznamů, zatímco druhý dotaz běží přes pouhých 32 záznamů:
Příklad: Průběžné výsledky
Dotaz uchovávání informací. Předpokládejme, že máte tabulku, která shrnuje, kdy se zobrazila každá stránka Wikipedie (velikost vzorku je 10 M) a chcete pro každé datum 1 datum2 najít procento stránek zkontrolovaných v date1 i date2 vzhledem ke stránkám zobrazeným k datu 1 (datum1 < datum2).
Triviální způsob používá operátory spojení a sumarizace:
// 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
Výstup
Den 1 | Den 2 | Procento |
---|---|---|
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 |
Výše uvedený dotaz trval přibližně 18 sekund.
Když použijete funkci hll()
, hll_merge()
a dcount_hll()
funkce, ekvivalentní dotaz skončí po ~1,3 sekundách a ukáže, že hll
funkce urychlí dotaz výše o ~14krát:
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
Výstup
den 1 | den2 | Procento |
---|---|---|
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 |
Poznámka:
Výsledky dotazů nejsou 100% přesné kvůli chybě hll
funkcí. Další informace o chybách naleznete v tématu dcount()
.