Udostępnij przez


Korzystanie z elementów hll() i tdigest()

Dotyczy: ✅Microsoft Fabric✅Azure Data ExplorerAzure MonitorMicrosoft Sentinel

Załóżmy, że chcesz obliczyć liczbę unikatowych użytkowników każdego dnia w ciągu ostatnich siedmiu dni. Można uruchomić summarize dcount(user) raz dziennie z zakresem filtrowany do ostatnich siedmiu dni. Ta metoda jest nieefektywna, ponieważ za każdym razem, gdy obliczanie jest uruchamiane, istnieje sześć dni nakładających się na poprzednie obliczenie. Można również obliczyć agregację dla każdego dnia, a następnie połączyć te agregacje. Ta metoda wymaga "zapamiętania" ostatnich sześciu wyników, ale jest o wiele bardziej wydajna.

Partycjonowanie zapytań zgodnie z opisem jest łatwe w przypadku prostych agregacji, takich jak count() i sum(). Może być również przydatny w przypadku złożonych agregacji, takich jak dcount() i percentiles(). W tym artykule wyjaśniono, jak usługa Kusto obsługuje takie obliczenia.

W poniższych przykładach pokazano, jak używać hll/tdigest i demonstrować, że użycie tych poleceń jest wysoce wydajne w niektórych scenariuszach:

Ważne

Wyniki hll, tdigesthll_ifhll_mergei tdigest_merge są obiektami typudynamic, które mogą być następnie przetwarzane przez inne funkcje (dcount_hll, percentile_tdigest, percentiles_array_tdigest, i ).percentrank_tdigest Kodowanie tego obiektu może ulec zmianie w czasie (na przykład z powodu uaktualnienia oprogramowania); jednak takie zmiany zostaną wprowadzone w sposób zgodny z poprzednimi wersjami, dzięki czemu można trwale przechowywać takie wartości i odwoływać się do nich w zapytaniach niezawodnie.

Uwaga

W niektórych przypadkach obiekty dynamiczne generowane przez hll funkcje agregujące lub tdigest mogą być duże i przekraczają domyślną właściwość MaxValueSize w zasadach kodowania. Jeśli tak, obiekt zostanie pozyskany jako null. Na przykład w przypadku utrwalania danych wyjściowych hll funkcji o poziomie dokładności 4 rozmiar hll obiektu przekracza wartość domyślną MaxValueSize, czyli 1 MB. Aby uniknąć tego problemu, zmodyfikuj zasady kodowania kolumny, jak pokazano w poniższych przykładach.

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

Wyjście

sizeInMb
1.0000524520874

Pozyskiwanie tego obiektu do tabeli przed zastosowaniem tego rodzaju zasad spowoduje pozyskiwanie wartości null:

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

Wyjście

Column1
1

Aby uniknąć pozyskiwania wartości null, użyj specjalnego typu bigobjectzasad kodowania , który zastępuje MaxValueSize wartość do 2 MB w następujący sposób:

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

Pozyskiwanie wartości teraz do tej samej tabeli powyżej:

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

Pozyskuje drugą wartość pomyślnie:

MyTable
| project isempty(hll_x)

Wyjście

Column1
1
0

Przykład: liczba z binned sygnaturą czasowa

Istnieje tabela zawierająca PageViewsHllTDigesthll wartości stron wyświetlanych w każdej godzinie. Te wartości mają być binned do 12h. hll Scal wartości przy użyciu funkcji agregującej z sygnaturą hll_merge() czasową binned na 12h. Użyj funkcji dcount_hll , aby zwrócić wartość końcową dcount :

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

Wyjście

Sygnatura czasowa 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

Aby bin timestamp for 1d:

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

Wyjście

Sygnatura czasowa 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

To samo zapytanie można wykonać względem wartości tdigest, które reprezentują BytesDelivered wartość w każdej godzinie:

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

Wyjście

Sygnatura czasowa 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

Przykład: tabela tymczasowa

Limity usługi Kusto są osiągane w przypadku zestawów danych, które są zbyt duże, gdzie należy uruchamiać okresowe zapytania w zestawie danych, ale uruchamiać regularne zapytania, aby obliczyć percentile() lub dcount() za pośrednictwem dużych zestawów danych.

Aby rozwiązać ten problem, nowo dodane dane mogą zostać dodane do tabeli tymczasowej jako hll lub wartości używanehll(), gdy wymagana operacja jest dcount lub tdigest() gdy wymagana operacja jest percentylem przy użyciu set/append lub update policytdigest . W takim przypadku wyniki dcount pośrednie lub tdigest są zapisywane w innym zestawie danych, który powinien być mniejszy niż docelowy duży.

Aby rozwiązać ten problem, nowo dodane dane mogą zostać dodane do tabeli tymczasowej jako hll lub wartości używanehll(), gdy wymagana operacja to dcounttdigest . W takim przypadku wyniki dcount pośrednie są zapisywane w innym zestawie danych, który powinien być mniejszy niż docelowy duży.

Jeśli musisz uzyskać końcowe wyniki tych wartości, zapytania mogą używać hll/tdigest fuzji: . hll-merge()/tdigest_merge() Następnie po pobraniu scalonych wartości może zostać wywołana na tych scalonych wartościach, percentile_tdigest() / dcount_hll() aby uzyskać końcowy wynik dcount lub percentylów.

Zakładając, że istnieje tabela, PageViews, do której dane są pozyskiwane codziennie, każdego dnia, w którym chcesz obliczyć odrębną liczbę stron wyświetlanych na minutę później niż data = datetime(2016-05-01 18:00:00.0000000).

Uruchom poniższe zapytanie:

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

Wyjście

Sygnatura czasowa 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

To zapytanie agreguje wszystkie wartości za każdym razem, gdy uruchamiasz to zapytanie (na przykład jeśli chcesz uruchomić je wiele razy dziennie).

Jeśli zapiszesz hll wartości i tdigest (które są pośrednimi wynikami dcount i percentylem) w tabeli tymczasowej, PageViewsHllTDigestprzy użyciu zasad aktualizacji lub zestaw/dołączanie poleceń, możesz scalić tylko wartości, a następnie użyć dcount_hll/percentile_tdigest następującego zapytania:

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

Wyjście

Sygnatura czasowa 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

To zapytanie powinno być bardziej wydajne, ponieważ jest uruchamiane w mniejszej tabeli. W tym przykładzie pierwsze zapytanie jest uruchamiane na rekordach ok. 215 mln, podczas gdy drugi jest uruchamiany w ciągu zaledwie 32 rekordów:

Przykład: Wyniki pośrednie

Zapytanie przechowywania. Załóżmy, że masz tabelę podsumowującą, kiedy każda strona Wikipedii została wyświetlona (rozmiar próbki to 10 M), a chcesz znaleźć dla każdej daty1 daty2 procent stron przeglądanych zarówno w kolumnie date1, jak i date2 względem stron wyświetlanych w dniu 1 (data1 data1 < ).

Trywialny sposób używa operatorów sprzężenia i podsumowania:

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

Wyjście

Dzień1 Dzień2 Procent
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

Powyższe zapytanie trwało ok. 18 sekund.

Jeśli używasz hll()funkcji , hll_merge()i dcount_hll() , równoważne zapytanie zakończy się po ok. 1,3 sekundy i pokaże, że hll funkcje przyspieszają powyższe zapytanie o ~14 razy:

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

Wyjście

dzień1 dzień2 Procent
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

Uwaga

Wyniki zapytań nie są dokładne w 100% z powodu błędu hll funkcji. Aby uzyskać więcej informacji na temat błędów, zobacz dcount().