ORTA
Query DSL
Elasticsearch'ün sorgu dili JSON tabanlıdır. İki ana kategori vardır: Query context (relevance score hesaplar) ve Filter context (yes/no, cache'lenir, daha hızlı).
Kod örneği tercihiBu sayfadaki istemci örneklerini birlikte değiştirir.
Karar Rehberi
| Durum | Öneri | Örnek veya gerekçe |
|---|---|---|
| match | Uygun: Full-text arama | Ürün arama kutusu |
| term | Uygun: Keyword exact match | Status filtre, enum |
| bool | Uygun: Karmaşık kombinasyonlar | Filtre + arama + boost |
| range | Uygun: Sayısal/tarih aralık | Fiyat: 100-500 TL |
| match_phrase | Uygun: Sıralı kelime eşleşmesi | "kırmızı spor ayakkabı" |
| multi_match | Uygun: Birden fazla field | name + description arama |
| function_score | Uygun: Custom ranking | Popülerlik boost |
Bool Query Yapısı
# Kompleks bool query: e-ticaret ürün arama
curl -X GET "http://localhost:9200/products/_search" -H "Content-Type: application/json" -d'
{
"query": {
"bool": {
"must": [
{ "multi_match": {
"query": "spor ayakkabı",
"fields": ["name^3", "description", "tags^2"],
"type": "best_fields",
"fuzziness": "AUTO"
}}
],
"filter": [
{ "term": { "is_active": true } },
{ "range": { "price": { "gte": 500, "lte": 5000 } } },
{ "terms": { "category": ["spor-ayakkabi", "sneaker"] } }
],
"should": [
{ "term": { "brand": { "value": "nike", "boost": 2.0 } } },
{ "range": { "stock": { "gte": 10 } } }
],
"must_not": [
{ "term": { "status": "discontinued" } }
],
"minimum_should_match": 1
}
},
"highlight": {
"fields": { "name": {}, "description": {} }
},
"sort": [
{ "_score": "desc" },
{ "price": "asc" }
],
"from": 0,
"size": 20,
"_source": ["name", "price", "category", "brand"]
}'
public async Task<SearchResult<Product>> SearchProductsAsync(ProductSearchRequest request)
{
var response = await _client.SearchAsync<Product>(s => s
.Index("products")
.From(request.Page * request.PageSize)
.Size(request.PageSize)
.Query(q => q
.Bool(b =>
{
b.Must(mu => mu
.MultiMatch(mm => mm
.Query(request.Query)
.Fields(new[] { "name^3", "description", "tags^2" })
.Type(TextQueryType.BestFields)
.Fuzziness(new Fuzziness("AUTO"))));
b.Filter(
f => f.Term(t => t.Field(p => p.IsActive).Value(true)),
f => f.Range(r => r.NumberRange(nr => nr
.Field(p => p.Price)
.Gte(request.MinPrice)
.Lte(request.MaxPrice))),
f => f.Terms(t => t
.Field(p => p.Category)
.Terms(new TermsQueryField(
request.Categories.Select(c => FieldValue.String(c)).ToArray())))
);
b.Should(
sh => sh.Term(t => t
.Field(p => p.Brand)
.Value(request.PreferredBrand)
.Boost(2.0f)),
sh => sh.Range(r => r.NumberRange(nr => nr
.Field(p => p.Stock).Gte(10)))
);
b.MustNot(mn => mn
.Term(t => t.Field("status").Value("discontinued")));
b.MinimumShouldMatch(1);
return b;
}))
.Highlight(h => h
.Fields(f => f
.Add("name", new HighlightField())
.Add("description", new HighlightField())))
.Sort(so => so
.Score(ScoreSortOrder.Desc)
.Field(p => p.Price, SortOrder.Asc))
.SourceIncludes(new[] { "name", "price", "category", "brand" }));
return new SearchResult<Product>(
response.Documents.ToList(),
response.Total,
response.Took);
}
Örnek: E-ticaret arama kutusunda kullanıcı "nike kırmızı 42" yazar. Bool query: must=multi_match("nike kırmızı 42"), filter=[is_active:true, stock>0], should=[brand:nike boost:3]. Filter cache'lenir, must scoring yapar. Sonuç: hızlı + alakalı.
term vs match: term query text field'larda ÇALIŞMAZ çünkü text field'lar analyzed'dır (lowercase vb.). Keyword field'larda term, text field'larda match kullanın. Bu en yaygın ES hatasıdır.
Anti-Pattern: term query on text field
# BU ÇALIŞMAZ! "Nike Air Max" text field'da analyzed → "nike", "air", "max" token'larına dönüşür
# term query exact match arar → "Nike Air Max" bulunamaz
curl -X GET "http://localhost:9200/products/_search" -H "Content-Type: application/json" -d'
{
"query": {
"term": { "name": "Nike Air Max" }
}
}'
# Sonuç: 0 hit (çünkü inverted index'te "Nike Air Max" yok, "nike" var)
# Text field için: match query (analyzed, tokenize edilir)
curl -X GET "http://localhost:9200/products/_search" -H "Content-Type: application/json" -d'
{
"query": {
"bool": {
"must": [
{ "match": { "name": "Nike Air Max" } }
],
"filter": [
{ "term": { "category": "spor-ayakkabi" } },
{ "term": { "is_active": true } }
]
}
}
}'
# match → text field (analyzed) ✅
# term → keyword field (not analyzed) ✅