Verwenden von „hll()“ und „tdigest()“
Gilt für: ✅Microsoft Fabric✅Azure Data Explorer✅Azure Monitor✅Microsoft Sentinel
Angenommen, Sie möchten die Anzahl der eindeutigen Benutzer jeden Tag in den letzten sieben Tagen berechnen. Sie können einmal pro Tag mit einer Spanne nach den letzten sieben Tagen ausgeführt summarize dcount(user)
werden. Diese Methode ist ineffizient, da jedes Mal, wenn die Berechnung ausgeführt wird, eine Sechs-Tage-Überlappung mit der vorherigen Berechnung besteht. Sie können auch ein Aggregat für jeden Tag berechnen und diese Aggregate dann kombinieren. Diese Methode erfordert, dass Sie sich die letzten sechs Ergebnisse merken, aber es ist viel effizienter.
Partitionierungsabfragen wie beschrieben sind für einfache Aggregate wie count()
z. B. und sum()
. Es kann auch für komplexe Aggregate nützlich sein, z dcount()
. B. und percentiles()
. In diesem Artikel wird erläutert, wie Kusto solche Berechnungen unterstützt.
In den folgenden Beispielen wird gezeigt, wie Sie diese Befehle verwenden hll
/tdigest
und demonstrieren können, die in einigen Szenarien sehr leistungsfähig sind:
Wichtig
Die Ergebnisse von hll
, hll_if
, hll_merge
, tdigest
und tdigest_merge
sind Objekte vom Typdynamic
, die dann von anderen Funktionen verarbeitet werden können (dcount_hll
, percentile_tdigest
, und percentiles_array_tdigest
percentrank_tdigest
). Die Codierung dieses Objekts kann sich im Laufe der Zeit ändern (z. B. aufgrund eines Softwareupgrades); Solche Änderungen erfolgen jedoch abwärtskompatibel, sodass man solche Werte dauerhaft speichern und zuverlässig in Abfragen referenzieren kann.
Hinweis
In einigen Fällen können die dynamischen Objekte, die von den hll
tdigest
Aggregatfunktionen generiert werden, groß sein und die Standardmäßige MaxValueSize-Eigenschaft in der Codierungsrichtlinie überschreiten. Wenn ja, wird das Objekt als NULL aufgenommen.
Wenn sie beispielsweise die Ausgabe der hll
Funktion mit Genauigkeitsebene 4 beibehalten, überschreitet die Größe des hll
Objekts die MaxValueSize-Standardgröße, die 1 MB ist.
Um dieses Problem zu vermeiden, ändern Sie die Codierungsrichtlinie der Spalte, wie in den folgenden Beispielen gezeigt.
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 |
Wenn Sie dieses Objekt in eine Tabelle aufnehmen, bevor Sie diese Art von Richtlinie anwenden, wird NULL aufgenommen:
.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)
MyTable
| project isempty(hll_x)
Output
Spalte1 |
---|
1 |
Verwenden Sie den speziellen Codierungsrichtlinientyp bigobject
, der die MaxValueSize
Codierung auf 2 MB überschreibt, um null zu vermeiden:
.alter column MyTable.hll_x policy encoding type='bigobject'
Aufnehmen eines Werts jetzt zur gleichen Tabelle oben:
.set-or-append MyTable <| range x from 1 to 1000000 step 1
| summarize hll(x,4)
nimmt den zweiten Wert erfolgreich ein:
MyTable
| project isempty(hll_x)
Output
Spalte1 |
---|
1 |
0 |
Beispiel: Anzahl mit binniertem Zeitstempel
Es gibt eine Tabelle, die Werte von Seiten enthälthll
, PageViewsHllTDigest
die in jeder Stunde angezeigt werden. Sie möchten, dass diese Werte in einen Binned -Wert 12h
umgewandelt werden sollen. Führen Sie die hll
Werte mithilfe der hll_merge()
Aggregatfunktion zusammen, wobei der Zeitstempel mit dem binniert ist 12h
. Verwenden Sie die Funktion dcount_hll
, um den endgültigen dcount
Wert zurückzugeben:
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 |
Zum Bin-Zeitstempel für 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 |
Dieselbe Abfrage kann über die Werte von tdigest
, die BytesDelivered
die in jeder Stunde darstellen, durchgeführt werden:
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 |
Beispiel: Temporäre Tabelle
Kusto-Grenzwerte werden mit Zu großen Datasets erreicht, bei denen Sie regelmäßige Abfragen über das Dataset ausführen müssen, aber die regulären Abfragen ausführen, um große Datasets zu berechnen percentile()
oder dcount()
zu übersteigen.
Um dieses Problem zu lösen, können neu hinzugefügte Daten zu einer temporären Tabelle als oder Werte hll()
hinzugefügt werden, die verwendet werden, wenn der erforderliche Vorgang oder tdigest()
dcount
der erforderliche Vorgang per Quantil verwendet set/append
oder update policy
verwendet tdigest
wird.hll
In diesem Fall werden die Zwischenergebnisse eines dcount
anderen Datasets gespeichert oder tdigest
in einem anderen Dataset gespeichert, das kleiner als das zielgroße sein sollte.
Um dieses Problem zu lösen, können neu hinzugefügte Daten zu einer temporären Tabelle als hll
oder tdigest
Werte hll()
hinzugefügt werden, die verwendet werden, wenn der erforderliche Vorgang ist dcount
. In diesem Fall werden die Zwischenergebnisse dcount
in einem anderen Dataset gespeichert, das kleiner als das zielgroße sein sollte.
Wenn Sie die endgültigen Ergebnisse dieser Werte abrufen müssen, können die Abfragen Fusionen verwendenhll
/tdigest
: . hll-merge()
/tdigest_merge()
Nach dem Abrufen der zusammengeführten Werte können diese zusammengeführten Werte aufgerufen werden, percentile_tdigest()
/ dcount_hll()
um das Endergebnis von dcount
oder Quantils zu erhalten.
Vorausgesetzt, es gibt eine Tabelle, PageViews, in die Daten täglich aufgenommen werden, jeden Tag, an dem Sie die unterschiedliche Anzahl von Seiten berechnen möchten, die pro Minute angezeigt werden als Datum = datetime(2016-05-01 18:00:00.00.000000).
Führen Sie die folgende Abfrage aus:
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 |
Diese Abfrage aggregiert alle Werte jedes Mal, wenn Sie diese Abfrage ausführen (z. B. wenn Sie sie mehrmals täglich ausführen möchten).
Wenn Sie die hll
Zwischenergebnisse und Quantilswerte dcount
in einer temporären Tabelle speichern, PageViewsHllTDigest
indem Sie eine Aktualisierungsrichtlinie verwenden oder Befehle zum Festlegen/Anfügen verwenden, können Sie nur die Werte zusammenführen und dann die folgende Abfrage verwendendcount_hll
/percentile_tdigest
:tdigest
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 | 84,224 | 20056275 |
2016-05-02 00:00:00.0000000 | 83486 | 64135183 |
2016-05-03 00:00:00.0000000 | 72247 | 13685621 |
Diese Abfrage sollte leistungsfähiger sein, da sie über eine kleinere Tabelle ausgeführt wird. In diesem Beispiel wird die erste Abfrage über ~215M-Datensätze ausgeführt, während die zweite über nur 32 Datensätze ausgeführt wird:
Beispiel: Zwischenergebnisse
Die Aufbewahrungsabfrage. Angenommen, Sie haben eine Tabelle, die zusammenfasst, wann jede Wikipedia-Seite angezeigt wurde (Beispielgröße ist 10M), und Sie möchten für jedes Datum1 Datum2 den Prozentsatz der Seiten ermitteln, die in Datum1 und Datum2 relativ zu den am Datum1 angezeigten Seiten (Datum1 < Datum2) überprüft wurden.
Die triviale Methode verwendet Verknüpfungs- und Zusammenfassungsoperatoren:
// 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
Tag1 | Tag2 | Prozentwert |
---|---|---|
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 |
Die obige Abfrage dauerte ca. 18 Sekunden.
Wenn Sie die hll()
hll_merge()
Funktionen und Funktionen dcount_hll()
verwenden, endet die entsprechende Abfrage nach ~1,3 Sekunden und zeigt, dass die hll
Funktionen die oben genannte Abfrage um ~14 Mal beschleunigen:
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
Tag1 | Tag 2 | Prozentwert |
---|---|---|
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 |
Hinweis
Die Ergebnisse der Abfragen sind aufgrund des Fehlers der hll
Funktionen nicht 100 % genau. Weitere Informationen zu den Fehlern finden Sie unter dcount()
.