← Kursa Dön
📄 Text · 35 min

Index Templates ve Component Templates

Giriş — Fabrikada Kalıp Kullanmak

Bir fabrikada her ürünü tek tek elle şekillendirmezsiniz — bir kalıp yaparsınız ve her yeni ürün o kalıptan çıkar. Aynı şekilde Elasticsearch'te her yeni index oluştururken mapping, settings ve alias'ları tek tek tanımlamak yerine bir template (şablon) oluşturursunuz. Yeni index oluşturulduğunda, eğer adı şablonun pattern'ına uyuyorsa, otomatik olarak şablondaki ayarlar uygulanır.

Özellikle log verileri, zaman serisi verileri ve çok sayıda index oluşturulan senaryolarda template'ler hayat kurtarır. logs-2024.01, logs-2024.02, logs-2024.03... Her biri için ayrı ayrı mapping tanımlamak mı? Bir template tanımla, gerisini Elasticsearch halletsin.

Bu ders, legacy template'lerden modern composable template'lere, component template'lere, data stream'lere ve ILM entegrasyonuna kadar her şeyi derinlemesine ele alacak.


1. Legacy Templates vs Composable Templates

1.1 Legacy Templates (Eski Yöntem)

Elasticsearch 7.8 öncesinde legacy template'ler (veya "v1 template") kullanılıyordu. _template endpoint'i ile yönetilirdi:

// Legacy template — ARTIK ÖNERİLMİYOR
PUT _template/logs-legacy
{
  "index_patterns": ["logs-*"],
  "order": 1,
  "settings": {
    "number_of_shards": 2,
    "number_of_replicas": 1,
    "refresh_interval": "5s"
  },
  "mappings": {
    "properties": {
      "timestamp": { "type": "date" },
      "level": { "type": "keyword" },
      "message": { "type": "text" }
    }
  },
  "aliases": {
    "all-logs": {}
  }
}

Legacy template'lerin sorunları:

  • Template'ler arası paylaşım yok — aynı mapping parçasını birden fazla template'e kopyalama zorunluluğu

  • Çakışma çözümü sadece order ile — karmaşık senaryolarda yönetimi zor

  • Güncelleme yapıldığında tüm template overwrite ediliyor

  • Modülerlik yok

1.2 Composable Templates (Modern Yöntem)

Elasticsearch 7.8+ ile gelen composable template'ler (_index_template endpoint'i) çok daha güçlü ve esnek bir yapı sunar:

// Modern composable template
PUT _index_template/logs-template
{
  "index_patterns": ["logs-*"],
  "priority": 100,
  "template": {
    "settings": {
      "number_of_shards": 2,
      "number_of_replicas": 1,
      "refresh_interval": "5s"
    },
    "mappings": {
      "properties": {
        "timestamp": { "type": "date" },
        "level": { "type": "keyword" },
        "message": { "type": "text" }
      }
    },
    "aliases": {
      "all-logs": {}
    }
  }
}

Composable template avantajları:

  • Component template desteği — ortak parçaları paylaşabilirsiniz

  • priority ile çakışma çözümü daha açık ve öngörülebilir

  • Partial update mümkün

  • Data stream desteği

1.3 Karşılaştırma Tablosu

┌──────────────────┬─────────────────┬─────────────────────┐
│ Özellik          │ Legacy (_template)│ Composable          │
│                  │                   │ (_index_template)   │
├──────────────────┼─────────────────┼─────────────────────┤
│ Endpoint         │ _template        │ _index_template     │
│ Çakışma çözümü   │ order (merge)    │ priority (tek kazanır)│
│ Component support│ ❌               │ ✅                  │
│ Data streams     │ ❌               │ ✅                  │
│ Modülerlik       │ Düşük            │ Yüksek              │
│ Merge davranışı  │ Birden fazla     │ En yüksek priority  │
│                  │ template merge   │ tek template kazanır │
│ Durumu           │ Deprecated       │ Aktif, önerilen     │
└──────────────────┴─────────────────┴─────────────────────┘

⚠️ Dikkat: Legacy template ve composable template aynı index pattern'a sahipse, composable template her zaman kazanır. İkisini karıştırmayın — tüm template'lerinizi composable'a migrate edin.


2. Component Templates — Yeniden Kullanılabilir Parçalar

2.1 Component Template Nedir?

Component template, tek başına kullanılmayan ama composable template'lerin içinde yapı taşı (building block) olarak kullanılan şablonlardır. Lego parçaları gibi düşünün — tek başlarına anlamsız ama birleştirildiğinde güçlü yapılar oluştururlar.

Component Templates:
  [timestamp-mapping]  →  timestamp: date, @timestamp: date_nanos
  [log-settings]       →  shards:2, replicas:1, refresh:5s
  [security-fields]    →  user_id: keyword, ip_address: ip, session: keyword

Composable Template:
  logs-template = [timestamp-mapping] + [log-settings] + [security-fields] + ekstra ayarlar
  metrics-template = [timestamp-mapping] + [log-settings] + ekstra ayarlar
  audit-template = [timestamp-mapping] + [security-fields] + ekstra ayarlar

2.2 Component Template Oluşturma

// Component 1: Timestamp alanları
PUT _component_template/timestamp-mapping
{
  "template": {
    "mappings": {
      "properties": {
        "timestamp": {
          "type": "date",
          "format": "yyyy-MM-dd'T'HH:mm:ss.SSSZ||epoch_millis"
        },
        "@timestamp": {
          "type": "date"
        }
      }
    }
  },
  "_meta": {
    "description": "Ortak timestamp field'ları",
    "version": 1
  }
}

// Component 2: Log ayarları
PUT _component_template/log-settings
{
  "template": {
    "settings": {
      "number_of_shards": 2,
      "number_of_replicas": 1,
      "refresh_interval": "5s",
      "codec": "best_compression"
    }
  },
  "_meta": {
    "description": "Log index'leri için optimize edilmiş ayarlar"
  }
}

// Component 3: Güvenlik alanları
PUT _component_template/security-fields
{
  "template": {
    "mappings": {
      "properties": {
        "user_id": { "type": "keyword" },
        "ip_address": { "type": "ip" },
        "session_id": { "type": "keyword" },
        "user_agent": {
          "type": "text",
          "fields": {
            "keyword": { "type": "keyword", "ignore_above": 256 }
          }
        }
      }
    }
  }
}

// Component 4: Log-spesifik alanlar
PUT _component_template/log-fields
{
  "template": {
    "mappings": {
      "properties": {
        "level": {
          "type": "keyword"
        },
        "logger": {
          "type": "keyword"
        },
        "message": {
          "type": "text",
          "fields": {
            "keyword": {
              "type": "keyword",
              "ignore_above": 1024
            }
          }
        },
        "stack_trace": {
          "type": "text",
          "index": false
        },
        "thread_name": {
          "type": "keyword"
        }
      }
    }
  }
}

2.3 Component Template'leri Birleştirme

// Composable template — component'leri birleştir
PUT _index_template/app-logs
{
  "index_patterns": ["app-logs-*"],
  "priority": 200,
  "composed_of": [
    "timestamp-mapping",
    "log-settings",
    "security-fields",
    "log-fields"
  ],
  "template": {
    "settings": {
      "index.lifecycle.name": "logs-ilm-policy",
      "index.lifecycle.rollover_alias": "app-logs"
    },
    "aliases": {
      "searchable-logs": {}
    }
  },
  "_meta": {
    "description": "Uygulama logları için composable template",
    "version": 2
  }
}

Birleştirme sırası:

  1. composed_of listesindeki component'ler sırayla uygulanır

  2. Sonraki component, öncekinin aynı adlı field'ını override eder

  3. En son, composable template'in kendi template bloğu uygulanır ve her şeyin üstüne yazar

Uygulama Sırası:
  timestamp-mapping → log-settings → security-fields → log-fields → template (override)
  Sol → Sağ: Sağdaki aynı field'ı override eder

2.4 Component Template Listeleme ve İnceleme

// Tüm component template'leri listele
GET _component_template

// Belirli bir component template'i incele
GET _component_template/timestamp-mapping

// Pattern ile filtreleme
GET _component_template/log-*

// Bir composable template'in son halini simüle et
POST _index_template/_simulate/app-logs

// Belirli bir index adı için hangi template uygulanacağını simüle et
POST _index_template/_simulate_index/app-logs-2024.02.27

Simulate API çok değerlidir — template'lerinizin beklediğiniz gibi merge edildiğini doğrulamak için kullanın:

POST _index_template/_simulate_index/app-logs-2024.02.27

// Yanıt — birleştirilmiş son hali gösterir:
{
  "template": {
    "settings": {
      "index": {
        "number_of_shards": "2",
        "number_of_replicas": "1",
        "refresh_interval": "5s",
        "codec": "best_compression",
        "lifecycle": {
          "name": "logs-ilm-policy",
          "rollover_alias": "app-logs"
        }
      }
    },
    "mappings": {
      "properties": {
        "timestamp": { "type": "date", "format": "yyyy-MM-dd'T'HH:mm:ss.SSSZ||epoch_millis" },
        "@timestamp": { "type": "date" },
        "user_id": { "type": "keyword" },
        "ip_address": { "type": "ip" },
        "level": { "type": "keyword" },
        "message": { "type": "text" }
      }
    },
    "aliases": {
      "searchable-logs": {}
    }
  }
}

3. Template Priority ve Çakışma Yönetimi

3.1 Priority Kuralları

Composable template'lerde priority değeri çakışmaları çözer. En yüksek priority kazanır ve sadece o template uygulanır (merge yok):

// Genel log template — düşük priority
PUT _index_template/generic-logs
{
  "index_patterns": ["logs-*"],
  "priority": 100,
  "template": {
    "settings": { "number_of_shards": 1 }
  }
}

// Spesifik app log template — yüksek priority
PUT _index_template/app-logs
{
  "index_patterns": ["logs-app-*"],
  "priority": 200,
  "template": {
    "settings": { "number_of_shards": 3 }
  }
}
logs-system-2024.01  → generic-logs (priority 100) uygulanır → 1 shard
logs-app-2024.01     → app-logs (priority 200) uygulanır → 3 shard
                       (generic-logs da eşleşir ama priority düşük → uygulanmaz)

⚠️ Dikkat: Legacy template'lerde birden fazla eşleşen template merge edilirdi. Composable template'lerde ise sadece en yüksek priority'li tek template uygulanır, diğerleri göz ardı edilir. Bu önemli bir davranış farkıdır.

3.2 Aynı Priority Çakışması

İki composable template aynı priority ve aynı index pattern'a sahipse, Elasticsearch hata verir:

// Bu hata verir!
PUT _index_template/template-a
{
  "index_patterns": ["logs-*"],
  "priority": 100,
  "template": { "settings": { "number_of_shards": 1 } }
}

PUT _index_template/template-b
{
  "index_patterns": ["logs-*"],
  "priority": 100,
  "template": { "settings": { "number_of_shards": 2 } }
}

// Yanıt: "multiple index templates match... with the same priority [100]"

4. Data Streams — Zaman Serisi Verileri

4.1 Data Stream Nedir?

Data stream, zaman serisi verileri (log, metrik, event) için özel olarak tasarlanmış bir soyutlama katmanıdır. Bir data stream:

  • Arka planda birden fazla backing index oluşturur

  • Otomatik rollover yapar (belirli boyut/yaş sınırına ulaşınca yeni index)

  • Append-only yapıdadır — doğrudan güncelleme/silme yapılamaz

Data Stream: logs-app

  logs-app → .ds-logs-app-2024.01.01-000001  (backing index - eski)
           → .ds-logs-app-2024.01.15-000002  (backing index)
           → .ds-logs-app-2024.02.01-000003  (backing index - güncel, yazma buraya)

  Okuma: Tüm backing index'lerden
  Yazma: Sadece en son backing index'e

4.2 Data Stream Oluşturma

Data stream oluşturmak için önce bir composable template gerekir:

// 1. Component template'ler (opsiyonel ama önerilen)
PUT _component_template/ds-log-mappings
{
  "template": {
    "mappings": {
      "properties": {
        "@timestamp": { "type": "date" },
        "level": { "type": "keyword" },
        "message": { "type": "text" },
        "service": { "type": "keyword" },
        "host": { "type": "keyword" }
      }
    }
  }
}

PUT _component_template/ds-log-settings
{
  "template": {
    "settings": {
      "number_of_shards": 2,
      "number_of_replicas": 1,
      "refresh_interval": "5s"
    }
  }
}

// 2. Composable template — data_stream özelliği açık
PUT _index_template/logs-ds-template
{
  "index_patterns": ["logs-ds-*"],
  "data_stream": {},
  "priority": 200,
  "composed_of": ["ds-log-mappings", "ds-log-settings"],
  "template": {
    "settings": {
      "index.lifecycle.name": "logs-lifecycle"
    }
  }
}

⚠️ Dikkat: Data stream template'i oluştururken "data_stream": {} bloğu zorunludur. Ayrıca mapping'de @timestamp field'ı olmalıdır — bu data stream'lerin zorunlu alanıdır.

// 3. Data stream otomatik oluşur — ilk dokümanı yazınca
POST logs-ds-app/_doc
{
  "@timestamp": "2024-02-27T10:30:00Z",
  "level": "ERROR",
  "message": "Database connection timeout",
  "service": "payment-service",
  "host": "prod-server-01"
}

// Veya açıkça oluştur
PUT _data_stream/logs-ds-app

4.3 Data Stream ile Çalışma

// Arama — tüm backing index'lerde arar
GET logs-ds-app/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "level": "ERROR" } }
      ],
      "filter": [
        { "range": { "@timestamp": { "gte": "now-1h" } } }
      ]
    }
  }
}

// Data stream bilgisi
GET _data_stream/logs-ds-app

// Yanıt:
{
  "data_streams": [{
    "name": "logs-ds-app",
    "timestamp_field": { "name": "@timestamp" },
    "indices": [
      { "index_name": ".ds-logs-ds-app-2024.01.01-000001", "index_uuid": "..." },
      { "index_name": ".ds-logs-ds-app-2024.02.01-000002", "index_uuid": "..." }
    ],
    "generation": 2,
    "status": "GREEN",
    "template": "logs-ds-template"
  }]
}

4.4 Data Stream'de Güncelleme ve Silme

Data stream'ler append-only'dir. Ancak _update_by_query ve _delete_by_query ile backing index üzerinden işlem yapabilirsiniz:

// Delete by query — data stream'de doğrudan DELETE çalışmaz
POST logs-ds-app/_delete_by_query
{
  "query": {
    "range": {
      "@timestamp": {
        "lte": "2024-01-01"
      }
    }
  }
}

// Update by query
POST logs-ds-app/_update_by_query
{
  "query": {
    "term": { "level": "WARN" }
  },
  "script": {
    "source": "ctx._source.level = 'WARNING'"
  }
}

5. Rollover API — Otomatik Index Geçişi

5.1 Rollover Nedir?

Rollover, mevcut index belirli koşulları sağladığında (boyut, doküman sayısı, yaş) otomatik olarak yeni bir index oluşturma mekanizmasıdır.

5.2 Alias-Based Rollover (Geleneksel)

// 1. İlk index'i oluştur (rollover alias ile)
PUT logs-000001
{
  "aliases": {
    "logs-write": {
      "is_write_index": true
    },
    "logs-read": {}
  },
  "settings": {
    "number_of_shards": 2
  }
}

// 2. Rollover koşullarını tanımla ve çalıştır
POST logs-write/_rollover
{
  "conditions": {
    "max_age": "7d",
    "max_docs": 10000000,
    "max_size": "50gb",
    "max_primary_shard_size": "25gb"
  }
}

Rollover sonucu:

{
  "acknowledged": true,
  "shards_acknowledged": true,
  "old_index": "logs-000001",
  "new_index": "logs-000002",
  "rolled_over": true,
  "dry_run": false,
  "conditions": {
    "[max_size: 50gb]": true,
    "[max_age: 7d]": false,
    "[max_docs: 10000000]": false,
    "[max_primary_shard_size: 25gb]": true
  }
}

Koşullar OR mantığıyla çalışır — herhangi biri sağlanırsa rollover gerçekleşir.

5.3 Data Stream Rollover

Data stream kullanıyorsanız rollover daha kolaydır:

// Manuel rollover
POST logs-ds-app/_rollover

// Koşullu rollover
POST logs-ds-app/_rollover
{
  "conditions": {
    "max_primary_shard_size": "50gb",
    "max_age": "7d"
  }
}

💡 İpucu: Production'da rollover'ı manuel çalıştırmazsınız. ILM policy tanımlarsınız ve Elasticsearch otomatik olarak rollover yapar.


6. Index Lifecycle Management (ILM)

6.1 ILM Nedir?

ILM, bir index'in yaşam döngüsünü otomatik yöneten bir politikadır. Index'in "yaşına" veya "boyutuna" göre farklı fazlara geçirir:

Index Yaşam Döngüsü:
┌────────┐    ┌────────┐    ┌────────┐    ┌────────┐    ┌────────┐
│  HOT   │ →  │  WARM  │ →  │  COLD  │ →  │ FROZEN │ →  │ DELETE │
│        │    │        │    │        │    │        │    │        │
│Yazma + │    │Salt    │    │Nadir   │    │Arşiv   │    │Sil     │
│Okuma   │    │okunur  │    │erişim  │    │erişim  │    │        │
│SSD     │    │HDD     │    │HDD     │    │S3/MinIO│    │        │
│2 rep   │    │1 rep   │    │0 rep   │    │0 rep   │    │        │
└────────┘    └────────┘    └────────┘    └────────┘    └────────┘
   7 gün         30 gün       90 gün        365 gün      730 gün

6.2 ILM Policy Oluşturma

PUT _ilm/policy/logs-lifecycle
{
  "policy": {
    "phases": {
      "hot": {
        "min_age": "0ms",
        "actions": {
          "rollover": {
            "max_primary_shard_size": "50gb",
            "max_age": "7d",
            "max_docs": 50000000
          },
          "set_priority": {
            "priority": 100
          }
        }
      },
      "warm": {
        "min_age": "30d",
        "actions": {
          "shrink": {
            "number_of_shards": 1
          },
          "forcemerge": {
            "max_num_segments": 1
          },
          "set_priority": {
            "priority": 50
          },
          "allocate": {
            "number_of_replicas": 1,
            "require": {
              "data": "warm"
            }
          }
        }
      },
      "cold": {
        "min_age": "90d",
        "actions": {
          "set_priority": {
            "priority": 0
          },
          "allocate": {
            "number_of_replicas": 0,
            "require": {
              "data": "cold"
            }
          },
          "freeze": {}
        }
      },
      "delete": {
        "min_age": "365d",
        "actions": {
          "delete": {}
        }
      }
    }
  }
}

6.3 ILM Policy'yi Template'e Bağlama

// Component template ile ILM bağlama
PUT _component_template/ilm-settings
{
  "template": {
    "settings": {
      "index.lifecycle.name": "logs-lifecycle"
    }
  }
}

// Composable template'te kullan
PUT _index_template/managed-logs
{
  "index_patterns": ["managed-logs-*"],
  "data_stream": {},
  "priority": 300,
  "composed_of": [
    "timestamp-mapping",
    "log-settings",
    "ilm-settings"
  ]
}

6.4 ILM Durum İzleme

// Bir index'in ILM durumunu kontrol et
GET managed-logs-000001/_ilm/explain

// Yanıt:
{
  "indices": {
    "managed-logs-000001": {
      "index": "managed-logs-000001",
      "managed": true,
      "policy": "logs-lifecycle",
      "phase": "hot",
      "phase_time_millis": 1708000000000,
      "action": "complete",
      "step": "complete",
      "age": "15d"
    }
  }
}

// ILM hata durumunu kontrol et
GET managed-logs-*/_ilm/explain?only_errors=true

// ILM retry (hata sonrası tekrar dene)
POST managed-logs-000001/_ilm/retry

7. Java ile Template Yönetimi

7.1 Component Template Oluşturma

public class TemplateManager {
    private final ElasticsearchClient client;

    public TemplateManager(ElasticsearchClient client) {
        this.client = client;
    }

    // Component template oluştur
    public void createTimestampComponent() throws IOException {
        PutComponentTemplateRequest request = PutComponentTemplateRequest.of(p -> p
            .name("timestamp-mapping")
            .template(t -> t
                .mappings(m -> m
                    .properties("@timestamp", prop -> prop
                        .date(d -> d.format("yyyy-MM-dd'T'HH:mm:ss.SSSZ||epoch_millis"))
                    )
                    .properties("timestamp", prop -> prop
                        .date(d -> d)
                    )
                )
            )
            .meta("description", JsonData.of("Ortak timestamp field'ları"))
            .meta("version", JsonData.of(1))
        );

        client.cluster().putComponentTemplate(request);
        System.out.println("Component template 'timestamp-mapping' created");
    }

    // Settings component
    public void createLogSettingsComponent() throws IOException {
        PutComponentTemplateRequest request = PutComponentTemplateRequest.of(p -> p
            .name("log-settings")
            .template(t -> t
                .settings(s -> s
                    .numberOfShards("2")
                    .numberOfReplicas("1")
                    .refreshInterval(ri -> ri.time("5s"))
                )
            )
        );

        client.cluster().putComponentTemplate(request);
    }
}

7.2 Composable Template Oluşturma

public void createComposableTemplate() throws IOException {
    PutIndexTemplateRequest request = PutIndexTemplateRequest.of(p -> p
        .name("app-logs-template")
        .indexPatterns("app-logs-*")
        .composedOf("timestamp-mapping", "log-settings")
        .priority(200)
        .template(t -> t
            .mappings(m -> m
                .properties("level", prop -> prop.keyword(k -> k))
                .properties("message", prop -> prop.text(tx -> tx
                    .fields("keyword", f -> f.keyword(k -> k.ignoreAbove(1024)))
                ))
                .properties("service", prop -> prop.keyword(k -> k))
            )
            .aliases("all-app-logs", a -> a)
        )
    );

    client.indices().putIndexTemplate(request);
    System.out.println("Composable template 'app-logs-template' created");
}

7.3 Data Stream Template ve Kullanımı

// Data stream template oluştur
public void createDataStreamTemplate() throws IOException {
    PutIndexTemplateRequest request = PutIndexTemplateRequest.of(p -> p
        .name("ds-app-logs")
        .indexPatterns("ds-app-logs-*")
        .dataStream(ds -> ds)   // Data stream aktif
        .priority(300)
        .composedOf("timestamp-mapping", "log-settings")
        .template(t -> t
            .settings(s -> s
                .index(i -> i.lifecycle(l -> l.name("logs-lifecycle")))
            )
        )
    );

    client.indices().putIndexTemplate(request);
}

// Data stream'e doküman yazma
public void indexToDataStream() throws IOException {
    Map<String, Object> document = new HashMap<>();
    document.put("@timestamp", "2024-02-27T10:30:00Z");
    document.put("level", "ERROR");
    document.put("message", "Connection timeout");
    document.put("service", "payment-service");

    IndexRequest<Map<String, Object>> request = IndexRequest.of(i -> i
        .index("ds-app-logs-prod")
        .document(document)
    );

    IndexResponse response = client.index(request);
    System.out.println("Indexed to: " + response.index());
    // Çıktı: Indexed to: .ds-ds-app-logs-prod-2024.02.27-000001
}

7.4 Template Simulate

// Template simulate — birleştirilmiş son hali gör
public void simulateTemplate(String indexName) throws IOException {
    SimulateIndexTemplateRequest request = SimulateIndexTemplateRequest.of(s -> s
        .name(indexName)
    );

    SimulateIndexTemplateResponse response = client.indices().simulateIndexTemplate(request);

    // Overlay template bilgisi
    System.out.println("Template applied: " + response.template());
    System.out.println("Overlapping: " + response.overlapping());
}

8. İleri Template Teknikleri

8.1 Dynamic Templates

Template'ler içinde dynamic template tanımlayarak, bilinmeyen field'ların nasıl mapping'leneceğini kontrol edebilirsiniz:

PUT _component_template/dynamic-rules
{
  "template": {
    "mappings": {
      "dynamic_templates": [
        {
          "strings_as_keywords": {
            "match_mapping_type": "string",
            "mapping": {
              "type": "keyword",
              "ignore_above": 256
            }
          }
        },
        {
          "long_fields_as_integer": {
            "match_mapping_type": "long",
            "mapping": {
              "type": "integer"
            }
          }
        },
        {
          "unindexed_longs": {
            "match": "metric_*",
            "mapping": {
              "type": "long",
              "index": false
            }
          }
        },
        {
          "text_with_keyword": {
            "match": "*_text",
            "mapping": {
              "type": "text",
              "fields": {
                "keyword": { "type": "keyword" }
              }
            }
          }
        }
      ]
    }
  }
}

8.2 Runtime Fields ile Template

Runtime field'lar index-time'da değil search-time'da hesaplanır. Template'lerde tanımlanabilir:

PUT _component_template/runtime-fields
{
  "template": {
    "mappings": {
      "runtime": {
        "day_of_week": {
          "type": "keyword",
          "script": {
            "source": "emit(doc['@timestamp'].value.dayOfWeekEnum.getDisplayName(TextStyle.FULL, Locale.ROOT))"
          }
        },
        "message_length": {
          "type": "long",
          "script": {
            "source": "emit(doc['message.keyword'].value.length())"
          }
        }
      }
    }
  }
}

8.3 Index Alias Stratejileri

Template'lerde alias tanımlayarak arama ve yazma işlemlerini soyutlayabilirsiniz:

PUT _index_template/multi-alias-template
{
  "index_patterns": ["orders-*"],
  "priority": 100,
  "template": {
    "aliases": {
      "orders-all": {},
      "orders-search": {
        "filter": {
          "term": { "status": "active" }
        }
      },
      "orders-recent": {
        "filter": {
          "range": {
            "@timestamp": { "gte": "now-30d" }
          }
        }
      }
    }
  }
}

9. Yaygın Hatalar ve Best Practices

9.1 Yaygın Hatalar

Hata 1: Legacy ve composable template'leri karıştırmak

// ❌ YANLIŞ — Aynı pattern'a hem legacy hem composable template
PUT _template/logs-old          // Legacy
PUT _index_template/logs-new    // Composable

// Composable her zaman kazanır! Legacy'nin varlığından habersiz olabilirsiniz.
// Çözüm: Tüm legacy template'leri silin
DELETE _template/logs-old

Hata 2: Component template sırasını yanlış yapmak

// composed_of sırası ÖNEMLİ!
"composed_of": ["base-settings", "override-settings"]
// override-settings, base-settings'in aynı adlı ayarlarını ezer

Hata 3: Data stream'de @timestamp unutmak

// ❌ Data stream template'inde @timestamp yoksa hata alırsınız
// ✅ @timestamp field'ı zorunlu

9.2 Best Practices

✅ YAP:
  • Component template'leri küçük ve tek amaçlı tut
  • Template'leri version'la (_meta.version kullanarak)
  • Simulate API ile doğrula
  • Data stream'leri zaman serisi verileri için kullan
  • ILM policy'yi template'e bağla
  • Priority'leri mantıklı aralıklarla belirle (100, 200, 300...)

❌ YAPMA:
  • Legacy template kullanma (deprecated)
  • Aynı priority'de çakışan pattern'lar oluşturma
  • Component template'leri gereksiz yere büyütme
  • Force merge'ı aktif index'lerde yapma
  • ILM olmadan rollover yönetmeye çalışma

10. Özet

  • Legacy template'ler (_template) deprecated — composable template'lere (_index_template) geçin

  • Component template'ler yeniden kullanılabilir yapı taşlarıdır. Mapping, settings ve alias parçalarını modüler olarak paylaşın

  • Composable template'lerde çakışma, priority ile çözülür — en yüksek priority tek başına kazanır, merge yoktur

  • Data stream'ler zaman serisi verileri için idealdir: otomatik backing index yönetimi, append-only yapı, zorunlu @timestamp

  • Rollover API index boyutunu ve yaşını kontrol eder. ILM ile birlikte kullanarak tamamen otomatik yaşam döngüsü yönetimi sağlayın

  • ILM policy hot → warm → cold → frozen → delete fazlarını otomatik yönetir. Template'e bağlayarak her yeni index'in otomatik yönetilmesini sağlayın

  • Simulate API (_simulate_index) template birleşim sonucunu doğrulamak için vazgeçilmezdir — production'a deploy etmeden önce her zaman kullanın