Elasticsearch’te Aggregation ile Veri Analizi
Elasticsearch ile ciddi bir log analizi veya metrik izleme altyapısı kurduysanız, bir noktada sadece veri aramak yetmez hale gelir. “Kaç tane?” sorusundan “En çok hangisi?”, “Saatlik dağılım nasıl?”, “Ortalama yanıt süresi ne?” sorularına geçmeye başlarsınız. İşte tam bu noktada Elasticsearch aggregation mekanizması devreye girer ve sizi SQL’deki GROUP BY, COUNT, AVG gibi işlemlerin çok daha güçlü ve esnek bir versiyonuyla karşılaştırır.
Aggregation Nedir ve Neden Önemlidir
Elasticsearch aggregation, verilerinizi gruplandırmanıza, istatistiksel analizler yapmanıza ve karmaşık veri özetleri çıkarmanıza olanak tanıyan bir framework’tür. Klasik bir arama sorgusu size “şu kriterlere uyan belgeler bunlar” der. Aggregation ise “şu kriterlere uyan belgeler arasında şu alanın dağılımı şöyle, ortalaması bu, maksimum değeri şu” der.
Gerçek dünyada bu ne anlama gelir? Bir e-ticaret şirketinin sysadmin’i olduğunuzu düşünün. Nginx access log’larını Elasticsearch’e aktarıyorsunuz. Aggregation olmadan sadece “500 hatası dönen istekler hangileri” diye sorabilirsiniz. Aggregation ile “Son 24 saatte hangi endpoint’ler en çok 500 hatası üretti, bu hataların saatlik dağılımı nasıl ve hangi kullanıcı ajanlarından geliyor” diye sorabilirsiniz. Kibana’nın dashboard’larında gördüğünüz tüm grafikler ve metrikler arka planda bu aggregation mekanizmasıyla çalışır.
Aggregation Türleri
Elasticsearch aggregation’ları temelde dört kategoriye ayrılır:
- Bucket Aggregations: Belgeleri gruplara (bucket) ayırır. SQL’deki GROUP BY gibi düşünebilirsiniz.
- Metric Aggregations: Sayısal değerler üzerinde hesaplamalar yapar. SUM, AVG, MIN, MAX gibi işlemler.
- Pipeline Aggregations: Diğer aggregation’ların çıktıları üzerinde işlem yapar.
- Matrix Aggregations: Birden fazla alan üzerinde istatistiksel hesaplamalar yapar.
Günlük sysadmin işlerinde en çok Bucket ve Metric aggregation’larını kullanırsınız. Pipeline aggregation’lar daha ileri seviye senaryolarda, örneğin moving average hesaplamalarında veya derivative işlemlerinde işe yarar.
Temel Aggregation Sorgusunun Yapısı
Bir aggregation sorgusunun temel iskeletini anlamak, geri kalan her şeyi kolaylaştırır. Sorgu yapısı şu şekildedir:
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"query": {
"range": {
"@timestamp": {
"gte": "now-24h",
"lte": "now"
}
}
},
"aggs": {
"status_code_distribution": {
"terms": {
"field": "status",
"size": 10
}
}
}
}'
Burada dikkat etmeniz gereken birkaç nokta var. “size”: 0 diyerek ham belgelerin dönmesini engelliyoruz, sadece aggregation sonuçlarını istiyoruz. Bu performans açısından kritiktir. “query” kısmı aggregation’ın hangi veri üzerinde çalışacağını filtreler. “aggs” altında aggregation tanımlarınız yer alır.
Terms Aggregation: En Çok Kullanılan Bucket Tipi
Terms aggregation, bir alandaki benzersiz değerleri gruplandırır ve her grubun belge sayısını döndürür. Log analizinde vazgeçilmezdir.
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"aggs": {
"top_endpoints": {
"terms": {
"field": "request.keyword",
"size": 20,
"order": {
"_count": "desc"
}
}
}
}
}'
Bu sorgu, en çok istek alan 20 endpoint’i listeler. Keyword alanları için .keyword suffix’ini kullanmayı unutmayın, aksi halde analyzed text alanlarında aggregation çalışmaz veya hata verir. Bu konuda yeni başlayanların en sık yaptığı hatalardan biridir.
Terms aggregation’da “size” parametresi önemlidir. Varsayılan 10’dur ama büyük veri setlerinde daha fazlasına ihtiyaç duyabilirsiniz. Ancak şunu bilin: bu değeri aşırı büyütmek (örneğin 10000) hem bellek hem de CPU açısından maliyetlidir.
Metric Aggregations: Sayısal Analiz
Sistem performansı izlerken sadece sayımla yetinemezsiniz. Yanıt sürelerinin ortalaması, 95. persentil, maksimum değer gibi metriklere ihtiyaç duyarsınız.
curl -X POST "localhost:9200/apm-metrics-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"query": {
"term": {
"service.name": "payment-api"
}
},
"aggs": {
"response_time_stats": {
"extended_stats": {
"field": "transaction.duration.us"
}
},
"response_time_percentiles": {
"percentiles": {
"field": "transaction.duration.us",
"percents": [50, 75, 90, 95, 99]
}
}
}
}'
extended_stats aggregation tek sorguda count, min, max, avg, sum, standart sapma ve varyans döndürür. percentiles aggregation ise SLA takibi için kritiktir. P95 ve P99 değerleri, “kullanıcıların %1’i kaç milisaniyeden uzun bekledi” sorusuna yanıt verir.
Nested Aggregation: Aggregation İçinde Aggregation
Elasticsearch aggregation’larının gerçek gücü, iç içe geçirebilme özelliğinden gelir. Bir bucket aggregation içine metric aggregation koyarak “her durum kodu için ortalama yanıt süresi nedir” gibi sorulara yanıt bulabilirsiniz.
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"aggs": {
"by_status_code": {
"terms": {
"field": "status",
"size": 10
},
"aggs": {
"avg_response_time": {
"avg": {
"field": "response_time_ms"
}
},
"max_response_time": {
"max": {
"field": "response_time_ms"
}
},
"p95_response_time": {
"percentiles": {
"field": "response_time_ms",
"percents": [95]
}
}
}
}
}
}'
Bu sorgu her HTTP durum kodu için ortalama, maksimum ve P95 yanıt süresini verir. 200 kodları için P95 50ms iken 500 kodları için P95 değerinin 3000ms olduğunu görürseniz, hata durumlarının neden yavaş olduğunu araştırmanız gerektiğini anlarsınız.
Date Histogram: Zaman Serisi Analizi
Zaman bazlı analizler için date_histogram aggregation hayat kurtarıcıdır. Kibana’nın o güzel zaman serisi grafiklerini oluşturan mekanizma budur.
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"query": {
"range": {
"@timestamp": {
"gte": "now-7d",
"lte": "now"
}
}
},
"aggs": {
"requests_over_time": {
"date_histogram": {
"field": "@timestamp",
"calendar_interval": "1h",
"time_zone": "Europe/Istanbul"
},
"aggs": {
"error_count": {
"filter": {
"range": {
"status": {
"gte": 500,
"lte": 599
}
}
}
},
"avg_response": {
"avg": {
"field": "response_time_ms"
}
}
}
}
}
}'
Burada calendar_interval ile saatlik, günlük, haftalık gibi takvim tabanlı aralıklar belirtebilirsiniz. time_zone parametresi Türkiye saatiyle doğru gruplama yapmanızı sağlar. Gece yarısı saat farkı nedeniyle yanlış günlere düşen verileri görmek istemezsiniz.
Dikkat: Elasticsearch 7.2 ve üzerinde interval yerine calendar_interval veya fixed_interval kullanılması gerekir. Eski interval parametresi deprecated olmuştur.
Pipeline Aggregation ile İleri Seviye Analiz
Pipeline aggregation’lar diğer aggregation’ların çıktılarını girdi olarak kullanır. Örneğin saatlik hata oranını hesaplayıp moving average almak istiyorsanız:
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"aggs": {
"hourly_data": {
"date_histogram": {
"field": "@timestamp",
"fixed_interval": "1h"
},
"aggs": {
"error_count": {
"filter": {
"term": {
"status": 500
}
}
},
"total_count": {
"value_count": {
"field": "status"
}
},
"error_rate": {
"bucket_script": {
"buckets_path": {
"errors": "error_count._count",
"total": "total_count"
},
"script": "params.total > 0 ? (params.errors / params.total) * 100 : 0"
}
}
}
},
"moving_avg_error_rate": {
"moving_avg": {
"buckets_path": "hourly_data>error_rate",
"window": 3
}
}
}
}'
Bu sorgu saatlik hata oranını yüzde olarak hesaplar ve 3 saatlik moving average alır. Ani spike’ların smoothing ile daha net görülmesini sağlar.
Gerçek Dünya Senaryosu: APM Verisi Analizi
Diyelim ki bir microservice mimariniz var ve Elastic APM kullanıyorsunuz. Hangi servisin en fazla yavaş transaction ürettiğini, hangi endpoint’lerin sorunlu olduğunu analiz etmek istiyorsunuz.
curl -X POST "localhost:9200/apm-*-transaction*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"query": {
"bool": {
"must": [
{
"range": {
"@timestamp": {
"gte": "now-1h"
}
}
},
{
"term": {
"transaction.result": "HTTP 5xx"
}
}
]
}
},
"aggs": {
"by_service": {
"terms": {
"field": "service.name",
"size": 20
},
"aggs": {
"by_transaction": {
"terms": {
"field": "transaction.name",
"size": 10
},
"aggs": {
"avg_duration": {
"avg": {
"field": "transaction.duration.us"
}
},
"p99_duration": {
"percentiles": {
"field": "transaction.duration.us",
"percents": [99]
}
}
}
},
"total_errors": {
"value_count": {
"field": "transaction.id"
}
}
}
}
}
}'
Bu sorgu son 1 saatte hata veren her servisi listeler, her servis için hatalı endpoint’leri gösterir ve her endpoint’in ortalama ile P99 süresini raporlar. Incident sırasında hangi servise önce bakmanız gerektiğini saniyeler içinde anlarsınız.
Aggregation Performans İpuçları
Aggregation’lar güçlüdür ama dikkatli kullanılmazsa Elasticsearch cluster’ınızı zorlayabilir. Bir kaç kritik kural:
- “size”: 0 kullanmayı alışkanlık haline getirin. Hem aggregation hem ham belge getirmek gereksiz yüklenmeye neden olur.
- Terms aggregation’da size değerini makul tutun. 10000 gibi yüksek değerler heap kullanımını ciddi şekilde artırır.
- Filter aggregation kullanın, query yerine. Aggregation’ı sadece belirli belgelerle sınırlamak istiyorsanız filter aggregation caching açısından daha verimlidir.
- Wildcard index pattern’larından kaçının.
nginx-logs-*yerine mümkünse tarih bazlı spesifik index’leri hedefleyin. - fielddata açık olmayan keyword olmayan alanlarda aggregation yapmayın. Text alanlarında aggregation yapmak için fielddata enable etmek gerekir ki bu heap’i ezer.
- Shard sayısını aggregation performansı açısından değerlendirin. Her shard ayrı ayrı aggregation hesaplar, sonuçlar coordinating node’da merge edilir.
Özellikle production ortamında şu ayarı da gözden geçirin:
curl -X PUT "localhost:9200/_cluster/settings"
-H 'Content-Type: application/json'
-d '{
"transient": {
"search.max_buckets": 10000
}
}'
search.max_buckets parametresi tek bir aggregation response’unda döndürülebilecek maksimum bucket sayısını sınırlar. Varsayılan değer 65535’e kadar çıkabilir ancak production’da bunu kontrol altında tutmak isteyebilirsiniz.
Composite Aggregation ile Pagination
Büyük veri setlerinde tüm bucket’ları tek sorguda çekmek mümkün olmayabilir. Composite aggregation bu sorunu çözer ve aggregation sonuçlarında sayfalama yapmanıza olanak tanır.
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"aggs": {
"ip_endpoint_combo": {
"composite": {
"size": 100,
"sources": [
{
"client_ip": {
"terms": {
"field": "client_ip.keyword"
}
}
},
{
"endpoint": {
"terms": {
"field": "request.keyword"
}
}
}
]
}
}
}
}'
Sonuçta bir after_key değeri döner. Bir sonraki sayfayı çekmek için bu değeri after parametresi olarak kullanırsınız:
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"aggs": {
"ip_endpoint_combo": {
"composite": {
"size": 100,
"after": {
"client_ip": "192.168.1.105",
"endpoint": "/api/v2/products"
},
"sources": [
{
"client_ip": {
"terms": {
"field": "client_ip.keyword"
}
}
},
{
"endpoint": {
"terms": {
"field": "request.keyword"
}
}
}
]
}
}
}
}'
Composite aggregation özellikle tüm kombinasyonları işlemeniz gereken ETL süreçlerinde ve raporlama pipeline’larında çok işe yarar. Klasik terms aggregation ile bu boyuttaki analizler hem verimsiz hem de hatalı sonuç üretebilir.
Aggregation Sonuçlarını Yorumlamak
Aggregation sonuçlarını doğru yorumlamak da en az sorguyu yazmak kadar önemlidir. Terms aggregation sonuçlarında gördüğünüz doc_count_error_upper_bound değeri, sonuçların ne kadar hassas olduğunu gösterir. Bu değer sıfırdan büyükse, bazı bucket’ların atlanmış olabileceği anlamına gelir.
Bu durumu düzeltmek için iki yol vardır. Birincisi size parametresini artırmak, ikincisi ise shard_size parametresini artırmaktır. shard_size, her shard’ın coordinating node’a kaç bucket göndereceğini belirler ve varsayılan olarak size * 1.5 + 10 şeklinde hesaplanır. Büyük cluster’larda daha yüksek shard_size daha doğru sonuçlar verir ama aynı zamanda daha fazla network ve bellek kullanımı demektir.
curl -X POST "localhost:9200/nginx-logs-*/_search"
-H 'Content-Type: application/json'
-d '{
"size": 0,
"aggs": {
"top_ips": {
"terms": {
"field": "client_ip.keyword",
"size": 10,
"shard_size": 50
}
}
}
}'
Kibana ile Aggregation Sonuçlarını Görselleştirmek
Komut satırından aggregation sonuçlarını JSON olarak okumak her zaman pratik değildir. Kibana’nın Lens veya Visualize aracında aggregation sorgularını görsel olarak oluşturabilirsiniz. Ama bazen Kibana’nın arka planda ürettiği sorguyu görmek öğretici olabilir.
Kibana Dev Tools konsolunda aggregation’larınızı test etmek, curl’e göre çok daha rahat bir deneyim sunar. Auto-complete özelliği aggregation type’larını ve parametrelerini önererek öğrenme sürecini hızlandırır.
Kibana Lens’te “Top values” seçtiğinizde arka planda terms aggregation, “Median” seçtiğinizde percentiles aggregation, “Date histogram” seçtiğinizde date_histogram aggregation çalışır. Bu ilişkiyi anladığınızda hem Kibana’yı daha etkin kullanırsınız hem de özel dashboard ihtiyaçlarında doğrudan API’yi kullanabilirsiniz.
Sonuç
Elasticsearch aggregation mekanizması, ham log ve metrik verilerini anlamlı içgörülere dönüştürmenin en etkili yollarından biridir. Bucket aggregation’larla veriyi gruplandırmayı, metric aggregation’larla sayısal analiz yapmayı, date histogram ile zaman serisi analizi oluşturmayı ve pipeline aggregation’larla bu sonuçlar üzerinde ileri hesaplamalar yapmayı öğrendiğinizde, Elasticsearch salt bir arama motoru olmaktan çıkıp güçlü bir analitik platformuna dönüşür.
Pratik olarak başlamak için önce kendi log verilerinizin yapısını anlayın, sonra basit terms ve metric aggregation’larla başlayın. İç içe aggregation’lara geçin, date_histogram ile zaman serisi analizleri yapın. Performans sorunlarıyla karşılaştığınızda size, shard_size ve search.max_buckets parametrelerini gözden geçirin.
En önemlisi: Her aggregation sorgusunu önce geliştirme veya test ortamında çalıştırın. Yanlış yazılmış ya da aşırı karmaşık bir aggregation sorgusu, production cluster’ınızda ciddi performans sorunlarına yol açabilir. Elasticsearch cluster’ınız hem arama hem de aggregation yükünü dengeli taşıyacak şekilde boyutlandırılmışsa, bu analizleri gerçek zamanlı olarak çalıştırabilir ve altyapınızı çok daha iyi gözlemleyebilirsiniz.
