Elasticsearch 8'den 9.x'e ve OpenSearch 3: Yenilikler, Kaldırılanlar ve Hangisini Seçmeli?
Elasticsearch 8'den 9.x'e önce son 8.19'a geçip deprecation uyarılarını temizleyerek ve snapshot alarak yükseltilir; OpenSearch 3 ise çekirdeği ortak ama ayrı yolda giden bir motor ve ayrı bir .NET client istiyor. Gerçek çıktılarla: 8.19'da uyarı veren parametrelerin 9.5'te 400 dönmesi, deprecation API, 8.19 verisini 9.5'te açmak ve geri dönememek, LOOKUP JOIN, Elastic client'ın OpenSearch'ten 406 alması, OpenSearch.Client ile aynı arama ve bir karar tablosu.
Sürüm notu: Bu yazıdaki örnekler Elasticsearch 9.5.6 ve 8.19.25, OpenSearch 3.9.0, .NET 10, Elastic.Clients.Elasticsearch 9.5.3 ve OpenSearch.Client 2.3.0 ile çalıştırılmıştır. Elastic Cloud ve Amazon OpenSearch Service çalıştırılmadı; onlarla ilgili bilgiler Elastic'in ve Amazon'un dokümanlarından.
Önce Tahmin Et
Sitedeki serilerin ortak örnek uygulaması Bookstore (bir online kitapçı) için yazdığımız arama kodu Elasticsearch 9.5'e karşı çalışıyor. OpenSearch, Elasticsearch 7.10.2'den ayrılmış bir fork; ikisi de Lucene üstünde, ikisi de aynı REST (HTTP üzerinden kaynak odaklı API tarzı) yollarını (/books/_search, _bulk, _analyze) kullanıyor ve 1. yazıda gördüğümüz gibi birçok ekip ikisini birbirinin yerine düşünüyor. Lab'da bir OpenSearch 3.9.0 container'ı açtım, 36 kitabı _bulk ile yükledim ve 10. yazıdaki syntax komutunu hiçbir kodu değiştirmeden ona yönelttim:
$env:BOOKSTORE_ES_URL = "http://localhost:9203"
dotnet run --project src/Bookstore.SearchLab -- syntax
Elastic.Clients.Elasticsearch 9.5.3 bu sunucuyla konuşabilir mi? Konuşamıyorsa hata nereden gelir: sorgunun kendisinden mi, bağlantıdan mı, başka bir yerden mi?
8.x'ten 9.x'e Yükseltme Yolu
Önce Elasticsearch'ün kendi yükseltme yoluna bakalım. Elastic'in yükseltme hazırlık dokümanına göre kural net: 9.x'e geçmeden önce son 8.19.x sürümüne geçilmesi gerekiyor; 9.1 ve sonrasına yalnız 8.19'dan çıkılabiliyor. 7.x ve öncesinde oluşturulmuş index'ler yükseltmeden önce reindex edilmeli, silinmeli ya da salt okunur arşive alınmalı; aksi hâlde 9.x node'u açılmıyor. Bu yolu küçük bir lab'da yürüdüm. 8.19.25 (bu yazıyı yazarken Elastic'in registry'sindeki son 8.x image'ı) ile bir node açtım, basit bir books-v1 index'i oluşturup beş kitap yükledim ve 9.0'da kaldırılan iki parametreyi denedim:
POST /books-v1/_search
{ "query": { "range": { "price": { "from": 100, "to": 200 } } } }
HTTP/1.1 200 OK
Warning: 299 Elasticsearch-8.19.25-... "Deprecated field [from] used, this field is unused and will be removed entirely"
Warning: 299 Elasticsearch-8.19.25-... "Deprecated field [to] used, this field is unused and will be removed entirely"
POST /books-v1/_search
{ "query": { "match": { "title": "dune" } }, "highlight": { "force_source": true, "fields": { "title": {} } } }
HTTP/1.1 200 OK
Warning: 299 Elasticsearch-8.19.25-... "[highlight][1:65] Deprecated field [force_source] used, this field is unused and will be removed entirely"
8.19 çalışıyor ve yalnız bir Warning header'ı dönüyor; çoğu uygulama bu header'ı hiç loglamaz. Aynı istekler 9.5.6'da:
{"error":{"type":"parsing_exception","reason":"[range] query does not support [from]","line":1,"col":36},"status":400}
{"error":{"type":"x_content_parse_exception","reason":"[1:50] [highlight] unknown field [force_source]"},"status":400}
Uyarı, yükseltmeden sonra 400'e dönüşüyor. Bu yüzden 8.19'da iki şey yapılıyor: uygulamanın loglarında Warning: 299 header'larını aramak ve deprecation API'sini çalıştırmak. Kod tarafını göremeyen bu API, cluster'daki ayarları, template'leri ve index'leri tarıyor. Denemek için 8.19'da mapping'inde _source.mode olan bir component template oluşturdum (9.0'da bu attribute'un etkisi kalmadı):
GET /_migration/deprecations
{
"cluster_settings": [],
"node_settings": [],
"templates": {
"legacy-source": [
{
"level": "critical",
"message": "Configuring source mode in mappings is deprecated.",
"details": "Configuring source mode in mappings is deprecated and will be removed in future versions. Use [index.mapping.source.mode] index setting instead.",
"resolve_during_rolling_upgrade": false
}
]
},
"index_settings": {},
...
}
Sonra node'u durdurup aynı data volume'üyle 9.5.6 image'ını başlattım (tek node'da tam yeniden başlatma; çok node'lu bir cluster'da node'lar sırayla güncellenir, buna rolling upgrade deniyor):
GET /
"number" : "9.5.6",
"minimum_wire_compatibility_version" : "8.19.0",
"minimum_index_compatibility_version" : "8.0.0"
GET /books-v1/_count
{"count":5, ...}
GET /_migration/deprecations?filter_path=index_settings
{
"index_settings": {
"books-v1": [
{
"level": "critical",
"message": "Old index with a compatibility version < 9.0",
"details": "This index has version: 8.19.9-8.19.23",
"resolve_during_rolling_upgrade": false,
"_meta": { "reindex_required": true }
}
]
}
}
Üç bilgi var. 9.5.6, 8.0 ve sonrasında oluşturulmuş index'leri okuyabiliyor (minimum_index_compatibility_version) ve node'lar arası iletişimde en az 8.19 istiyor. 8.x'te oluşturulan index çalışıyor, ama deprecation API onu şimdiden "kritik" işaretliyor: bir sonraki major sürüme geçmeden önce reindex edilmesi gerekecek. 11. yazıdaki alias'lı geçiş tam bunun için var; Bookstore'da bu, migrate books-vN demek. Son olarak geri dönüşü denedim, aynı volume'ü 8.19.25 ile açtım:
"log.level":"ERROR","message":"fatal exception while booting Elasticsearch", ...
"error.type":"java.lang.IllegalArgumentException","error.message":"indexCreatedVersionMajor is in the future: 10"
9.x, index dosyalarını Lucene 10 biçiminde yazıyor ve 8.x onları okuyamıyor. Yükseltilmiş bir node geri alınamıyor; tek geri dönüş yolu yükseltmeden önce alınmış snapshot'tan restore. 12. yazıdaki SLM'in (snapshot'ları zamanlayan özellik) son başarılı snapshot'ını kontrol etmeden yükseltmeye başlama.
9.0'da Kaldırılan ve Değişenler
Elastic'in breaking changes sayfasındaki 9.0 listesi uzun; bir arama uygulamasını en çok etkileyenleri, Bookstore açısından gruplayarak özetliyorum:
- Sorgu:
rangesorgusunun eski parametreleri (from,tove benzerleri) ve highlight'takiforce_sourcekaldırıldı;date_histogramboolean değer kabul etmiyor;random_score'un varsayılan alanı_seq_nooldu, yani rastgele sıralamalar değişebilir. Bookstore'un sorgularıgte/ltkullandığı için etkilenmedi. - API: bulk action satırları daha sıkı parse ediliyor (5. yazıda gördük); zaman aşımları 5xx yerine 429 dönüyor (10. yazıdaki retry kararı); hata JSON'ları tutarlı bir biçime geçti; alias API'lerindeki eski
localparametresi kaldırıldı. - Mapping: metadata field tanımlarında
type,fields,copy_toveboostkabul edilmiyor;_source'unmodeattribute'u artık etkisiz (yukarıdaki deprecation). - Kaldırılan özellikler: frozen index'ler okunamıyor (yükseltmeden önce ele alınmalı) ve teknik önizlemedeki
_knn_searchAPI'si kaldırıldı; vektör aramasıknnsorgusuyla yapılıyor.semantic_textalanı artık normal bir text alanı gibi davranıyor. - Güvenlik: TLSv1.1 varsayılan protokollerden çıkarıldı; çok eski istemciler bağlanamayabilir.
- Analiz: Snowball stemmer'ları güncellendi. 4. yazıdaki Türkçe stemmer da Snowball; Bookstore'un Türkçe başlık ve açıklamalarındaki 236 farklı kelimeyi 8.19.25 ve 9.5.6'da aynı filtre zinciriyle (
turkishlowercase +turkishstemmer) analiz ettim ve kökler birebir aynı çıktı. Kendi verinde aynı karşılaştırmayı yap; kökler değişmişse eski index'te yazılmış term'lerle yeni sorgunun term'leri eşleşmez ve reindex gerekir.
9.1–9.5 arasında da breaking change var ve minor sürümleri "güvenli" varsaymamak gerekiyor. Bookstore'u etkileyebilecek olan, 9.1'de ES|QL sorgularının varsayılan olarak hata vermek yerine kısmi sonuç döndürmeye başlaması: cevaptaki is_partial bayrağına bakmayan bir rapor, eksik veriyi tam sanabilir (10. yazıdaki esql komutu gibi bir rapor için allow_partial_results=false ver). 9.4'te time series index'lerinde sequence number'lar kapatıldı, yani orada if_seq_no ile optimistic concurrency çalışmıyor; Bookstore'un books index'i time series değil, 5. yazıdaki yöntem etkilenmiyor.
9.1–9.5 Arasında Gelenler
Seriyi yazarken kullandığımız ya da bir arama uygulaması için önemli olan birkaç yenilik. 9.1'de (8.19 ile birlikte) ES|QL'in LOOKUP JOIN komutu GA (Generally Available; production kullanımı için desteklenen) oldu: bir sorgunun sonucunu index.mode: lookup ile açılmış küçük bir index'le birleştirmek. Kategori adlarının Türkçe karşılıklarını böyle bir index'e koydum:
PUT /category-labels
{
"settings": { "index.mode": "lookup" },
"mappings": { "properties": { "category": { "type": "keyword" }, "label_tr": { "type": "keyword" } } }
}
POST /_query?format=txt
{ "query": "FROM books | WHERE language == \"tr\" | STATS books = COUNT(*) BY category = categories | LOOKUP JOIN category-labels ON category | SORT books DESC | LIMIT 5" }
books | category | label_tr
---------------+------------------+---------------
21 |Fiction |Roman
17 |Classics |Klasikler
2 |Historical Fiction|null
2 |Science Fiction |Bilim Kurgu
2 |Fantasy |Fantastik
Lookup index'te karşılığı olmayan kategori null geliyor; bu bir left join. 9.2'de LOOKUP JOIN birden çok alan ve ifadeyle eşleşmeyi öğrendi. 9.5.0'da reindex için ayrı yönetim API'leri geldi (GET /_reindex, GET /_reindex/<task_id>, iptal ve hız ayarı); 11. yazıdaki migrate komutu ilerlemeyi bununla izliyor. Bunların dışında 9.x boyunca gelen yeniliklerin büyük kısmı vektör araması, semantic search, inference ve observability tarafında; bir arama sayfası için önemli olanları (hybrid search, RRF (Reciprocal Rank Fusion; birden çok sıralamayı tek listede birleştirme yöntemi) ve retriever'lar) RAG (Retrieval-Augmented Generation; dil modelinin cevabını aranıp bulunan belgelerle besleme) serisinin "Hybrid Search ve Reciprocal Rank Fusion: Keyword ile Vector Aramayı Birleştirmek" yazısı anlatıyor. Sürüm listesini takip etmenin en güvenilir yolu release notes ve breaking changes sayfaları; blog yazıları öne çıkanları anlatır, kırılanları değil.
OpenSearch 3: Ortak Kök, Ayrışan Yol
OpenSearch, 2021'de Elasticsearch'ün lisans değişikliğinden sonra Elasticsearch 7.10.2'den ayrıldı, Apache 2.0 lisanslı ve 2024'ten beri Linux Foundation altındaki OpenSearch Software Foundation'da (1. yazı). Bugünkü sürüm 3.9.0 (Docker Hub'da 2026-10-26). OpenSearch Software Foundation, Nisan 2026'da bir LTS (Long-Term Support; uzun süreli destek) programı duyurdu: ilk LTS sürümü 3.6, her LTS en az 18 ay destekleniyor ve her major sürümün en az bir LTS'i olacak. Elasticsearch'te resmî bir LTS adı yok; karşılığı, bir önceki major'ın son minor'ının yama almaya devam etmesi: 8.19, 9.x yayındayken de güncelleniyor (8.19.25 image'ı Kasım 2026'da çıktı).
Lab'da gördüğüm farklar. Varsayılan image security plugin'iyle geliyor ve ilk açılışta bir admin parolası istiyor:
OpenSearch 2.12.0 onwards, the OpenSearch Security Plugin a change that requires an initial password for 'admin' user.
Please define an environment variable 'OPENSEARCH_INITIAL_ADMIN_PASSWORD' with a strong password string.
If a password is not provided, the setup will quit.
Denemeler için security plugin'ini kapattım (DISABLE_SECURITY_PLUGIN=true, DISABLE_INSTALL_DEMO_CONFIG=true); production'da bunu yapma. Sonra Bookstore'un mapping'ini olduğu gibi göndermeyi denedim:
PUT /books (search/books.index.json)
{"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"Failed to build analyzers: [search_synonyms]"}], ...
"reason":"[search_synonyms] synonym requires either `synonyms` or `synonyms_path` to be configured", ...}
4. yazıdaki synonyms_set ve onu yöneten synonyms API Elasticsearch'e ait; OpenSearch'te eş anlamlılar mapping'de liste olarak ya da sunucudaki bir dosyadan veriliyor. analysis-icu plugin'i varsayılan image'da yok, ama bin/opensearch-plugin install analysis-icu ile kuruldu (yeniden başlatma gerekiyor). Analiz zinciri ise ortak Lucene'den geldiği için aynı: turkish analyzer'ı aynı 236 kelimede iki motorda da aynı 218 token'ı üretti. ES|QL yok; OpenSearch'ün karşılığı PPL (Piped Processing Language; komutları pipe ile birbirine bağlayan sorgu dili) ve SQL plugin'i:
POST /_query
{"error":"Incorrect HTTP method for uri [/_query] and method [POST], allowed: [GET, DELETE, PUT, HEAD]","status":405}
POST /_plugins/_ppl
{ "query": "source=books | where price < 170 | stats count() as books, avg(price) as avg_price by language" }
"datarows": [ [1, 150.0, "en"], [4, 147.5, "tr"] ]
Kısacası temel sorgu dili, yani Query DSL (Domain Specific Language; Elasticsearch'ün JSON tabanlı sorgu dili), (match, bool, aggregation'lar) büyük ölçüde ortak, ama 7.10'dan sonra iki tarafa eklenen her şey (synonyms API, ES|QL, LOOKUP JOIN, retriever'lar bir yanda; PPL, kendi security plugin'i, k-NN ve neural search plugin'leri öbür yanda) ayrı. "Uyumlu" sözünü 7.10'dan kalan çekirdek için kullan.
.NET Tarafı: İki Ayrı Client
Tahminin cevabı:
Fluent: POST /_search {...} -> -1 hit(s)
Initializer: POST /books/_search {...} -> -1 hit(s)
Invalid Elasticsearch response built from a unsuccessful (406) low level call on POST: /_search
Exception: Request failed to execute. Call: Status code 406 from: POST /_search. ServerError: Type: Reason: "Content-Type header [application/vnd.elasticsearch+json;compatible-with=9] is not supported"
Sorgu doğru, bağlantı kuruluyor; hata header'da. Elastic'in 9.x client'ı her isteği application/vnd.elasticsearch+json;compatible-with=9 içerik tipiyle gönderiyor (sunucuya "9.x API'sini konuşuyorum" diyen sürüm bilgisi) ve OpenSearch bu tipi tanımadığı için 406 dönüyor. Aynı uygulamanın HEAD isteğiyle yaptığı index var mı kontrolü ise sorunsuz geçti; gövdesiz istekte bu header gitmiyor. Yani Elastic client'ı OpenSearch'e karşı "kısmen çalışıyor" gibi görünebilir, bu da hatayı daha geç fark ettirir. OpenSearch'ün kendi client'ı OpenSearch.Client; NEST'ten (Elasticsearch'ün 7.x'e kadarki .NET client'ı) 7.10 sürümünde fork edildi ve bugün NuGet'teki son sürümü 2.3.0. Aynı aramayı onunla küçük bir projede yazdım:
// 13. yazı: aynı arama, OpenSearch'e karşı OpenSearch.Client ile (NEST 7.10'un fork'u).
string url = Environment.GetEnvironmentVariable("BOOKSTORE_OS_URL") ?? "http://localhost:9200";
ConnectionSettings settings = new ConnectionSettings(new Uri(url)).DefaultIndex("books");
OpenSearchClient client = new(settings);
ISearchResponse<BookHit> response = await client.SearchAsync<BookHit>(s => s
.Size(5)
.Query(q => q.Bool(b => b
.Must(m => m.Match(mt => mt.Field(f => f.Title).Query("dune")))
.Filter(f => f.Term(t => t.Field(x => x.Language).Value("tr"))))));
// NEST adları: IsValidResponse yerine IsValid, ApiCallDetails yerine ApiCall.
Console.WriteLine($"{response.ApiCall.HttpMethod} {response.ApiCall.Uri.PathAndQuery} -> HTTP {response.ApiCall.HttpStatusCode}, IsValid {response.IsValid}, {response.Total} hit(s)");
$env:BOOKSTORE_OS_URL = "http://localhost:9203"
dotnet run --project src/Bookstore.OpenSearchLab
POST /books/_search?typed_keys=true -> HTTP 200, IsValid True, 1 hit(s)
9781000000191 Dune (tr) 420.0
Lambda'lı sözdizimi 10. yazıdaki fluent sözdizimine çok benziyor, ama tipler, namespace'ler ve adlar farklı (OpenSearch.Client, ISearchResponse<T>, IsValid). Bu client'ın descriptor araması 10. yazıdaki Elastic client'ın aksine DefaultIndex'i kullandı ve /books/_search'e gitti. Serializer da farklı: Elastic client System.Text.Json kullanıyor, OpenSearch.Client NEST'ten gelen kendi serializer'ını. İki motor arasında geçiş, kodda bir paket değişikliği değil, arama katmanının yeniden yazılması demek. Bookstore'da sorguların BookSearchRequestBuilder'da toplanmış olması (10. yazı) bu işi küçültür ama ortadan kaldırmaz.
Managed Seçenekler ve Sürüm Gecikmesi
Bulutta en yaygın iki seçenek: Elastic Cloud (Elastic'in kendi servisi; Elasticsearch'ün son sürümleri ve ücretli abonelik özellikleri) ve Amazon OpenSearch Service. AWS (Amazon Web Services; Amazon'un bulut platformunun kısaltması) dokümanına göre Amazon OpenSearch Service OpenSearch'ün 3.5, 3.3 ve 3.1 sürümlerini destekliyor, yani bugünkü 3.9.0'ın birkaç sürüm gerisinde; eski Elasticsearch'ü ise yalnız 7.10'a kadar (lisans değişikliğinden önceki son açık kaynak sürüm) çalıştırıyor. Elasticsearch 8.x veya 9.x isteyen biri için AWS'nin managed servisi bir seçenek değil. Öte yandan Amazon OpenSearch Service, Elasticsearch'te ücretli aboneliğe bağlı olan document level security (DLS) ve field level security'yi (FLS) içeriyor (12. yazı). Bu servislerin hiçbirini bu seride çalıştırmadım.
Hangisini Seçmeli?
| Soru | Elasticsearch 9.x | OpenSearch 3.x |
|---|---|---|
| Lisans | AGPLv3 ya da Elastic'in iki kaynak-erişilebilir lisansından biri (1. yazı) | Apache 2.0 |
| Yönetişim | Elastic şirketi | Linux Foundation altında OpenSearch Software Foundation |
| Managed servis | Elastic Cloud (AWS, Azure, Google Cloud üzerinde) | Amazon OpenSearch Service |
| Uzun destek | Önceki major'ın son minor'ı yama almaya devam ediyor (bugün 8.19) | LTS programı (3.6 ilk LTS, en az 18 ay) |
| Bu serideki özellikler | Hepsi (synonyms API, ES|QL, LOOKUP JOIN, reindex API'leri) | Çekirdek DSL ortak; synonyms API ve ES|QL yok, PPL var |
| DLS/FLS | Ücretli abonelik | Security plugin'inde |
| .NET client | Elastic.Clients.Elasticsearch 9.x (System.Text.Json) | OpenSearch.Client 2.x (NEST tabanlı) |
Pratik kurallar. Kurumun bulutu AWS ise ve ekip managed servis istiyorsa, OpenSearch zaten verilmiş bir kararın sonucu olur; o durumda seriyi OpenSearch'ün dokümanıyla birlikte oku ve ES|QL ile synonyms API'sini kullanan bölümleri karşılıklarıyla değiştir. Elastic'in son özelliklerine, ES|QL'e ve Elastic'in kendi desteğine ihtiyaç varsa Elasticsearch. Lisans politikası Apache 2.0 dışında bir şeye izin vermiyorsa OpenSearch; Elasticsearch'ün AGPLv3 seçeneği (1. yazı) bazı kurumlar için yeterli, bazıları için değil, bunu hukuk ekibine sor. Ekip zaten birini işletiyorsa, diğerine geçmenin bedeli (client, sorgular, operasyon araçları) çoğu zaman özellik farkından büyük.
Üretimde Dikkat
Yükseltmeyi bir proje gibi planla: son 8.19.x'e geç, deprecation API'sini ve uygulama loglarındaki Warning: 299 header'larını temizle, snapshot al, önce bir test cluster'ında dene. Yükseltilmiş bir node geri alınamıyor.
Client'ı ve sunucuyu birlikte güncelle. 9.x client 9.x sunucuyla çalışıyor; 8.x sunucuya karşı 9.x client kullanma (10. yazı). Sunucu yükseltmesinden önce client'ın 8.x'te kalması ve yükseltmeden sonra güncellenmesi gerekiyor.
Minor sürümleri de oku. 9.1'deki ES|QL kısmi sonuç değişikliği ve 9.4'teki time series değişikliği gibi maddeler minor sürümlerde geldi. Her yükseltmeden önce aradaki bütün minor'ların breaking changes bölümüne bak ve 7. yazıdaki rank-eval ile 10. yazıdaki testleri yeni sürümle çalıştır.
Elasticsearch'ten OpenSearch'e (ya da tersine) geçiş bir yükseltme değil, bir migration. Snapshot'lar iki motor arasında taşınamıyor varsayımıyla planla; veriyi kaynaktan (Bookstore'da SQL Server) yeni motora yeniden yükle.
Sık Düşülen Tuzaklar
Deprecation uyarılarını görmezden gelmek. 8.19'daki Warning header'ı 9.x'te bir 400 hatası.
8.x'ten 9.x'e 8.19'u atlayarak geçmeye çalışmak. 9.1 ve sonrasına yalnız 8.19'dan geçiliyor.
Yükseltmeden önce snapshot almamak. 9.x'in yazdığı index'i 8.x açamıyor (indexCreatedVersionMajor is in the future: 10).
"OpenSearch, Elasticsearch'le uyumlu" demek. Çekirdek ortak; Elastic'in 9.x client'ı 406 alıyor, synonyms API ve ES|QL yok.
Elastic client'ın bazı isteklerinin OpenSearch'e karşı çalışmasına güvenmek. Gövdesiz istekler geçiyor, aramalar geçmiyor; ilk testte değil production'da fark edersin.
Managed servisin sürümünü kontrol etmemek. Amazon OpenSearch Service, OpenSearch'ün son sürümünün birkaç sürüm gerisinde.
Küçük Bir Deneme
★☆☆ 8.19.25 ile bir node aç, books-v1'e random_score kullanan bir sorgu gönder ("random_score": { "seed": 42 }, alan vermeden). Bir Warning dönüyor mu? Aynı sorguyu 9.5.6'da çalıştır ve sonuç sırasını karşılaştır.
★★☆ search/books.index.json'u OpenSearch'te çalışacak şekilde uyarla: synonyms_set yerine synonyms listesi, ICU (International Components for Unicode; Unicode metin işleme kütüphanesi) plugin'ini Dockerfile'da kur. 36 kitabı yükle ve 4. yazıdaki "kurk mantolu" ve "novel" aramalarını iki motorda karşılaştır.
★★★ Bookstore.Search'e bir IBookSearch interface'i ekle, Elasticsearch ve OpenSearch için iki implementasyon yaz. Hangi parçalar ortak kalıyor (sorgu parametreleri, sonuç modeli), hangileri ayrışıyor (facet'ler, did-you-mean, autocomplete)? Bu soyutlamanın bedeli bir arama motorunu değiştirme ihtimaline değer mi?
Seri burada bitiyor. LIKE'ın yetmediği yerden başlayıp Bookstore için inverted index, mapping, Türkçe analyzer'lar, SQL Server senkronizasyonu, Query DSL, relevance ölçümü, autocomplete, facet'ler, .NET client, alias'lı yaşam döngüsü ve production'ı kurduk. Bir sonraki adım, kelime eşleşmesinin yetmediği yer: anlamca benzer sonuçlar. RAG serisi aynı Elasticsearch'te vektör aramasını ve bu serideki BM25 (1. yazıdaki relevance formülü) aramasıyla birleştirmeyi anlatıyor.