Elasticsearch'e Python, Node.js ve Java istemcileriyle bağlanmak

Selamlar, bu yazımda Elasticsearch'e farklı dillerden nasıl bağlanacağımıza bakacağız. Kavramlardan çok pratik tarafa odaklanalım çünkü 'cluster ayakta, index hazır, peki şimdi uygulamadan nasıl konuşacağım?' sorusu en çok burada takılıyor. Üç dili de göreceğiz: Python, Node.js, Java.

İlk açıklığa kavuşturalım: hepsinde resmi istemci kullanın. requests ile JSON yollayıp idare etmeye çalışmak ilk gün şirin durur, ama serialization, retry, sniffing, version uyumu derken işin içinden çıkamazsınız. Resmi istemciler bu işleri sizin yerinize hallediyor.

Python istemcisi

Kurulum klasik:

pip install elasticsearch

Asgari bir bağlantı şöyle:

from elasticsearch import Elasticsearch

es = Elasticsearch(
    'https://localhost:9200',
    basic_auth=('elastic', 'parolaniz'),
    ca_certs='/path/to/ca.crt',
    request_timeout=30,
    max_retries=3,
    retry_on_timeout=True,
)

print(es.info()['cluster_name'])

Üç şeye dikkat: verify_certs=False'u sadece localhost'ta deneyin. Prod'da CA dosyasını verin. request_timeout defaultu 10 saniye, ağır query'lerde yetmez. max_retries ile retry_on_timeout'u beraber set etmezseniz retry'lar çoğu durumda devreye girmez.

Çok belge basacaksanız tek tek es.index() çağırmayın. helpers.bulk Türk geliştiricinin en sık atladığı kısım:

from elasticsearch.helpers import bulk

docs = (
    {'_index': 'makaleler', '_id': i, '_source': {'baslik': f'Yazi {i}', 'goruntulenme': i * 10}}
    for i in range(1, 10001)
)

success, failed = bulk(es, docs, chunk_size=500, stats_only=True)
print(f'Basarili: {success}, basarisiz: {failed}')

Tek tek index'leme ile bulk arasında benim ölçtüğüm fark genellikle 20-50 kat. chunk_size'ı belge boyutuna göre ayarlayın; 500 ortalama metinler için iyi bir başlangıç.

Node.js istemcisi

npm install @elastic/elasticsearch

Bağlantı tarafı:

const { Client } = require('@elastic/elasticsearch');
const fs = require('fs');

const client = new Client({
  node: 'https://localhost:9200',
  auth: { username: 'elastic', password: 'parolaniz' },
  tls: { ca: fs.readFileSync('/path/to/ca.crt') },
  maxRetries: 3,
  requestTimeout: 30000,
  compression: true,
});

const info = await client.info();
console.log(info.cluster_name);

compression: true küçük bir ayar ama bandwidth'iniz uzaksa geri dönüşü çok iyi. Bulk tarafında payload yapısı Python'dakinden farklı; iki satırlık çiftler halinde gidiyor:

const ops = [];
for (let i = 1; i <= 1000; i++) {
  ops.push({ index: { _index: 'makaleler', _id: String(i) } });
  ops.push({ baslik: `Yazi ${i}`, goruntulenme: i * 10 });
}

const res = await client.bulk({ refresh: false, operations: ops });
if (res.errors) {
  // hatali itemları gez, sessiz gecme
  res.items.forEach((it, i) => it.index?.error && console.error(i, it.index.error));
}

refresh: true'yu prod'da otomatik açmayın - her bulk'tan sonra segment refresh write performansını yere yapıştırır.

Java istemcisi

Java tarafı biraz daha tören istiyor. Maven'da:

<dependency>
  <groupId>co.elastic.clients</groupId>
  <artifactId>elasticsearch-java</artifactId>
  <version>8.12.0</version>
</dependency>

Minimum auth'lu bağlantı:

RestClient rest = RestClient.builder(new HttpHost("localhost", 9200, "https"))
    .setHttpClientConfigCallback(b -> b.setDefaultCredentialsProvider(creds))
    .build();

ElasticsearchTransport transport = new RestClientTransport(rest, new JacksonJsonpMapper());
ElasticsearchClient client = new ElasticsearchClient(transport);

var info = client.info();
System.out.println(info.clusterName());

creds'i BasicCredentialsProvider ile kurmanız gerekiyor; SSLContext'i de elle inşa edeceksiniz. Spring Boot kullanıyorsanız spring-boot-starter-data-elasticsearch bu kalıbı bir miktar saklıyor, ama altta yatan istemci yine bu.

Sık karşılaşılan tuzaklar

  • verify_certs=False ile prod'a çıkmak: Geliştirme modunu unutup canlıya bırakırsanız MITM'e açık olursunuz. CA path'i config'den okuyun, dev profilde gevşetin.
  • Tek tek index'leme: 10.000 belgeyi for döngüsünde index() ile basıyorsanız ya cluster'ı yıpratıyorsunuz ya da inanılmaz yavaş çalışıyorsunuz. Bulk her zaman.
  • Timeout'ları default bırakmak: Türkiye'den bir AWS Frankfurt cluster'ına bağlanıyorsanız 10 saniye bazen yetmez. 30 saniye ve retry_on_timeout makul başlangıç.
  • refresh=true her yazımda: Hızlı arama için cazip ama write throughput'unu uçuruma atar. Sadece testte kullanın.
  • API key yerine basic auth: Production'da kullanıcı/parola yerine API key kullanın, scope'u dar tutun.

Kapanış

Üç dilde de istemci kurulumu kavramsal olarak aynı: bağlantı, auth, TLS, retry, bulk. Bence en kritik nokta bulk operasyonları doğru kullanmak; tek bu bile cluster'ınızın ömrünü uzatıyor. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.