Gerçek Dünya Aggregation Kalıpları
Giriş — Dashboard'ların Arkasındaki Sorgular
Her gün kullandığınız dashboard'ları düşünün. E-ticaret sitesinde sol taraftaki filtreler (kategori, fiyat aralığı, marka, rating), Google Analytics'teki ziyaretçi grafikleri, Kibana'daki log analiz panelleri — bunların hepsi aggregation sorgularının sonucudur.
Bu ders, gerçek dünya senaryolarında en sık kullanılan aggregation kalıplarını gösterecek. Her bir pattern, kopyalayıp kendi projenize uyarlayabileceğiniz tam çalışan örneklerdir. "Aggregation biliyorum ama gerçek projede nasıl kullanacağımı bilmiyorum" diyorsanız, bu ders tam size göre.
1. E-Commerce Faceted Search
Faceted search (yüzlü arama), kullanıcının arama sonuçlarını kategorilere göre daraltmasını sağlar. Amazon, Trendyol, Hepsiburada — hepsinin sol panelindeki filtreler faceted search'tür.
1.1 Test Verisi
PUT products
{
"mappings": {
"properties": {
"name": { "type": "text", "analyzer": "turkish" },
"category": { "type": "keyword" },
"brand": { "type": "keyword" },
"price": { "type": "float" },
"rating": { "type": "float" },
"color": { "type": "keyword" },
"in_stock": { "type": "boolean" },
"created_at": { "type": "date" }
}
}
}
POST products/_bulk
{"index":{}}
{"name":"Samsung Galaxy S24 Ultra","category":"Telefon","brand":"Samsung","price":54999,"rating":4.7,"color":"Siyah","in_stock":true,"created_at":"2024-01-15"}
{"index":{}}
{"name":"iPhone 15 Pro Max","category":"Telefon","brand":"Apple","price":64999,"rating":4.8,"color":"Beyaz","in_stock":true,"created_at":"2024-01-10"}
{"index":{}}
{"name":"Samsung Galaxy Tab S9","category":"Tablet","brand":"Samsung","price":24999,"rating":4.5,"color":"Gri","in_stock":true,"created_at":"2024-02-01"}
{"index":{}}
{"name":"Nike Air Max 270","category":"Ayakkabı","brand":"Nike","price":3499,"rating":4.3,"color":"Siyah","in_stock":true,"created_at":"2024-03-01"}
{"index":{}}
{"name":"Adidas Ultraboost","category":"Ayakkabı","brand":"Adidas","price":4299,"rating":4.6,"color":"Beyaz","in_stock":false,"created_at":"2024-03-15"}
{"index":{}}
{"name":"Samsung Galaxy Buds FE","category":"Kulaklık","brand":"Samsung","price":2499,"rating":4.2,"color":"Siyah","in_stock":true,"created_at":"2024-04-01"}
{"index":{}}
{"name":"Apple AirPods Pro 2","category":"Kulaklık","brand":"Apple","price":7499,"rating":4.9,"color":"Beyaz","in_stock":true,"created_at":"2024-02-15"}
{"index":{}}
{"name":"Sony WH-1000XM5","category":"Kulaklık","brand":"Sony","price":8999,"rating":4.7,"color":"Siyah","in_stock":true,"created_at":"2024-01-20"}1.2 Faceted Search Sorgusu
GET products/_search
{
"query": {
"bool": {
"must": [
{ "match": { "name": "samsung" } }
]
}
},
"size": 20,
"aggs": {
"categories": {
"terms": { "field": "category", "size": 20 }
},
"brands": {
"terms": { "field": "brand", "size": 30 }
},
"price_ranges": {
"range": {
"field": "price",
"ranges": [
{ "key": "0-1000 TL", "to": 1000 },
{ "key": "1000-5000 TL", "from": 1000, "to": 5000 },
{ "key": "5000-10000 TL", "from": 5000, "to": 10000 },
{ "key": "10000-25000 TL", "from": 10000, "to": 25000 },
{ "key": "25000+ TL", "from": 25000 }
]
}
},
"rating_ranges": {
"range": {
"field": "rating",
"ranges": [
{ "key": "4+ Yıldız", "from": 4.0 },
{ "key": "3-4 Yıldız", "from": 3.0, "to": 4.0 },
{ "key": "3 Altı", "to": 3.0 }
]
}
},
"colors": {
"terms": { "field": "color", "size": 15 }
},
"in_stock_filter": {
"terms": { "field": "in_stock" }
},
"price_stats": {
"stats": { "field": "price" }
}
}
}Bu tek sorgu şunları döndürür:
Ürün listesi (hits)
Kategori filtresi (Telefon: 1, Tablet: 1, Kulaklık: 1)
Marka filtresi (Samsung: 3)
Fiyat aralıkları (bucket'lar ve sayıları)
Rating aralıkları
Renk filtresi
Stok durumu
Fiyat istatistikleri (min, max, avg)
1.3 Post-Filter — Facet Sayılarını Korumak
Normal filter aggregation sayılarını etkiler. Kullanıcı "Samsung" markasını seçtiğinde, diğer marka sayıları da değişir — bu genelde istenmez. post_filter ile arama sonuçlarını filtrelerken aggregation'ları etkilemezsiniz:
GET products/_search
{
"query": {
"match": { "name": "kulaklık" }
},
"post_filter": {
"term": { "brand": "Samsung" }
},
"aggs": {
"brands": {
"terms": { "field": "brand", "size": 20 }
},
"categories": {
"terms": { "field": "category", "size": 20 }
}
}
}post_filter yalnızca hits'i etkiler, aggs'ı etkilemez. Böylece:
Ürün listesi: Sadece Samsung kulaklıklar
Marka facet: Tüm markalar ve sayıları (Samsung: 1, Apple: 1, Sony: 1) — filtreden etkilenmedi!
⚠️ Dikkat: post_filter sadece top-level aggregation'ları korur. Eğer aggregation'ın da filtrelenmesini istiyorsanız, aggregation içinde filter agg kullanın.
2. Time-Series Analytics
Log analizi, monitoring, IoT verisi — zaman serisi verileri Elasticsearch'ün en güçlü olduğu alandır.
2.1 Saatlik/Günlük/Aylık Analiz
GET server_logs/_search
{
"size": 0,
"aggs": {
"hourly": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "hour",
"min_doc_count": 0,
"extended_bounds": {
"min": "2024-12-01T00:00:00",
"max": "2024-12-01T23:59:59"
}
},
"aggs": {
"avg_response_time": { "avg": { "field": "response_time_ms" } },
"error_count": {
"filter": {
"range": { "status_code": { "gte": 500 } }
}
},
"request_count": { "value_count": { "field": "_id" } },
"percentile_response": {
"percentiles": {
"field": "response_time_ms",
"percents": [50, 90, 95, 99]
}
}
}
}
}
}min_doc_count: 0 ile boş saatler de gösterilir (veri olmasa bile bucket oluşur). extended_bounds tam 24 saatlik aralığı garanti eder.
2.2 Karşılaştırmalı Time Series
Bu hafta ile geçen haftayı karşılaştırmak:
GET server_logs/_search
{
"size": 0,
"aggs": {
"this_week": {
"filter": {
"range": {
"timestamp": {
"gte": "now-7d/d",
"lte": "now/d"
}
}
},
"aggs": {
"daily": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "day"
},
"aggs": {
"requests": { "value_count": { "field": "_id" } },
"avg_latency": { "avg": { "field": "response_time_ms" } }
}
}
}
},
"last_week": {
"filter": {
"range": {
"timestamp": {
"gte": "now-14d/d",
"lte": "now-7d/d"
}
}
},
"aggs": {
"daily": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "day"
},
"aggs": {
"requests": { "value_count": { "field": "_id" } },
"avg_latency": { "avg": { "field": "response_time_ms" } }
}
}
}
}
}
}3. Funnel Analysis
Kullanıcı dönüşüm hunisi: Sayfa ziyareti → Ürün görüntüleme → Sepete ekleme → Ödeme → Sipariş tamamlama.
GET user_events/_search
{
"size": 0,
"aggs": {
"funnel": {
"filters": {
"filters": {
"1_page_view": {
"term": { "event_type": "page_view" }
},
"2_product_view": {
"term": { "event_type": "product_view" }
},
"3_add_to_cart": {
"term": { "event_type": "add_to_cart" }
},
"4_checkout": {
"term": { "event_type": "checkout_start" }
},
"5_purchase": {
"term": { "event_type": "purchase" }
}
}
},
"aggs": {
"unique_users": {
"cardinality": {
"field": "user_id"
}
}
}
}
}
}Sonuç:
{
"buckets": {
"1_page_view": { "doc_count": 50000, "unique_users": { "value": 12000 } },
"2_product_view": { "doc_count": 25000, "unique_users": { "value": 8000 } },
"3_add_to_cart": { "doc_count": 5000, "unique_users": { "value": 3000 } },
"4_checkout": { "doc_count": 2500, "unique_users": { "value": 1500 } },
"5_purchase": { "doc_count": 1200, "unique_users": { "value": 800 } }
}
}Dönüşüm oranları: 12000 ziyaretçi → 800 satın alma = %6.7 dönüşüm oranı. En büyük kayıp "ürün görüntüleme → sepete ekleme" aşamasında.
3.1 Zaman Bazlı Funnel
GET user_events/_search
{
"size": 0,
"aggs": {
"weekly_funnel": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "week"
},
"aggs": {
"views": {
"filter": { "term": { "event_type": "product_view" } },
"aggs": { "users": { "cardinality": { "field": "user_id" } } }
},
"carts": {
"filter": { "term": { "event_type": "add_to_cart" } },
"aggs": { "users": { "cardinality": { "field": "user_id" } } }
},
"purchases": {
"filter": { "term": { "event_type": "purchase" } },
"aggs": { "users": { "cardinality": { "field": "user_id" } } }
}
}
}
}
}Haftalık funnel: Her haftanın dönüşüm oranını takip edebilirsiniz. Bir kampanya yaptığınız hafta dönüşüm artıyor mu?
4. Top-N Per Category
Her kategorideki en iyi N ürünü bulmak. SQL'deki ROW_NUMBER() OVER (PARTITION BY category) karşılığı.
GET products/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category", "size": 10 },
"aggs": {
"top_3_products": {
"top_hits": {
"size": 3,
"sort": [{ "rating": "desc" }],
"_source": ["name", "brand", "price", "rating"]
}
},
"avg_price": { "avg": { "field": "price" } },
"product_count": { "value_count": { "field": "_id" } }
}
}
}
}Sonuç yapısı:
Telefon (2 ürün, ort. 59999 TL)
1. iPhone 15 Pro Max — 4.8 ⭐ — 64999 TL
2. Samsung Galaxy S24 Ultra — 4.7 ⭐ — 54999 TL
Kulaklık (3 ürün, ort. 6332 TL)
1. Apple AirPods Pro 2 — 4.9 ⭐ — 7499 TL
2. Sony WH-1000XM5 — 4.7 ⭐ — 8999 TL
3. Samsung Galaxy Buds FE — 4.2 ⭐ — 2499 TL4.1 Top-N with Filters
Her kategoride stokta olan en pahalı 3 ürün:
GET products/_search
{
"size": 0,
"aggs": {
"by_category": {
"terms": { "field": "category" },
"aggs": {
"in_stock_only": {
"filter": { "term": { "in_stock": true } },
"aggs": {
"top_expensive": {
"top_hits": {
"size": 3,
"sort": [{ "price": "desc" }],
"_source": ["name", "price"]
}
}
}
}
}
}
}
}5. Moving Average ve Trend Analizi
5.1 Moving Average
Pipeline aggregation ile hareketli ortalama hesaplamak — trend çizgisi oluşturmak için:
GET orders/_search
{
"size": 0,
"aggs": {
"monthly_sales": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "month"
},
"aggs": {
"total_revenue": { "sum": { "field": "total_amount" } }
}
},
"revenue_moving_avg": {
"moving_avg": {
"buckets_path": "monthly_sales>total_revenue",
"window": 3,
"model": "simple"
}
}
}
}⚠️ Not: moving_avg aggregation Elasticsearch 8.x'te deprecated olmuştur. Yerine moving_fn kullanın:
GET orders/_search
{
"size": 0,
"aggs": {
"monthly_sales": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "month"
},
"aggs": {
"total_revenue": {
"sum": { "field": "total_amount" }
},
"revenue_moving_avg": {
"moving_fn": {
"buckets_path": "total_revenue",
"window": 3,
"script": "MovingFunctions.unweightedAvg(values)"
}
},
"revenue_trend": {
"moving_fn": {
"buckets_path": "total_revenue",
"window": 5,
"script": "MovingFunctions.linearWeightedAvg(values)"
}
}
}
}
}
}MovingFunctions built-in fonksiyonları:
unweightedAvg(values)— Basit hareketli ortalamalinearWeightedAvg(values)— Doğrusal ağırlıklı (son değerler daha ağır)ewma(values, alpha)— Üstel ağırlıklı hareketli ortalamaholt(values, alpha, beta)— Holt's double exponential smoothingholtWinters(values, alpha, beta, gamma, period, ...)— Mevsimsel trend
5.2 Cumulative Sum — Kümülatif Toplam
GET orders/_search
{
"size": 0,
"aggs": {
"monthly_sales": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "month"
},
"aggs": {
"monthly_revenue": { "sum": { "field": "total_amount" } },
"cumulative_revenue": {
"cumulative_sum": {
"buckets_path": "monthly_revenue"
}
}
}
}
}
}Yıllık hedefi takip etmek için mükemmel: her ay kümülatif gelir artışını görürsünüz.
5.3 Derivative — Değişim Oranı
GET orders/_search
{
"size": 0,
"aggs": {
"monthly_sales": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "month"
},
"aggs": {
"monthly_revenue": { "sum": { "field": "total_amount" } },
"revenue_change": {
"derivative": {
"buckets_path": "monthly_revenue"
}
}
}
}
}
}Önceki aya göre gelir değişimi: pozitif → büyüme, negatif → düşüş.
6. Percentile Monitoring ve SLA
6.1 Response Time Percentile'ları
GET api_logs/_search
{
"size": 0,
"aggs": {
"response_percentiles": {
"percentiles": {
"field": "response_time_ms",
"percents": [50, 75, 90, 95, 99, 99.9]
}
},
"response_ranks": {
"percentile_ranks": {
"field": "response_time_ms",
"values": [100, 200, 500, 1000]
}
}
}
}percentiles: P50 = 45ms, P95 = 230ms, P99 = 890ms. SLA'nız "P99 < 1000ms" ise, şu an karşılıyorsunuz.
percentile_ranks: 200ms'den hızlı yanıt oranı %88, 500ms'den hızlı %96. Yani isteklerin %96'sı yarım saniyeden kısa sürede yanıtlanıyor.
6.2 SLA Dashboard Verisi
GET api_logs/_search
{
"size": 0,
"query": {
"range": {
"timestamp": { "gte": "now-24h" }
}
},
"aggs": {
"hourly_sla": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "hour"
},
"aggs": {
"total_requests": {
"value_count": { "field": "_id" }
},
"successful_requests": {
"filter": {
"range": { "status_code": { "lt": 500 } }
}
},
"error_requests": {
"filter": {
"range": { "status_code": { "gte": 500 } }
}
},
"p50_latency": {
"percentiles": {
"field": "response_time_ms",
"percents": [50]
}
},
"p99_latency": {
"percentiles": {
"field": "response_time_ms",
"percents": [99]
}
},
"sla_compliance": {
"filter": {
"bool": {
"must": [
{ "range": { "response_time_ms": { "lte": 1000 } } },
{ "range": { "status_code": { "lt": 500 } } }
]
}
}
}
}
}
}
}Her saat için: toplam istek, başarılı/hatalı istek, P50/P99 latency, SLA uyum oranı. Bir dashboard widget'ı tek bu sorguyla beslenir.
6.3 Uptime Hesaplama
GET health_checks/_search
{
"size": 0,
"aggs": {
"daily_uptime": {
"date_histogram": {
"field": "timestamp",
"calendar_interval": "day"
},
"aggs": {
"total_checks": { "value_count": { "field": "_id" } },
"successful_checks": {
"filter": { "term": { "status": "up" } }
},
"uptime_pct": {
"bucket_script": {
"buckets_path": {
"success": "successful_checks._count",
"total": "total_checks"
},
"script": "params.total > 0 ? (params.success / params.total) * 100 : 0"
}
}
}
}
}
}bucket_script pipeline aggregation ile yüzde hesaplama. Her gün için uptime yüzdesi: %99.95, %100, %99.87...
7. Gerçek Dünya E-Commerce Dashboard
Tam bir e-ticaret dashboard'unun tüm widget'larını tek sorguda çekelim:
GET orders/_search
{
"size": 0,
"query": {
"range": { "order_date": { "gte": "now-30d" } }
},
"aggs": {
"total_revenue": { "sum": { "field": "total_amount" } },
"total_orders": { "value_count": { "field": "_id" } },
"avg_order_value": { "avg": { "field": "total_amount" } },
"unique_customers": { "cardinality": { "field": "customer_id" } },
"daily_trend": {
"date_histogram": {
"field": "order_date",
"calendar_interval": "day"
},
"aggs": {
"revenue": { "sum": { "field": "total_amount" } },
"orders": { "value_count": { "field": "_id" } },
"moving_avg_revenue": {
"moving_fn": {
"buckets_path": "revenue",
"window": 7,
"script": "MovingFunctions.unweightedAvg(values)"
}
}
}
},
"top_categories": {
"terms": { "field": "category.keyword", "size": 5 },
"aggs": {
"revenue": { "sum": { "field": "total_amount" } },
"avg_order": { "avg": { "field": "total_amount" } }
}
},
"top_products": {
"terms": { "field": "product_name.keyword", "size": 10, "order": { "revenue": "desc" } },
"aggs": {
"revenue": { "sum": { "field": "total_amount" } },
"quantity": { "sum": { "field": "quantity" } }
}
},
"order_value_distribution": {
"histogram": {
"field": "total_amount",
"interval": 500,
"min_doc_count": 1
}
},
"payment_methods": {
"terms": { "field": "payment_method.keyword" }
},
"regional_breakdown": {
"terms": { "field": "region.keyword", "size": 10 },
"aggs": {
"revenue": { "sum": { "field": "total_amount" } },
"orders": { "value_count": { "field": "_id" } }
}
}
}
}Bu tek sorgu şu widget'ları besler:
KPI Kartları: Toplam gelir, sipariş sayısı, ortalama sipariş değeri, müşteri sayısı
Trend Grafiği: Günlük gelir + 7 günlük hareketli ortalama
Top Kategoriler: En çok satan 5 kategori
Top Ürünler: Gelire göre en iyi 10 ürün
Sipariş Dağılımı: Histogram (kaç sipariş hangi fiyat aralığında)
Ödeme Yöntemleri: Kredi kartı, havale, kapıda ödeme oranları
Bölgesel Dağılım: Şehir/bölge bazında gelir ve sipariş
8. Yaygın Hatalar
Hata 1: Faceted Search'te post_filter Unutmak
// ❌ Marka filtrelenince diğer markaların sayısı 0 olur
{
"query": { "bool": { "filter": [{ "term": { "brand": "Samsung" } }] } },
"aggs": { "brands": { "terms": { "field": "brand" } } }
}
// Sadece Samsung gösterilir, Apple: 0, Sony: 0
// ✅ post_filter ile filtrele — agg'lar etkilenmez
{
"query": { "match_all": {} },
"post_filter": { "term": { "brand": "Samsung" } },
"aggs": { "brands": { "terms": { "field": "brand" } } }
}Hata 2: Pipeline Agg'da Yanlış Path
// ❌ buckets_path yanlış
"moving_fn": { "buckets_path": "monthly_revenue" }
// Eğer "monthly_revenue" başka bir agg'ın altındaysa hata verir
// ✅ Tam path verin: "parent_agg>child_metric"
"moving_fn": { "buckets_path": "monthly_sales>total_revenue" }Hata 3: min_doc_count Unutmak
// ❌ Veri olmayan zaman dilimleri atlanır — grafikte boşluk
"date_histogram": { "field": "timestamp", "calendar_interval": "hour" }
// ✅ Boş bucket'ları göster
"date_histogram": {
"field": "timestamp",
"calendar_interval": "hour",
"min_doc_count": 0,
"extended_bounds": {
"min": "2024-12-01T00:00:00",
"max": "2024-12-01T23:59:59"
}
}9. Best Practices
| Uygulama | Neden |
|---|---|
size: 0 kullanın (hits gerekmiyorsa) | Ağ ve bellek tasarrufu |
post_filter ile facet sayılarını koruyun | Kullanıcı deneyimi bozulmasın |
min_doc_count: 0 + extended_bounds kullanın | Zaman serisi grafiklerinde boşluk olmasın |
| Pipeline agg'ları sibling olarak tanımlayın | Metric agg ile aynı seviyede olmalı |
bucket_script ile yüzde hesaplayın | Dönüşüm oranı, uptime gibi metriklerde |
| Dashboard'ı tek sorguda besleyin | Ağ çağrısı sayısını minimuma indirin |
moving_fn kullanın (moving_avg deprecated) | ES 8.x uyumluluğu |
Özet
Faceted search
post_filterile yapılır — aggregation sayıları korunurken hits filtrelenirTime-series
date_histogram+min_doc_count: 0+extended_boundsile boşluksuz zaman serisiFunnel analysis
filtersaggregation +cardinalityile dönüşüm hunisi — drop-off noktaları belirlenirTop-N per category
terms+top_hitsile her gruptaki en iyi N öğeMoving average
moving_fn+MovingFunctionsile trend analiziPercentile monitoring
percentiles+percentile_ranksile SLA takibiDashboard tek sorguyla tüm widget verisini çekin — KPI, trend, dağılım, top-N hepsi bir arada
AI Asistan
Sorularını yanıtlamaya hazır