von der Bucket-Grundlage bis zum Sales-Dashboard
Die date_histogram Aggregation gruppiert Dokumente in feste Zeit-Buckets und ist damit das Fundament fast jeder Zeitreihen-Auswertung in Elasticsearch und OpenSearch. Wer calendar_interval und fixed_interval verwechselt oder Zeitzonen ignoriert, bekommt Dashboards mit verschobenen Balken und falschen Tagesgrenzen, ohne dass die Query einen Fehler wirft.
Inhaltsverzeichnis
- 1. Warum die Date Histogram Aggregation für Zeitreihen unverzichtbar ist
- 2. Grundlagen: Syntax und Buckets der Date Histogram Aggregation
- 3. Calendar Intervals vs Fixed Intervals im Detail
- 4. Zeitzonen korrekt handhaben
- 5. Sub-Aggregationen: Umsatz und Kennzahlen pro Zeitraum
- 6. Lückenlose Zeitreihen: min_doc_count und extended_bounds
- 7. Performance bei großen Indizes
- 8. Sales-over-Time Dashboards in der Praxis
- 9. Typische Fehler und Debugging
- 10. Zusammenfassung
- 11. FAQ
1. Warum die Date Histogram Aggregation für Zeitreihen unverzichtbar ist
Die Date Histogram Aggregation ist die Standardlösung, wenn Dokumente in Elasticsearch nach einem Zeitfeld in gleich große Zeiträume gruppiert werden sollen. Bestellungen pro Tag, Fehlerraten pro Stunde, Sessions pro Woche: überall dort, wo eine Kennzahl über die Zeit verlaufen soll, bildet ein Date Histogram die Buckets, in die anschließend Metrik-Aggregationen wie sum, avg oder cardinality eingehängt werden. Anders als eine einfache Terms-Aggregation auf ein gerundetes Datumsfeld übernimmt die date_histogram Aggregation das Bucket-Alignment, die Kalenderlogik und die Sortierung automatisch.
Der praktische Nutzen zeigt sich vor allem in Dashboards und Reporting-Systemen, bei denen Anwender einen Zeitraum wählen und sofort eine saubere Zeitreihe sehen sollen, ohne dass Backend-Code die Bucket-Grenzen manuell berechnet. Ein Date Histogram übernimmt dabei auch Randfälle, die von Hand leicht falsch implementiert werden: unterschiedliche Monatslängen, Schaltjahre und die Umstellung von Sommer- auf Winterzeit. Wer diese Fälle ignoriert, bekommt Balkendiagramme, deren Wochenenden plötzlich verschoben sind oder deren Februar-Balken doppelt so breit wirkt wie der Januar-Balken.
Die folgenden Abschnitte zeigen die date_histogram Aggregation von der Grundsyntax über die Unterschiede zwischen calendar_interval und fixed_interval bis zum vollständigen Sales-Dashboard mit mehreren Sub-Aggregationen. Jedes Beispiel nutzt reale Query-Syntax, wie sie gegen einen produktiven Elasticsearch- oder OpenSearch-Cluster läuft.
2. Grundlagen: Syntax und Buckets der Date Histogram Aggregation
Eine minimale Date Histogram Aggregation braucht drei Angaben: das Zeitfeld über das field-Attribut, die Bucket-Größe über calendar_interval oder fixed_interval und optional ein Ausgabeformat über format. Jedes Ergebnis-Bucket enthält den Bucket-Key als Epoch-Millisekunden, ein formatiertes key_as_string und doc_count, die Anzahl der Dokumente in diesem Zeitraum. Diese Buckets sind standardmäßig chronologisch sortiert, was Zeitreihen-Diagramme ohne zusätzliche Sortierlogik direkt konsumierbar macht.
Wichtig ist der Query-Kontext: Eine date_histogram Aggregation ohne einschränkenden range-Filter aggregiert über den kompletten Index. In der Praxis kombiniert man sie deshalb fast immer mit einer bool Query, die den Zeitraum über einen range-Filter auf dasselbe Feld eingrenzt. Ohne diesen Filter läuft die Aggregation zwar korrekt, aber unnötig teuer, weil auch Dokumente außerhalb des angezeigten Zeitraums durchsucht werden.
GET /orders/_search
{
"size": 0,
"query": {
"range": {
"order_date": { "gte": "2026-01-01", "lt": "2026-07-01" }
}
},
"aggs": {
"orders_per_day": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day",
"format": "yyyy-MM-dd",
"min_doc_count": 0
}
}
}
}
3. Calendar Intervals vs Fixed Intervals im Detail
Der wichtigste Unterschied bei jeder Date Histogram Aggregation ist die Wahl zwischen calendar_interval und fixed_interval, weil beide Optionen bei größeren Einheiten unterschiedliche Ergebnisse liefern. calendar_interval kennt Kalendersemantik: "month" erzeugt Buckets, die genau am Monatsersten beginnen und je nach Monat 28 bis 31 Tage umfassen. fixed_interval dagegen rechnet in festen Millisekunden-Vielfachen, sodass "30d" wirklich immer exakt 30 Tage lang ist, unabhängig davon, wo der Monat beginnt oder endet.
Für Auswertungen wie "Umsatz pro Monat" ist calendar_interval fast immer die richtige Wahl, weil Fachanwender einen Monatsbalken erwarten, der dem Kalendermonat entspricht, und nicht einen willkürlichen 30-Tage-Ausschnitt. Für technische Metriken wie "Requests pro festem 5-Minuten-Fenster" ist fixed_interval passender, weil hier die exakte, gleichbleibende Fensterbreite zählt und keine Kalenderlogik gewünscht ist. Ein Date Histogram mit calendar_interval unterstützt zusätzlich Einheiten wie week, quarter und year, die es bei fixed_interval gar nicht gibt, weil ihre Länge kalenderabhängig variiert.
Ein oft übersehener Effekt: Ein fixed_interval von "1d" ist nicht dasselbe wie calendar_interval "day", sobald eine Sommerzeitumstellung im betrachteten Zeitraum liegt. Der fixed_interval-Tag hat immer exakt 86 400 000 Millisekunden, während der Kalendertag an einem Umstellungstag 23 oder 25 Stunden dauert. Bei einem Date Histogram über mehrere Monate verschieben sich mit fixed_interval die sichtbaren Tagesgrenzen langsam gegenüber der lokalen Uhrzeit, was in Dashboards zu scheinbar falschen Tagesumsätzen führt.
GET /orders/_search
{
"size": 0,
"aggs": {
"revenue_per_month_calendar": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "month",
"format": "yyyy-MM"
}
},
"revenue_per_30_days_fixed": {
"date_histogram": {
"field": "order_date",
"fixed_interval": "30d",
"format": "yyyy-MM-dd"
}
}
}
}
4. Zeitzonen korrekt handhaben
Elasticsearch speichert Datumsfelder intern immer als UTC, unabhängig davon, in welcher Zeitzone die Daten ursprünglich erfasst wurden. Ohne explizite Angabe berechnet eine Date Histogram Aggregation ihre Bucket-Grenzen daher ebenfalls in UTC. Für einen Shop mit Kunden in Deutschland bedeutet das: Ein Tagesbucket "2026-07-24" beginnt in UTC um 00:00 Uhr, was in Mitteleuropäischer Sommerzeit bereits 02:00 Uhr morgens ist. Bestellungen zwischen 00:00 und 02:00 Uhr lokaler Zeit landen fälschlicherweise noch im Bucket des Vortags.
Der Parameter time_zone löst dieses Problem, indem er die Bucket-Grenzen der date_histogram Aggregation in eine benannte Zeitzone verschiebt, bevor die Kalenderlogik angewendet wird. Wichtig ist, eine IANA-Zeitzone wie "Europe/Berlin" statt eines festen UTC-Offsets wie "+02:00" zu verwenden, weil nur die benannte Zeitzone automatisch zwischen Sommer- und Winterzeit wechselt. Ein fester Offset würde im Winter genau die gleiche falsche Verschiebung erzeugen, die man im Sommer eigentlich beheben wollte. Das korrekte Query-Muster mit "time_zone": "Europe/Berlin" zeigt Abschnitt 9 im direkten Vergleich zur fehlerhaften Variante ohne Zeitzonenangabe.
Ein zweiter Zeitzonen-Effekt betrifft international tätige Shops, die Kunden in mehreren Zeitzonen bedienen. Ein einziges Date Histogram kann nur eine Zeitzone gleichzeitig anwenden. Wer Kunden nach lokaler Ortszeit auswerten will, braucht entweder eine gespeicherte Zeitzone pro Dokument mit einer nachgelagerten Berechnung, oder mehrere parallele Aggregationen pro Zielregion. Für die meisten Reporting-Anwendungsfälle reicht dagegen eine einzige feste Geschäftszeitzone völlig aus, solange sie konsistent im gesamten Dashboard verwendet wird.
5. Sub-Aggregationen: Umsatz und Kennzahlen pro Zeitraum
Die eigentliche Auswertung entsteht erst, wenn unter jedes Bucket der Date Histogram Aggregation eine Metrik-Aggregation gehängt wird. sum berechnet die Summe eines numerischen Felds pro Zeitraum, etwa den Tagesumsatz. avg liefert den Durchschnittsbestellwert, cardinality die Anzahl unterschiedlicher Kunden pro Tag. Diese Sub-Aggregationen laufen für jedes Bucket unabhängig und liefern in einer einzigen Query eine vollständige mehrdimensionale Zeitreihe.
Für Sales-Dashboards ist die Kombination aus sum, avg und value_count besonders verbreitet, weil sie mit einer einzigen Anfrage Umsatz, durchschnittlichen Bestellwert und Bestellanzahl pro Zeitraum liefert. Zusätzlich lässt sich eine bucket_selector Pipeline-Aggregation einhängen, um nachträglich nur Buckets mit einem Umsatz oberhalb eines Schwellwerts zu behalten, etwa um Ausreißertage in einem separaten Panel hervorzuheben.
GET /orders/_search
{
"size": 0,
"query": {
"range": { "order_date": { "gte": "now-90d/d", "lte": "now/d" } }
},
"aggs": {
"sales_per_day": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day",
"time_zone": "Europe/Berlin",
"min_doc_count": 0
},
"aggs": {
"daily_revenue": { "sum": { "field": "grand_total" } },
"avg_order_value": { "avg": { "field": "grand_total" } },
"unique_customers": { "cardinality": { "field": "customer_id" } }
}
}
}
}
6. Lückenlose Zeitreihen: min_doc_count und extended_bounds
Standardmäßig überspringt eine Date Histogram Aggregation Buckets ohne Dokumente, was bei umsatzlosen Tagen zu Lücken in der Zeitreihe führt. Für die meisten Liniendiagramme ist das unerwünscht, weil ein fehlender Datenpunkt anders aussieht als ein Datenpunkt mit dem Wert null. Der Parameter min_doc_count auf 0 zwingt die Aggregation, auch leere Buckets zurückzugeben, was durchgängige Zeitreihen ohne clientseitige Nachbearbeitung ermöglicht.
Ein zweites, verwandtes Problem betrifft die Ränder der Zeitreihe: Wenn der gewählte Zeitraum am Anfang oder Ende keine Dokumente enthält, erzeugt min_doc_count allein noch keine Buckets an diesen Rändern, weil die Aggregation ihre Bucket-Grenzen aus den tatsächlich vorhandenen Daten ableitet. extended_bounds löst das, indem es min und max explizit vorgibt und damit sicherstellt, dass ein Date Histogram exakt vom gewünschten Start- bis zum Enddatum reicht, selbst wenn die ersten oder letzten Tage komplett leer sind.
GET /orders/_search
{
"size": 0,
"aggs": {
"sales_per_day_no_gaps": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day",
"time_zone": "Europe/Berlin",
"min_doc_count": 0,
"extended_bounds": {
"min": "2026-01-01",
"max": "2026-07-24"
}
},
"aggs": {
"daily_revenue": { "sum": { "field": "grand_total" } }
}
}
}
}
7. Performance bei großen Indizes
Eine Date Histogram Aggregation über Milliarden von Dokumenten ist grundsätzlich effizient, weil Elasticsearch die Aggregation über den invertierten Index und die Doc-Values-Struktur ausführt, ohne einzelne Dokumente zu laden. Entscheidend für die Performance ist trotzdem der einschränkende range-Filter im query-Teil: Ohne ihn durchsucht die Aggregation den kompletten Datenbestand, mit ihm reduziert sich die Kandidatenmenge auf den tatsächlich relevanten Zeitraum, was besonders bei zeitbasierten Indizes mit Index-Rotation den Suchraum drastisch verkleinert.
Bei sehr feingranularen Buckets über lange Zeiträume, etwa stündliche Buckets über mehrere Jahre, steigt die Anzahl der zurückgegebenen Buckets schnell in den fünfstelligen Bereich, was den Response deutlich vergrößert und im Client teuer zu rendern ist. Ein bewährtes Pattern ist deshalb, die Granularität eines Date Histogram dynamisch an den angefragten Zeitraum zu koppeln: Tage für einen Monat, Wochen für ein Quartal, Monate für ein Jahr. Zusätzlich reduziert die Kombination mit gerollten Aggregationsindizes, in denen tägliche Summen bereits vorberechnet abgelegt sind, den Rechenaufwand für weit zurückliegende Zeiträume erheblich.
8. Sales-over-Time Dashboards in der Praxis
In einem typischen Sales-Dashboard kombiniert man ein Date Histogram mit mehreren parallelen Facetten: eine oberste Ebene nach Zeitraum, darunter optional eine Terms-Aggregation nach Produktkategorie oder Vertriebskanal. Diese Kombination liefert in einer einzigen Query sowohl den Gesamtverlauf als auch die Aufschlüsselung nach Kategorie pro Zeitraum, was clientseitig ein gestapeltes Balkendiagramm ohne zusätzliche Requests ermöglicht.
Für Vergleichsansichten wie "dieser Monat vs. Vormonat" empfiehlt sich statt zweier date_histogram Aggregationen häufig ein einziges Date Histogram über den kombinierten Zeitraum mit anschließender Verarbeitung im Client, weil die Buckets dann garantiert konsistent ausgerichtet sind. Bei Echtzeit-Dashboards, die alle paar Sekunden neu laden, lohnt sich außerdem ein request_cache auf Index-Ebene, sofern der Zeitraum selten wechselt, sowie ein bewusst gewähltes preference-Routing, um wiederholte Anfragen auf denselben Shard-Replikas zu bündeln und die Cache-Trefferquote zu erhöhen.
9. Typische Fehler und Debugging
Der häufigste Fehler bei einer Date Histogram Aggregation ist das Fehlen von time_zone, obwohl die Anwendung lokale Tagesgrenzen erwartet. Das äußert sich als scheinbar zufällige Verschiebung von Bestellungen zwischen zwei benachbarten Tagesbalken, besonders auffällig kurz nach Mitternacht. Der zweite häufige Fehler ist die Verwechslung von fixed_interval und calendar_interval bei Monats- oder Jahresauswertungen, was zu Balken mit inkonsistenter Breite und falsch beschrifteten Zeiträumen führt.
// WRONG: no time_zone, no extended_bounds, gaps show as missing days
{
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
}
}
// RIGHT: explicit time zone, no gaps, aligned to the full report range
{
"date_histogram": {
"field": "order_date",
"calendar_interval": "day",
"time_zone": "Europe/Berlin",
"min_doc_count": 0,
"extended_bounds": { "min": "2026-01-01", "max": "2026-07-24" }
}
}
Ein dritter Fehler betrifft das Zeitfeld selbst: Wird order_date als text statt als date gemappt, akzeptiert die date_histogram Aggregation das Feld gar nicht erst und schlägt mit einem Mapping-Fehler fehl. Wer ein Date Histogram gegen ein Feld mit falschem Typ ausführen will, muss das Mapping vor dem Reindex korrigieren, da date_histogram nur auf echten date- oder date_nanos-Feldern arbeitet und keine implizite String-zu-Datum-Konvertierung zur Query-Zeit durchführt.
| Eigenschaft | calendar_interval | fixed_interval | Einsatz |
|---|---|---|---|
| Einheiten | minute bis year, inklusive month, quarter | ms, s, m, h, d nur als feste Vielfache | Kalendermonate brauchen calendar_interval |
| Bucket-Länge | variabel, kalenderabhängig | immer exakt gleich lang | Feste Zeitfenster für Monitoring |
| DST-Verhalten | respektiert Zeitumstellung mit time_zone | ignoriert Zeitumstellung, driftet | Lokale Tagesgrenzen brauchen calendar_interval |
| Typischer Fall | Umsatz pro Monat, Woche, Jahr | Requests pro 5-Minuten-Fenster | Fachlich vs. technisch geprägte Metrik |
| Performance | vergleichbar, geringer Rechenaufwand | vergleichbar, geringer Rechenaufwand | Unterschied liegt in Filter und Bucket-Anzahl |
Mironsoft
Elasticsearch- und OpenSearch-Beratung für Suche, Analytics und Dashboards
Zeitreihen-Dashboards, die auch bei Zeitzonen stimmen?
Wir bauen Date Histogram Aggregationen, die Zeitzonen korrekt handhaben, lückenlose Zeitreihen liefern und auch bei großen Indizes performant bleiben, von der Mapping-Prüfung bis zum fertigen Sales-Dashboard.
Aggregations-Review
Prüfung bestehender date_histogram Queries auf Zeitzonen- und Intervallfehler
Dashboard-Umsetzung
Sales-over-Time Panels mit sauberen Sub-Aggregationen und lückenlosen Zeitreihen
Performance-Tuning
Filterstrategie, Rollup-Indizes und Bucket-Granularität für große Datenmengen
10. Zusammenfassung
Die Date Histogram Aggregation ist das zentrale Werkzeug für Zeitreihen in Elasticsearch und OpenSearch, weil sie Bucket-Bildung, Kalenderlogik und Sortierung in einer einzigen deklarativen Query vereint. calendar_interval liefert fachlich korrekte Monats-, Wochen- und Jahresbuckets, fixed_interval liefert exakt gleich lange technische Zeitfenster. Der Parameter time_zone ist bei lokal ausgerichteten Auswertungen praktisch immer erforderlich, weil Elasticsearch intern in UTC rechnet.
min_doc_count auf 0 und extended_bounds sorgen für lückenlose Zeitreihen ohne clientseitige Nachbearbeitung, während ein einschränkender range-Filter im query-Teil die Performance auch bei sehr großen Indizes absichert. Wer diese Bausteine kombiniert, baut Sales-Dashboards, die über Monatsgrenzen, Schaltjahre und Zeitumstellungen hinweg korrekte Zahlen zeigen, statt scheinbar zufällige Verschiebungen zu produzieren.
Date Histogram für Zeitreihen-Analysen, das Wichtigste auf einen Blick
Intervall-Wahl
calendar_interval für Kalendermonate, Wochen und Jahre. fixed_interval für exakt gleich lange technische Fenster.
Zeitzonen
Immer eine IANA-Zeitzone wie Europe/Berlin angeben, niemals einen festen UTC-Offset, sonst driften Tagesgrenzen.
Lückenlose Buckets
min_doc_count 0 plus extended_bounds erzeugen durchgängige Zeitreihen auch bei leeren Randbereichen.
Performance
Range-Filter im query-Teil einschränken, Granularität an den Zeitraum koppeln, Rollups für alte Daten nutzen.