EElasticsearch Handbook

ORTA

Aggregations

Aggregation'lar SQL'deki GROUP BY + aggregate fonksiyonlarının karşılığıdır. Üç ana tip: Bucket (gruplama), Metric (hesaplama), Pipeline (agg üzeri agg).

Kod örneği tercihiBu sayfadaki istemci örneklerini birlikte değiştirir.
Bucket Aggs terms (GROUP BY) date_histogram range / filters nested / composite Dokümanları gruplar Her bucket = alt küme Metric Aggs avg, sum, min, max cardinality (distinct) percentiles stats / extended_stats Sayısal hesaplamalar Bucket içinde çalışır Pipeline Aggs avg_bucket max_bucket derivative cumulative_sum Diğer agg sonuçları üzerinde İkincil hesaplamalar

Dashboard Aggregation Örneği

# E-ticaret dashboard: kategori bazlı satış analizi
curl -X GET "http://localhost:9200/orders/_search?size=0" -H "Content-Type: application/json" -d'
{
  "query": { "range": { "order_date": { "gte": "now-30d" } } },
  "aggs": {
    "by_category": {
      "terms": { "field": "category", "size": 20 },
      "aggs": {
        "total_revenue": { "sum": { "field": "total_amount" } },
        "avg_order_value": { "avg": { "field": "total_amount" } },
        "unique_customers": { "cardinality": { "field": "customer_id" } },
        "daily_sales": {
          "date_histogram": {
            "field": "order_date",
            "calendar_interval": "day"
          },
          "aggs": {
            "daily_revenue": { "sum": { "field": "total_amount" } }
          }
        }
      }
    },
    "price_ranges": {
      "range": {
        "field": "total_amount",
        "ranges": [
          { "to": 100 },
          { "from": 100, "to": 500 },
          { "from": 500, "to": 2000 },
          { "from": 2000 }
        ]
      }
    },
    "revenue_over_time": {
      "date_histogram": {
        "field": "order_date",
        "calendar_interval": "week"
      },
      "aggs": {
        "weekly_revenue": { "sum": { "field": "total_amount" } },
        "cumulative_revenue": {
          "cumulative_sum": { "buckets_path": "weekly_revenue" }
        }
      }
    }
  }
}'
public async Task<DashboardData> GetDashboardAsync()
{
    var response = await _client.SearchAsync<Order>(s => s
        .Index("orders")
        .Size(0)
        .Query(q => q.Range(r => r
            .DateRange(dr => dr.Field(f => f.OrderDate).Gte("now-30d"))))
        .Aggregations(aggs => aggs
            .Add("by_category", a => a.Terms(t => t
                .Field(f => f.Category).Size(20))
                .Aggregations(sub => sub
                    .Add("total_revenue", sa => sa.Sum(su => su.Field(f => f.TotalAmount)))
                    .Add("avg_order_value", sa => sa.Avg(av => av.Field(f => f.TotalAmount)))
                    .Add("unique_customers", sa => sa.Cardinality(c => c.Field(f => f.CustomerId)))))
            .Add("price_ranges", a => a.Range(r => r
                .Field(f => f.TotalAmount)
                .Ranges(
                    rn => rn.To(100),
                    rn => rn.From(100).To(500),
                    rn => rn.From(500).To(2000),
                    rn => rn.From(2000))))));

    var categoryBuckets = response.Aggregations
        .GetStringTerms("by_category").Buckets;

    return new DashboardData(categoryBuckets.Select(b => new CategoryStats(
        b.Key.ToString(),
        b.GetSum("total_revenue").Value ?? 0,
        b.GetAverage("avg_order_value").Value ?? 0,
        (long)(b.GetCardinality("unique_customers").Value ?? 0)
    )).ToList());
}

Örnek: Fintech dashboard'unda son 30 günlük işlemler: kategori bazlı toplam gelir, günlük trend, percentile dağılımı, benzersiz müşteri sayısı — hepsi tek bir ES query ile gelir. SQL'de 5-6 ayrı query gerekecek iş, ES'te tek request.

High cardinality terms: terms aggregation varsayılan 10 bucket döner. Çok fazla unique değer varsa (>10K) composite aggregation kullanın — memory-safe pagination sağlar.

Pipeline Aggregations

// Günlük satış + kümülatif toplam (dashboard trend line)
GET /orders/_search
{
  "size": 0,
  "aggs": {
    "daily_sales": {
      "date_histogram": {
        "field": "created_at",
        "calendar_interval": "day"
      },
      "aggs": {
        "revenue": { "sum": { "field": "total_amount" } },
        "cumulative_revenue": {
          "cumulative_sum": { "buckets_path": "revenue" }
        }
      }
    }
  }
}
// cumulative_sum: günlük gelir + kümülatif toplam
var response = await client.SearchAsync<Order>(s => s
    .Index("orders")
    .Size(0)
    .Aggregations(aggs => aggs
        .Add("daily_sales", a => a
            .DateHistogram(dh => dh
                .Field(f => f.CreatedAt)
                .CalendarInterval(CalendarInterval.Day))
            .Aggregations(sub => sub
                .Add("revenue", sa => sa.Sum(sum => sum.Field(f => f.TotalAmount)))
                .Add("cumulative_revenue", sa => sa
                    .CumulativeSum(cs => cs.BucketsPath("revenue")))))));

// Sonuçları oku
var dailySales = response.Aggregations
    .GetDateHistogram("daily_sales");

foreach (var bucket in dailySales!.Buckets)
{
    // Sum → SumAggregate, Pipeline aggs → SimpleValueAggregate
    bucket.TryGetValue("revenue", out var revenueAgg);
    bucket.TryGetValue("cumulative_revenue", out var cumulativeAgg);

    var dayRevenue = (revenueAgg as SumAggregate)?.Value ?? 0;
    var cumulative = (cumulativeAgg as SimpleValueAggregate)?.Value ?? 0;
    Console.WriteLine($"{bucket.KeyAsString}: günlük={dayRevenue:C} kümülatif={cumulative:C}");
}

Örnek: E-ticaret dashboard'unda "bu ayın kümülatif geliri" grafiği: date_histogramsumcumulative_sum pipeline ile tek sorgu. Aynı pattern: derivative (günlük değişim), moving_avg (trend), bucket_selector (filtre) ile genişler.