Java ile CRUD İşlemleri
Giriş — Depocu ve Forklift
Bir depo düşünün. Raflar dolu, binlerce ürün var. Depocu her gün aynı işleri yapar: yeni ürün yerleştirir (index), mevcut ürünü bulup getirir (get), etiket günceller (update), bozuk ürünü çıkarır (delete). Arada bir de TIR gelir — yüzlerce kutuyu tek seferde indirmek gerekir (bulk). Tek tek taşımak saatler alır; forklift ile palet palet taşırsanız dakikalar.
Elasticsearch Java Client ile CRUD işlemleri tam olarak bu mantıkla çalışır. Bu derste önce tek tek CRUD'u öğreneceğiz, sonra forkliftimiz olan Bulk API'yi devreye sokacağız. Önceki derste kurduğumuz ElasticsearchClient nesnesini kullanacağız.
1. Model Tanımları — POJO ve Record
1.1 Java Record (Önerilen)
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.time.LocalDateTime;
import java.util.List;
@JsonIgnoreProperties(ignoreUnknown = true)
public record Product(
@JsonProperty("name") String name,
@JsonProperty("description") String description,
@JsonProperty("category") String category,
@JsonProperty("price") double price,
@JsonProperty("stock") int stock,
@JsonProperty("tags") List<String> tags,
@JsonProperty("created_at") LocalDateTime createdAt
) {}1.2 Klasik POJO
@JsonIgnoreProperties(ignoreUnknown = true)
public class Product {
private String name;
private String description;
private String category;
private double price;
private int stock;
private List<String> tags;
@JsonProperty("created_at")
private LocalDateTime createdAt;
public Product() {} // Jackson için boş constructor zorunlu!
public Product(String name, String description, String category,
double price, int stock, List<String> tags,
LocalDateTime createdAt) {
this.name = name;
this.description = description;
this.category = category;
this.price = price;
this.stock = stock;
this.tags = tags;
this.createdAt = createdAt;
}
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getPrice() { return price; }
public void setPrice(double price) { this.price = price; }
public int getStock() { return stock; }
public void setStock(int stock) { this.stock = stock; }
// ... diğer getter/setter'lar
}💡 İpucu: Java 16+ kullanıyorsanız Record tercih edin — daha az kod, immutable, doğal equals/hashCode/toString.
1.3 ObjectMapper Konfigürasyonu
LocalDateTime gibi Java 8+ tarih tiplerini Jackson'ın tanıması için JavaTimeModule zorunludur:
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
ElasticsearchTransport transport = new RestClientTransport(
restClient, new JacksonJsonpMapper(objectMapper)
);⚠️ Dependency eklemeyi unutmayın:
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.16.1</version>
</dependency>2. Document Oluşturma (Index)
2.1 POJO ile Index
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.IndexResponse;
import co.elastic.clients.elasticsearch._types.Result;
import java.time.LocalDateTime;
import java.util.List;
public class IndexExample {
public static void indexWithPojo(ElasticsearchClient client) throws Exception {
Product product = new Product(
"MacBook Pro 16",
"Apple M3 Max çipli profesyonel dizüstü bilgisayar",
"electronics", 74999.99, 50,
List.of("apple", "laptop", "pro"),
LocalDateTime.now()
);
IndexResponse response = client.index(i -> i
.index("products")
.id("prod-001")
.document(product)
);
System.out.println("ID: " + response.id());
System.out.println("Version: " + response.version());
System.out.println("Result: " + response.result());
if (response.result() == Result.Created) {
System.out.println("Yeni document oluşturuldu");
} else if (response.result() == Result.Updated) {
System.out.println("Mevcut document güncellendi");
}
}
}ID belirtmezseniz Elasticsearch otomatik üretir:
IndexResponse response = client.index(i -> i
.index("products")
.document(product) // ID yok → otomatik üretilir
);
System.out.println("Auto ID: " + response.id()); // "k1xB4owBdRz2..."2.2 JSON String ile Index
Elimizde POJO yerine ham JSON olduğunda:
import java.io.StringReader;
String jsonString = """
{
"name": "Sony WH-1000XM5",
"description": "Gürültü engelleyici kulaklık",
"category": "electronics",
"price": 12999.99,
"stock": 200,
"tags": ["sony", "headphone"],
"created_at": "2024-01-15T10:30:00"
}
""";
IndexResponse response = client.index(i -> i
.index("products")
.id("prod-003")
.withJson(new StringReader(jsonString))
);2.3 Sadece Yoksa Oluştur — op_type: create
import co.elastic.clients.elasticsearch._types.OpType;
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
try {
IndexResponse response = client.index(i -> i
.index("products")
.id("prod-001")
.document(product)
.opType(OpType.Create) // Varsa 409 conflict fırlat
);
} catch (ElasticsearchException e) {
if (e.status() == 409) {
System.out.println("Document zaten var, atlanıyor.");
} else {
throw e;
}
}3. Document Okuma (Get)
3.1 Basit Get
import co.elastic.clients.elasticsearch.core.GetResponse;
public class GetExample {
public static void getById(ElasticsearchClient client) throws Exception {
GetResponse<Product> response = client.get(g -> g
.index("products")
.id("prod-001"),
Product.class
);
if (response.found()) {
Product product = response.source();
System.out.println("Ürün: " + product.getName());
System.out.println("Fiyat: " + product.getPrice());
} else {
System.out.println("Document bulunamadı!");
}
}
}3.2 Source Filtering — Sadece İstediğin Alanlar
GetResponse<Product> response = client.get(g -> g
.index("products")
.id("prod-001")
.sourceIncludes("name", "price"),
Product.class
);
// Sadece name ve price dolu, diğerleri null3.3 Exists — Varlık Kontrolü
import co.elastic.clients.transport.endpoints.BooleanResponse;
BooleanResponse exists = client.exists(e -> e.index("products").id("prod-001"));
System.out.println(exists.value() ? "Mevcut" : "Bulunamadı");3.4 Multi-Get — Toplu Okuma
import co.elastic.clients.elasticsearch.core.MgetResponse;
import co.elastic.clients.elasticsearch.core.mget.MultiGetResponseItem;
MgetResponse<Product> response = client.mget(m -> m
.index("products")
.ids("prod-001", "prod-002", "prod-003", "prod-999"),
Product.class
);
for (MultiGetResponseItem<Product> item : response.docs()) {
if (item.isResult()) {
var doc = item.result();
if (doc.found()) {
System.out.println("✅ " + doc.id() + ": " + doc.source().getName());
} else {
System.out.println("❌ " + doc.id() + ": Bulunamadı");
}
}
}⚠️ mget vs search: Belirli ID'leri biliyorsanız mget kullanın — doğrudan shard'a gider, aramadan çok daha hızlıdır.
4. Document Güncelleme (Update)
4.1 Partial Update
import co.elastic.clients.elasticsearch.core.UpdateResponse;
import java.util.Map;
public class UpdateExample {
public static void partialUpdate(ElasticsearchClient client) throws Exception {
UpdateResponse<Product> response = client.update(u -> u
.index("products")
.id("prod-001")
.doc(Map.of("price", 69999.99, "stock", 45)),
Product.class
);
System.out.println("Result: " + response.result());
System.out.println("Version: " + response.version());
}
}4.2 Script ile Update
Mevcut değere bağlı güncelleme — örneğin stoktan düşme:
UpdateResponse<Product> response = client.update(u -> u
.index("products")
.id("prod-001")
.script(s -> s
.inline(i -> i
.source("ctx._source.stock -= params.qty")
.params("qty", co.elastic.clients.json.JsonData.of(5))
)
),
Product.class
);Koşullu script — stok yeterliyse düş, yoksa noop:
String script = """
if (ctx._source.stock >= params.qty) {
ctx._source.stock -= params.qty;
} else {
ctx.op = 'noop';
}
""";
UpdateResponse<Product> response = client.update(u -> u
.index("products")
.id("prod-001")
.script(s -> s.inline(i -> i
.source(script)
.params("qty", co.elastic.clients.json.JsonData.of(100))
)),
Product.class
);
// Stok yetersizse → Result.NoOp4.3 Upsert — Yoksa Oluştur, Varsa Güncelle
Product newProduct = new Product("iPad Air M2", "M2 çipli tablet",
"electronics", 29999.99, 80, List.of("apple", "tablet"), LocalDateTime.now());
UpdateResponse<Product> response = client.update(u -> u
.index("products")
.id("prod-010")
.doc(newProduct) // Varsa güncelle
.upsert(newProduct), // Yoksa oluştur
Product.class
);
// Result.Created veya Result.Updated4.4 Güncellenmiş Hali Geri Alma
UpdateResponse<Product> response = client.update(u -> u
.index("products")
.id("prod-001")
.doc(Map.of("price", 64999.99))
.source(s -> s.fetch(true)), // Güncel halini döndür
Product.class
);
Product updated = response.get().source();
System.out.println("Güncel fiyat: " + updated.getPrice());5. Document Silme (Delete)
5.1 ID ile Silme
import co.elastic.clients.elasticsearch.core.DeleteResponse;
DeleteResponse response = client.delete(d -> d.index("products").id("prod-001"));
if (response.result() == Result.Deleted) {
System.out.println("Silindi");
} else if (response.result() == Result.NotFound) {
System.out.println("Zaten yoktu");
}5.2 Delete by Query — Koşullu Toplu Silme
import co.elastic.clients.elasticsearch.core.DeleteByQueryResponse;
// Stoku 0 olan tüm ürünleri sil
DeleteByQueryResponse response = client.deleteByQuery(d -> d
.index("products")
.query(q -> q.term(t -> t.field("stock").value(0)))
);
System.out.println("Silinen: " + response.deleted());
System.out.println("Süre (ms): " + response.took());Daha karmaşık koşul:
// 2023'ten önce oluşturulmuş VE stoku 0 olan ürünler
DeleteByQueryResponse response = client.deleteByQuery(d -> d
.index("products")
.query(q -> q.bool(b -> b
.must(m -> m.range(r -> r.field("created_at")
.lt(co.elastic.clients.json.JsonData.of("2023-01-01"))))
.must(m -> m.term(t -> t.field("stock").value(0)))
))
.refresh(true)
);6. Bulk API — Toplu İşlemler
Production'da binlerce document'ı tek tek index'lemek yüzlerce HTTP isteği demek. Bulk API tüm işlemleri tek istekte birleştirir — bu dersin en kritik kısmı.
6.1 Basit Bulk Index
import co.elastic.clients.elasticsearch.core.BulkResponse;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.elasticsearch.core.bulk.BulkResponseItem;
public class BulkExample {
public static void bulkIndex(ElasticsearchClient client) throws Exception {
List<Product> products = List.of(
new Product("iPhone 15 Pro", "A17 Pro", "electronics",
64999.99, 100, List.of("apple", "phone"), LocalDateTime.now()),
new Product("AirPods Pro 2", "ANC", "electronics",
9999.99, 500, List.of("apple", "earbuds"), LocalDateTime.now()),
new Product("Dell XPS 15", "i9", "electronics",
52999.99, 35, List.of("dell", "laptop"), LocalDateTime.now())
);
BulkRequest.Builder bulkBuilder = new BulkRequest.Builder();
for (int i = 0; i < products.size(); i++) {
final int idx = i;
final String id = "prod-" + (100 + i);
bulkBuilder.operations(op -> op
.index(ix -> ix.index("products").id(id)
.document(products.get(idx)))
);
}
BulkResponse response = client.bulk(bulkBuilder.build());
if (response.errors()) {
for (BulkResponseItem item : response.items()) {
if (item.error() != null) {
System.err.println("❌ " + item.id() + ": " + item.error().reason());
}
}
} else {
System.out.println("✅ " + response.items().size() + " document eklendi");
}
}
}6.2 Karma Bulk — Index + Update + Delete
BulkResponse response = client.bulk(b -> b
.operations(op -> op
.index(idx -> idx.index("products").id("prod-200")
.document(new Product("Yeni", "Açıklama", "electronics",
9999.99, 10, List.of("new"), LocalDateTime.now())))
)
.operations(op -> op
.update(upd -> upd.index("products").id("prod-001")
.action(a -> a.doc(Map.of("price", 59999.99))))
)
.operations(op -> op
.delete(del -> del.index("products").id("prod-old-001"))
)
);
for (BulkResponseItem item : response.items()) {
System.out.printf(" %s %s → %s%n",
item.operationType(), item.id(), item.result());
}6.3 Büyük Veri Seti — Chunk'lara Bölme
public class ChunkedBulkProcessor {
private static final int CHUNK_SIZE = 1000;
public static void bulkIndexChunked(ElasticsearchClient client,
List<Product> allProducts) throws Exception {
int success = 0, errors = 0;
long start = System.currentTimeMillis();
for (int i = 0; i < allProducts.size(); i += CHUNK_SIZE) {
int end = Math.min(i + CHUNK_SIZE, allProducts.size());
List<Product> chunk = allProducts.subList(i, end);
BulkRequest.Builder builder = new BulkRequest.Builder();
for (int j = 0; j < chunk.size(); j++) {
final Product p = chunk.get(j);
final String id = "prod-" + (i + j);
builder.operations(op -> op
.index(idx -> idx.index("products").id(id).document(p)));
}
BulkResponse resp = client.bulk(builder.build());
if (resp.errors()) {
for (BulkResponseItem item : resp.items()) {
if (item.error() != null) errors++; else success++;
}
} else {
success += chunk.size();
}
System.out.printf("İlerleme: %d/%d%n", end, allProducts.size());
}
System.out.printf("Bitti: %d OK, %d hata, %d ms%n",
success, errors, System.currentTimeMillis() - start);
}
}6.4 BulkIngester — Otomatik Chunk Yönetimi
import co.elastic.clients.helpers.bulk.BulkIngester;
import co.elastic.clients.helpers.bulk.BulkListener;
BulkListener<Void> listener = new BulkListener<>() {
@Override
public void beforeBulk(long id, BulkRequest req, List<Void> ctx) {
System.out.println("Bulk #" + id + " → " + req.operations().size() + " işlem");
}
@Override
public void afterBulk(long id, BulkRequest req, List<Void> ctx, BulkResponse resp) {
System.out.println("Bulk #" + id + (resp.errors() ? " ⚠️" : " ✅"));
}
@Override
public void afterBulk(long id, BulkRequest req, List<Void> ctx, Throwable err) {
System.err.println("Bulk #" + id + " BAŞARISIZ: " + err.getMessage());
}
};
try (BulkIngester<Void> ingester = BulkIngester.of(b -> b
.client(client)
.maxOperations(500)
.flushInterval(5, java.util.concurrent.TimeUnit.SECONDS)
.listener(listener)
)) {
for (int i = 0; i < products.size(); i++) {
final String id = "prod-" + i;
final Product p = products.get(i);
ingester.add(op -> op
.index(idx -> idx.index("products").id(id).document(p)), null);
}
} // close() → kalan işlemler otomatik gönderilir💡 BulkIngester thread-safe'tir, maxOperations'a ulaşınca veya flushInterval dolunca otomatik flush eder, close() çağrılınca kalanları gönderir.
7. Hata Yönetimi
7.1 Genel Hata Yakalama
import co.elastic.clients.elasticsearch._types.ElasticsearchException;
import co.elastic.clients.transport.TransportException;
public class ErrorHandling {
public static void safeIndex(ElasticsearchClient client,
String id, Product product) {
try {
IndexResponse response = client.index(i -> i
.index("products").id(id).document(product));
System.out.println("OK: " + response.id());
} catch (ElasticsearchException e) {
System.err.println("ES Hatası [" + e.status() + "]: " + e.error().reason());
switch (e.status()) {
case 400 -> System.err.println("→ Geçersiz istek (mapping hatası?)");
case 404 -> System.err.println("→ Index bulunamadı");
case 409 -> System.err.println("→ Version conflict");
case 429 -> System.err.println("→ Rate limit — retry gerekli");
}
} catch (TransportException e) {
System.err.println("Bağlantı hatası: " + e.getMessage());
} catch (java.io.IOException e) {
System.err.println("IO hatası: " + e.getMessage());
}
}
}7.2 Retry (Exponential Backoff)
public class RetryHelper {
public static <T> T withRetry(java.util.concurrent.Callable<T> op,
int maxRetries, long delayMs) throws Exception {
for (int attempt = 1; ; attempt++) {
try {
return op.call();
} catch (Exception e) {
if (attempt >= maxRetries) throw e;
System.out.printf("Deneme %d/%d başarısız, %dms bekleniyor%n",
attempt, maxRetries, delayMs);
Thread.sleep(delayMs);
delayMs = Math.min(delayMs * 2, 30000);
}
}
}
}
// Kullanım
IndexResponse resp = RetryHelper.withRetry(
() -> client.index(i -> i.index("products").id("1").document(product)),
3, 1000
);8. Optimistic Concurrency Control
İki thread aynı document'ı güncellemeye çalışırsa _seq_no ve _primary_term ile sadece biri başarılı olur:
// 1. Oku — seq_no ve primary_term al
GetResponse<Product> getResp = client.get(g -> g
.index("products").id("prod-001"), Product.class);
long seqNo = getResp.seqNo();
long primaryTerm = getResp.primaryTerm();
// 2. Koşullu güncelle
try {
IndexResponse updateResp = client.index(i -> i
.index("products")
.id("prod-001")
.document(getResp.source())
.ifSeqNo(seqNo)
.ifPrimaryTerm(primaryTerm)
);
System.out.println("OK, version: " + updateResp.version());
} catch (ElasticsearchException e) {
if (e.status() == 409) {
System.out.println("⚠️ Conflict! Başka biri güncellemiş → tekrar oku ve dene.");
}
}9. Bütünleşik Örnek — E-Ticaret Ürün Yönetimi
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.*;
import co.elastic.clients.elasticsearch._types.Result;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
public class ECommerceProductManager {
private final ElasticsearchClient client;
private static final String INDEX = "products_v2";
public ECommerceProductManager(ElasticsearchClient client) {
this.client = client;
}
public void setupIndex() throws Exception {
if (!client.indices().exists(e -> e.index(INDEX)).value()) {
client.indices().create(c -> c.index(INDEX)
.settings(s -> s.numberOfShards("3").numberOfReplicas("1"))
.mappings(m -> m
.properties("name", p -> p.text(t -> t.analyzer("standard")))
.properties("category", p -> p.keyword(k -> k))
.properties("price", p -> p.float_(f -> f))
.properties("stock", p -> p.integer(i -> i))
.properties("tags", p -> p.keyword(k -> k))
.properties("created_at", p -> p.date(d ->
d.format("yyyy-MM-dd'T'HH:mm:ss")))
)
);
System.out.println("✅ Index oluşturuldu");
}
}
public void addProduct(String id, Product product) throws Exception {
client.index(i -> i.index(INDEX).id(id).document(product));
}
public void addBulk(Map<String, Product> products) throws Exception {
BulkRequest.Builder b = new BulkRequest.Builder();
products.forEach((id, p) -> b.operations(op -> op
.index(idx -> idx.index(INDEX).id(id).document(p))));
BulkResponse resp = client.bulk(b.build());
if (resp.errors()) System.out.println("⚠️ Bulk hatası var!");
}
public Product getProduct(String id) throws Exception {
var resp = client.get(g -> g.index(INDEX).id(id), Product.class);
return resp.found() ? resp.source() : null;
}
public void updatePrice(String id, double price) throws Exception {
client.update(u -> u.index(INDEX).id(id)
.doc(Map.of("price", price)), Product.class);
}
public void decreaseStock(String id, int qty) throws Exception {
client.update(u -> u.index(INDEX).id(id)
.script(s -> s.inline(i -> i
.source("ctx._source.stock -= params.qty")
.params("qty", co.elastic.clients.json.JsonData.of(qty))
)), Product.class);
}
public boolean deleteProduct(String id) throws Exception {
return client.delete(d -> d.index(INDEX).id(id))
.result() == Result.Deleted;
}
public static void main(String[] args) throws Exception {
ObjectMapper om = new ObjectMapper();
om.registerModule(new JavaTimeModule());
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
RestClient rest = RestClient.builder(
new HttpHost("localhost", 9200, "http")).build();
var transport = new RestClientTransport(rest, new JacksonJsonpMapper(om));
var client = new ElasticsearchClient(transport);
var mgr = new ECommerceProductManager(client);
mgr.setupIndex();
mgr.addProduct("p-001", new Product("MacBook Pro 16", "M3 Max",
"electronics", 74999.99, 50, List.of("apple"), LocalDateTime.now()));
mgr.addBulk(Map.of(
"p-002", new Product("iPhone 15", "A17", "electronics",
64999.99, 100, List.of("apple"), LocalDateTime.now()),
"p-003", new Product("Sony XM5", "ANC", "electronics",
12999.99, 200, List.of("sony"), LocalDateTime.now())
));
client.indices().refresh(r -> r.index(INDEX));
Product p = mgr.getProduct("p-001");
System.out.println("Okunan: " + p.getName() + " — " + p.getPrice() + " TL");
mgr.updatePrice("p-001", 69999.99);
mgr.decreaseStock("p-002", 3);
System.out.println("Silindi: " + mgr.deleteProduct("p-003"));
transport.close();
rest.close();
}
}10. Best Practices
✅ Yapın
| Uygulama | Neden |
|---|---|
| Bulk API kullanın (10+ document) | Her HTTP isteğinin overhead'i var — toplu gönderin |
| Chunk size: 500-2000 | Çok büyük chunk bellek patlatır |
@JsonIgnoreProperties(ignoreUnknown = true) | Mapping değişse bile deserialize çalışır |
op_type: create ile duplicate engeli | Aynı ID'nin üzerine yazmayı önler |
Optimistic locking (if_seq_no) | Race condition'ları önler |
❌ Yapmayın
| Uygulama | Neden |
|---|---|
| Tek tek index'lemeyin | Her biri ayrı HTTP roundtrip — çok yavaş |
| Bulk'ta 10MB'ı aşmayın | 5-15MB ideal, büyük request timeout alır |
| Bulk errors kontrolünü atlamayın | errors: true olabilir ama exception fırlatmaz |
| Hata yönetimi olmadan production'a çıkmayın | Ağ hataları, conflict'ler kaçınılmaz |
11. Yaygın Hatalar
Hata 1: Jackson Boş Constructor Eksikliği
// ❌ No default constructor hatası
public class Product {
private final String name;
public Product(String name) { this.name = name; }
}
// ✅ Boş constructor ekle veya Record kullan
public class Product {
private String name;
public Product() {}
}Hata 2: LocalDateTime Serialization
// ❌ Tarih array olarak serialize oluyor: [2024,1,15,10,30]
// ✅ JavaTimeModule + WRITE_DATES_AS_TIMESTAMPS kapalı
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);Hata 3: Bulk Response Kontrol Etmemek
// ❌ Bazı document'lar başarısız olmuş olabilir!
BulkResponse response = client.bulk(builder.build());
System.out.println("Bitti!");
// ✅ Errors flag'ini kontrol et
if (response.errors()) {
response.items().stream()
.filter(item -> item.error() != null)
.forEach(item -> System.err.println(item.id() + " → " + item.error().reason()));
}Özet
IndexRequest ile document oluşturma: POJO, JSON string ile —
op_type: createduplicate'i önlerGetRequest ile tekil okuma, mget ile toplu okuma — source filtering ile sadece gerekli alanları çekin
UpdateRequest ile partial update, script update, upsert — koşullu güncelleme için Painless script
DeleteRequest ile tekil silme, DeleteByQuery ile koşullu toplu silme
Bulk API production'ın olmazsa olmazı — 500-2000'lik chunk'lar veya
BulkIngesterile otomatikHata yönetimi zorunlu —
ElasticsearchExceptionstatus code'ları, retry pattern, bulk error collectingOptimistic locking (
if_seq_no,if_primary_term) ile concurrent update güvenliğiJackson konfigürasyonu kritik:
JavaTimeModule+@JsonIgnorePropertieseklemeyi unutmayın
AI Asistan
Sorularını yanıtlamaya hazır