Elasticsearch Nedir: Dağıtık Arama Motoruna Giriş

Bir sabah işe geldiniz ve müşteri destek ekibi size şikayet yağmuru başlattı: “Arama çalışmıyor, hiçbir şey bulamıyoruz, sistem çok yavaş!” Geleneksel SQL veritabanınızda LIKE '%arama_terimi%' sorguları çekiyorsunuz, milyonlarca kayıt var ve her sorgu sunucuyu dizüstü bilgisayar fanı gibi çalıştırıyor. İşte tam bu noktada Elasticsearch sahneye çıkıyor.

Elasticsearch, Apache Lucene üzerine inşa edilmiş, dağıtık bir arama ve analiz motorudur. 2010 yılında Shay Banon tarafından geliştirilen bu sistem, bugün Netflix, GitHub, Wikipedia ve daha pek çok büyük platformun altyapısında kritik bir rol oynuyor. Ama merak etmeyin, sadece devlere özgü bir araç değil. Orta ölçekli bir e-ticaret sitesinden log yönetim sistemine kadar her yerde kullanabilirsiniz.

Elasticsearch Ne Değildir

Çoğu geliştirici ve sysadmin ilk karşılaştığında Elasticsearch’ü “hızlı bir veritabanı” olarak düşünür. Bu tanım hem doğru hem yanlış. Elasticsearch birincil veri deposu olarak kullanılmamalıdır. Şöyle düşünün: asıl verileriniz PostgreSQL veya MongoDB’de durur, Elasticsearch ise bu verinin arama odaklı bir kopyasını tutar.

Elasticsearch şunları iyi yapar:

  • Tam metin arama (Full-text search): “laptop” yazınca “laptops”, “notebook” gibi sonuçları da getirebilmek
  • Log analizi: Milyarlarca log satırı arasında saniyeler içinde sorgu çalıştırmak
  • Gerçek zamanlı analitik: Dashboard’lar için hızlı agregasyon sorguları
  • Coğrafi sorgular: “Bana 5 km yakınındaki restoranları göster” tarzı sorgular
  • Öneri sistemleri: Otomatik tamamlama ve benzer içerik önerileri

Elasticsearch şunları iyi yapmaz:

  • ACID uyumlu transaction yönetimi
  • Karmaşık ilişkisel veri modelleri (JOIN’ler)
  • Birincil veri kaynağı olarak güvenilir veri saklama

Temel Kavramlar: Elasticsearch’ün Alfabesi

Elasticsearch’ü anlamak için birkaç temel terimi kafanıza oturtmanız gerekiyor.

Index, Document ve Field

Index, SQL’deki tablo kavramına en yakın yapıdır. Ama tam olarak aynı değil. Bir index, benzer yapıdaki belgelerin toplandığı bir koleksiyondur. Örneğin “products” index’i, “orders” index’i gibi.

Document, index içindeki her bir kayıttır ve JSON formatında saklanır. SQL’deki bir satır gibi düşünebilirsiniz ama çok daha esnek. Aynı index içindeki iki document birbirinden farklı alanlara sahip olabilir (buna schema-less denir, ama dikkatli kullanın).

Field, document içindeki her bir alan. Tıpkı SQL’deki sütun gibi.

Shard ve Replica

Bu iki kavram Elasticsearch’ü “dağıtık” yapan temel taşlardır.

Shard, bir index’in fiziksel olarak bölündüğü parçalardır. Diyelim ki 100 GB’lık bir index’iniz var ve 3 node’unuz var. Elasticsearch bu index’i 3 shard’a böler ve her node bir shard üstlenir. Böylece hem depolama hem de sorgu yükü dağıtılmış olur.

Replica, shard’ların kopyalarıdır. Bir shard’ın 1 replica’sı olduğunda, o shard’ın tam kopyası farklı bir node’da tutulur. Bu iki şey sağlar: yüksek erişilebilirlik (bir node çökerse data kaybolmaz) ve okuma performansı (replica’lardan da okuma yapılabilir).

Küçük bir kurulum için başlangıç önerisi: 1 primary shard + 1 replica. Büyük veri setleri için shard sayısını artırın ama bunu index oluşturmadan önce planlayın, çünkü sonradan primary shard sayısını değiştiremezsiniz.

Node ve Cluster

Node, Elasticsearch’ün çalıştığı tek bir sunucu instance’ıdır. Cluster, birden fazla node’un bir araya gelmesiyle oluşur. Cluster içindeki node’lar birbirini otomatik olarak keşfeder ve yük dengelemesini kendi aralarında yaparlar.

Elasticsearch Nasıl Çalışır: Analiz Süreci

Bir metin Elasticsearch’e eklendiğinde sihirli bir şey olur: analyzer devreye girer. Analyzer üç aşamadan oluşur:

Character Filter: Metni temizler. HTML etiketlerini kaldırır, özel karakterleri dönüştürür.

Tokenizer: Metni token’lara (parçalara) böler. “Elasticsearch harika bir araçtır” cümlesi “elasticsearch”, “harika”, “bir”, “araçtır” token’larına bölünür.

Token Filter: Token’ları dönüştürür. Küçük harfe çevirir, stop word’leri (“bir”, “ve”, “veya” gibi) kaldırır, köklerine indirir (stemming).

Bu analiz süreci sayesinde kullanıcı “ARAÇLAR” yazsa bile “araçtır” içeren bir document bulunabilir. İşte full-text search’ün gücü buradan geliyor.

Kurulum ve İlk Adımlar

Şimdi işin pratik kısmına geçelim. Ubuntu 22.04 üzerinde kurulum yapacağız.

# GPG anahtarını ekle
wget -qO - https://artifacts.elastic.co/GPG-KEY-elasticsearch | sudo gpg --dearmor -o /usr/share/keyrings/elasticsearch-keyring.gpg

# Repository ekle
echo "deb [signed-by=/usr/share/keyrings/elasticsearch-keyring.gpg] https://artifacts.elastic.co/packages/8.x/apt stable main" | sudo tee /etc/apt/sources.list.d/elastic-8.x.list

# Kur
sudo apt-get update && sudo apt-get install elasticsearch -y

# Servisi başlat ve otomatik başlatmayı aktif et
sudo systemctl daemon-reload
sudo systemctl enable elasticsearch
sudo systemctl start elasticsearch

Kurulum tamamlandıktan sonra /etc/elasticsearch/elasticsearch.yml dosyasına temel konfigürasyonu yapalım:

# /etc/elasticsearch/elasticsearch.yml

cluster.name: production-cluster
node.name: node-1

# Network ayarları
network.host: 0.0.0.0
http.port: 9200

# Discovery ayarları (tek node için)
discovery.type: single-node

# Veri ve log dizinleri
path.data: /var/lib/elasticsearch
path.logs: /var/log/elasticsearch

# Bellek lock (üretim ortamı için kritik)
bootstrap.memory_lock: true

# Güvenlik (production'da mutlaka açık olsun)
xpack.security.enabled: true

JVM heap size ayarı çok önemli. Genel kural: toplam RAM’in yarısını Elasticsearch’e ver ama 32 GB’ı geçme (Compressed Oops optimizasyonu kaybolur).

# /etc/elasticsearch/jvm.options.d/heap.options dosyası oluştur
sudo tee /etc/elasticsearch/jvm.options.d/heap.options << 'EOF'
-Xms4g
-Xmx4g
EOF

# Memory lock için sistem limiti
sudo tee /etc/systemd/system/elasticsearch.service.d/override.conf << 'EOF'
[Service]
LimitMEMLOCK=infinity
EOF

sudo systemctl daemon-reload
sudo systemctl restart elasticsearch

Kurulumun çalıştığını doğrulayalım:

# Cluster sağlık durumunu kontrol et
curl -X GET "localhost:9200/_cluster/health?pretty" 
  -H 'Content-Type: application/json'

# Beklenen çıktı (single-node için yellow normal, cluster için green hedefleyin)
# {
#   "cluster_name" : "production-cluster",
#   "status" : "green",
#   "number_of_nodes" : 1,
#   "number_of_data_nodes" : 1,
#   ...
# }

İlk Index’inizi Oluşturun

Hayali bir e-ticaret senaryosu üzerinden gidelim. Ürün arama sistemi kuruyoruz.

# Mapping ile birlikte index oluştur
curl -X PUT "localhost:9200/products" 
  -H 'Content-Type: application/json' 
  -d '{
    "settings": {
      "number_of_shards": 3,
      "number_of_replicas": 1,
      "analysis": {
        "analyzer": {
          "turkish_analyzer": {
            "type": "custom",
            "tokenizer": "standard",
            "filter": ["lowercase", "turkish_stop", "asciifolding"]
          }
        },
        "filter": {
          "turkish_stop": {
            "type": "stop",
            "stopwords": "_turkish_"
          }
        }
      }
    },
    "mappings": {
      "properties": {
        "name": {
          "type": "text",
          "analyzer": "turkish_analyzer"
        },
        "description": {
          "type": "text",
          "analyzer": "turkish_analyzer"
        },
        "price": {
          "type": "float"
        },
        "category": {
          "type": "keyword"
        },
        "stock": {
          "type": "integer"
        },
        "created_at": {
          "type": "date"
        }
      }
    }
  }'

Burada text ve keyword arasındaki fark kritik. text alanlar analyze edilir ve tam metin aramasında kullanılır. keyword alanlar ise tam eşleşme, sıralama ve agregasyon için kullanılır. Örneğin category alanında “Elektronik” yazıyorsa, keyword tipinde tam olarak “Elektronik” aramanız gerekir. Filtreleme ve gruplama için idealdir.

Şimdi birkaç ürün ekleyelim:

# Tek document ekle
curl -X POST "localhost:9200/products/_doc" 
  -H 'Content-Type: application/json' 
  -d '{
    "name": "Samsung Galaxy S24 Ultra",
    "description": "Gelişmiş yapay zeka özellikleri ile güçlü akıllı telefon",
    "price": 42999.99,
    "category": "Elektronik",
    "stock": 150,
    "created_at": "2024-01-15"
  }'

# Bulk API ile toplu ekleme (büyük veri setleri için tercih edilmeli)
curl -X POST "localhost:9200/products/_bulk" 
  -H 'Content-Type: application/json' 
  -d '
{"index": {}}
{"name": "Apple MacBook Pro M3", "description": "Profesyonel kullanım için güçlü laptop", "price": 89999.99, "category": "Bilgisayar", "stock": 45, "created_at": "2024-01-20"}
{"index": {}}
{"name": "Sony WH-1000XM5", "description": "Aktif gürültü önleme özellikli premium kulaklık", "price": 8999.99, "category": "Aksesuar", "stock": 230, "created_at": "2024-01-22"}
{"index": {}}
{"name": "Logitech MX Master 3S", "description": "Profesyonel kablosuz ergonomik mouse", "price": 2499.99, "category": "Aksesuar", "stock": 380, "created_at": "2024-01-25"}
'

Arama Sorguları: Query DSL

Elasticsearch’ün kalbi Query DSL’dir (Domain Specific Language). JSON tabanlı bu sorgulama dili son derece güçlüdür.

Temel Sorgular

# Match sorgusu - full text search
curl -X GET "localhost:9200/products/_search" 
  -H 'Content-Type: application/json' 
  -d '{
    "query": {
      "match": {
        "name": "akıllı telefon"
      }
    }
  }'

# Bool sorgusu - birden fazla koşulu birleştir
curl -X GET "localhost:9200/products/_search" 
  -H 'Content-Type: application/json' 
  -d '{
    "query": {
      "bool": {
        "must": [
          {"match": {"description": "profesyonel"}}
        ],
        "filter": [
          {"term": {"category": "Bilgisayar"}},
          {"range": {"price": {"gte": 10000, "lte": 100000}}}
        ],
        "must_not": [
          {"term": {"stock": 0}}
        ]
      }
    },
    "sort": [
      {"price": {"order": "asc"}}
    ],
    "from": 0,
    "size": 10
  }'

must: Kesinlikle eşleşmeli ve relevance score’u etkiler filter: Eşleşmeli ama score’u etkilemez, cache’lenir ve daha hızlıdır should: Eşleşirse score artar ama zorunlu değil must_not: Kesinlikle eşleşmemeli

Agregasyonlar

Elasticsearch’ün en güçlü özelliklerinden biri agregasyonlardır. Anlık analitik dashboard’lar için mükemmeldir.

# Kategori bazında ürün sayısı ve ortalama fiyat
curl -X GET "localhost:9200/products/_search" 
  -H 'Content-Type: application/json' 
  -d '{
    "size": 0,
    "aggs": {
      "by_category": {
        "terms": {
          "field": "category",
          "size": 10
        },
        "aggs": {
          "avg_price": {
            "avg": {"field": "price"}
          },
          "total_stock": {
            "sum": {"field": "stock"}
          }
        }
      }
    }
  }'

Bu sorgu size her kategori için ürün sayısı, ortalama fiyat ve toplam stok bilgisini milisaniyeler içinde verir. Aynı işi SQL’de yapmaya çalışsaydınız ve milyonlarca ürününüz olsaydı, sonuçta çok farklı bir tablo görürdünüz.

Gerçek Dünya Senaryosu: Log Yönetimi

Elasticsearch’ün en yaygın kullanım senaryolarından biri ELK Stack (Elasticsearch, Logstash, Kibana) ile log yönetimidir. Şöyle bir senaryo hayal edin: 50 sunucunuzdan her dakika binlerce log satırı geliyor. Bu logları merkezi bir yerde toplamak, aramak ve görselleştirmek istiyorsunuz.

Filebeat ile log gönderimi için temel konfigürasyon:

# /etc/filebeat/filebeat.yml (uygulama sunucusunda)
filebeat.inputs:
  - type: log
    enabled: true
    paths:
      - /var/log/nginx/access.log
      - /var/log/nginx/error.log
    tags: ["nginx", "production"]
    fields:
      environment: production
      server_role: web

  - type: log
    enabled: true
    paths:
      - /var/log/myapp/*.log
    tags: ["application"]
    multiline.pattern: '^d{4}-d{2}-d{2}'
    multiline.negate: true
    multiline.match: after

output.elasticsearch:
  hosts: ["elasticsearch-server:9200"]
  index: "logs-%{[fields.environment]}-%{+yyyy.MM.dd}"

setup.ilm.enabled: true
setup.ilm.rollover_alias: "logs"
setup.ilm.pattern: "{now/d}-000001"

Log index’leri zaman içinde devasa büyüklüklere ulaşabilir. Index Lifecycle Management (ILM) bu sorunu çözer: eski ve az kullanılan index’leri otomatik olarak sıkıştırır, soğuk depolamaya taşır veya siler.

Performans ve İzleme

Elasticsearch’ü kurmak bir şey, sağlıklı çalıştırmak başka bir şey. İzlemeniz gereken kritik metrikler var.

# Node istatistikleri
curl -X GET "localhost:9200/_nodes/stats?pretty" | 
  python3 -c "import sys,json; d=json.load(sys.stdin); 
  nodes=d['nodes']
  for nid,n in nodes.items():
    print(f"Node: {n['name']}")
    print(f"  Heap: {n['jvm']['mem']['heap_used_percent']}%")
    print(f"  CPU: {n['os']['cpu']['percent']}%")
    print(f"  Disk: {n['fs']['total']['available_in_bytes'] // (1024**3)} GB free")"

# Index istatistikleri
curl -X GET "localhost:9200/_cat/indices?v&h=index,docs.count,store.size,pri,rep&s=store.size:desc"

# Yavaş sorguları izle (slow log aktif et)
curl -X PUT "localhost:9200/products/_settings" 
  -H 'Content-Type: application/json' 
  -d '{
    "index.search.slowlog.threshold.query.warn": "10s",
    "index.search.slowlog.threshold.query.info": "5s",
    "index.search.slowlog.threshold.query.debug": "2s",
    "index.search.slowlog.threshold.fetch.warn": "1s",
    "index.indexing.slowlog.threshold.index.warn": "10s"
  }'

İzlemeniz gereken kritik durumlar:

  • Heap kullanımı %85’i geçince: JVM garbage collection baskısı artar, performans düşer
  • Cluster status “red”: Bazı primary shard’lar erişilemez, veri kaybı riski var
  • Cluster status “yellow”: Replica shard’lar atanamamış, genelde node eksikliğinden
  • Disk %85 doluluk: Elasticsearch otomatik olarak index’leri read-only moda alır
  • Search thread pool rejection: Sorgu yükü işlenebilir kapasiteyi aşıyor

Güvenlik: Üretim Öncesi Yapılması Gerekenler

Elasticsearch 8.x ile birlikte güvenlik özellikleri varsayılan olarak açık geldi. Ama yine de yapılandırmanız gereken bazı şeyler var.

# Elasticsearch güvenlik kurulumu
sudo /usr/share/elasticsearch/bin/elasticsearch-setup-passwords auto

# Bu komut tüm dahili kullanıcılar için rastgele şifre üretir:
# elastic, kibana_system, logstash_system, beats_system, apm_system, remote_monitoring_user

# Üretilen şifreleri güvenli bir yerde saklayın!

# Özel kullanıcı oluştur (elastic superuser şifresi gerekli)
curl -X POST "localhost:9200/_security/user/app_user" 
  -u elastic:ELASTIC_SIFRENIZ 
  -H 'Content-Type: application/json' 
  -d '{
    "password": "guclu_bir_sifre_123",
    "roles": ["products_read_write"],
    "full_name": "Uygulama Kullanicisi"
  }'

# Özel role oluştur (minimum yetki prensibi)
curl -X POST "localhost:9200/_security/role/products_read_write" 
  -u elastic:ELASTIC_SIFRENIZ 
  -H 'Content-Type: application/json' 
  -d '{
    "indices": [{
      "names": ["products*"],
      "privileges": ["read", "write", "create_index"]
    }]
  }'

Network seviyesinde güvenlik için Nginx reverse proxy kullanmak iyi bir pratiktir. İnternete direkt 9200 portunu açmayın.

Yedekleme ve Felaket Kurtarma

Elasticsearch’ün snapshot mekanizması yedekleme için kullanılır. S3, GCS, Azure Blob Storage veya shared filesystem kullanabilirsiniz.

# Snapshot repository kaydet (NFS paylaşımlı dizin örneği)
curl -X PUT "localhost:9200/_snapshot/backup_repo" 
  -H 'Content-Type: application/json' 
  -d '{
    "type": "fs",
    "settings": {
      "location": "/mnt/elasticsearch-backups",
      "compress": true,
      "max_snapshot_bytes_per_sec": "100mb",
      "max_restore_bytes_per_sec": "200mb"
    }
  }'

# Manuel snapshot al
curl -X PUT "localhost:9200/_snapshot/backup_repo/snapshot_$(date +%Y%m%d_%H%M%S)?wait_for_completion=true" 
  -H 'Content-Type: application/json' 
  -d '{
    "indices": "products,orders,customers",
    "ignore_unavailable": true,
    "include_global_state": false
  }'

# Mevcut snapshot'ları listele
curl -X GET "localhost:9200/_snapshot/backup_repo/_all?pretty"

# Snapshot'tan geri yükle
curl -X POST "localhost:9200/_snapshot/backup_repo/snapshot_20240115_030000/_restore" 
  -H 'Content-Type: application/json' 
  -d '{
    "indices": "products",
    "rename_pattern": "(.+)",
    "rename_replacement": "restored_$1"
  }'

Otomatik snapshot için cron job kurun:

# /usr/local/bin/es-backup.sh
#!/bin/bash
SNAPSHOT_NAME="scheduled_$(date +%Y%m%d_%H%M%S)"
REPO="backup_repo"
ES_HOST="localhost:9200"
LOG_FILE="/var/log/elasticsearch/backup.log"

echo "$(date): Snapshot başlıyor: $SNAPSHOT_NAME" >> $LOG_FILE

RESULT=$(curl -s -X PUT "$ES_HOST/_snapshot/$REPO/$SNAPSHOT_NAME?wait_for_completion=true" 
  -H 'Content-Type: application/json' 
  -d '{"include_global_state": false}')

if echo $RESULT | grep -q '"state":"SUCCESS"'; then
  echo "$(date): Snapshot başarılı: $SNAPSHOT_NAME" >> $LOG_FILE
else
  echo "$(date): HATA - Snapshot başarısız: $RESULT" >> $LOG_FILE
  # Buraya alert mekanizmanızı ekleyin (slack webhook, pagerduty vb.)
fi

# 30 günden eski snapshot'ları sil
OLD_SNAPSHOTS=$(curl -s "$ES_HOST/_snapshot/$REPO/_all" | 
  python3 -c "import sys,json,time; d=json.load(sys.stdin);
  cutoff=(time.time()-30*86400)*1000
  [print(s['snapshot']) for s in d['snapshots'] if s['start_time_in_millis']<cutoff]")

for snapshot in $OLD_SNAPSHOTS; do
  curl -s -X DELETE "$ES_HOST/_snapshot/$REPO/$snapshot"
  echo "$(date): Eski snapshot silindi: $snapshot" >> $LOG_FILE
done
# Crontab'a ekle (her gece 3'te çalış)
echo "0 3 * * * root /usr/local/bin/es-backup.sh" > /etc/cron.d/elasticsearch-backup
chmod +x /usr/local/bin/es-backup.sh

Sonuç

Elasticsearch, doğru anlaşıldığında ve doğru kullanıldığında ciddi bir güç çarpanı olabilir. Yanlış anlaşıldığında ise bakımı zor, kaynak tüketen ve güvenlik açığı yaratan bir kabus haline gelebilir.

Buradan almanız gereken en önemli mesajlar şunlar:

  • Elasticsearch’ü birincil veritabanı olarak kullanmayın, asıl verilerinizi başka bir yerde tutun
  • Üretim ortamına almadan önce güvenlik yapılandırmasını tamamlayın, 9200 portunu internete açık bırakmayın
  • JVM heap boyutunu doğru ayarlayın ve memory lock’u etkinleştirin
  • Snapshot rutinlerinizi kurun ve düzenli olarak test edin (geri yüklemeyi denemediyseniz yedeğiniz yoktur)
  • Cluster sağlığını ve disk kullanımını mutlaka izleyin
  • Index mapping’lerini baştan doğru tasarlayın, sonradan değiştirmek bazen index’i yeniden oluşturmayı gerektirir

Bir sonraki yazıda Kibana kurulumu ve Discover, Dashboard özelliklerini ele alacağız. ELK Stack’in görsel yüzüyle tanışınca Elasticsearch’ün ham gücü çok daha anlamlı hale geliyor. O zamana kadar, deneyin ve kırmaktan korkmayın; test ortamı bunun için var.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir