Function Score Query — Skor Özelleştirme
Giriş — Google'ın Sırrı
Google sadece anahtar kelime eşleştirmesi yapsaydı, ilk sonuç genellikle en çok spam içeren site olurdu. Google'ı güçlü yapan şey, sayfa sıralamasında onlarca ek sinyal kullanmasıdır: popülerlik (PageRank), güncellik, kullanıcının konumu, tıklanma oranı ve daha yüzlercesi.
Elasticsearch'ün varsayılan BM25 scoring'i text relevance için mükemmeldir ama gerçek dünyada sadece metin benzerliği yetmez. Bir e-ticaret sitesinde popüler ürünler öne çıkmalı. Bir haber sitesinde güncel haberler öncelikli olmalı. Bir restoran uygulamasında yakındaki restoranlar daha üstte görünmeli.
İşte function_score query tam bu iş için var. BM25 skorunu ek fonksiyonlarla modifiye ederek, iş mantığınıza uygun özel sıralama oluşturmanızı sağlar. Bu ders, function_score'un her parametresini, her fonksiyon tipini ve gerçek dünya uygulamalarını derinlemesine ele alacak.
1. Function Score Temelleri
1.1 Yapı
GET /products/_search
{
"query": {
"function_score": {
"query": { ... }, // Temel query (BM25 skorunu üretir)
"functions": [ ... ], // Ek fonksiyonlar (skoru modifiye eder)
"score_mode": "multiply", // Fonksiyonlar arası birleştirme
"boost_mode": "multiply", // Fonksiyon skoru + query skoru birleştirme
"max_boost": 42, // Fonksiyonların üretebileceği max boost
"min_score": 5 // Bu skorun altındaki sonuçları at
}
}
}1.2 score_mode — Fonksiyonlar Arası Birleştirme
Birden fazla fonksiyon tanımladığınızda, bunların skorlarını nasıl birleştireceğinizi score_mode belirler:
┌──────────────┬──────────────────────────────────────────────────┐
│ score_mode │ Açıklama │
├──────────────┼──────────────────────────────────────────────────┤
│ multiply │ Tüm fonksiyon skorlarını çarp (varsayılan) │
│ sum │ Tüm fonksiyon skorlarını topla │
│ avg │ Ortalama al │
│ first │ İlk eşleşen fonksiyonun skorunu kullan │
│ max │ En yüksek fonksiyon skorunu kullan │
│ min │ En düşük fonksiyon skorunu kullan │
└──────────────┴──────────────────────────────────────────────────┘Örnek — İki fonksiyonun birleşimi:
Fonksiyon A skoru: 2.0
Fonksiyon B skoru: 3.0
score_mode: multiply → 2.0 × 3.0 = 6.0
score_mode: sum → 2.0 + 3.0 = 5.0
score_mode: avg → (2.0 + 3.0) / 2 = 2.5
score_mode: max → 3.0
score_mode: min → 2.01.3 boost_mode — Query Skoru ile Birleştirme
Fonksiyonların birleşik skoru (score_mode sonucu) ile orijinal query skorunun nasıl birleştirileceğini belirler:
┌──────────────┬──────────────────────────────────────────────────┐
│ boost_mode │ Formül │
├──────────────┼──────────────────────────────────────────────────┤
│ multiply │ query_score × function_score (varsayılan) │
│ replace │ function_score (query_score'u yok say) │
│ sum │ query_score + function_score │
│ avg │ (query_score + function_score) / 2 │
│ max │ max(query_score, function_score) │
│ min │ min(query_score, function_score) │
└──────────────┴──────────────────────────────────────────────────┘Senaryo: Query skoru = 10, Fonksiyon skoru = 3
boost_mode: multiply → 10 × 3 = 30
boost_mode: replace → 3
boost_mode: sum → 10 + 3 = 13
boost_mode: avg → (10 + 3) / 2 = 6.5💡 İpucu:
boost_mode: multiplyçoğu durumda en doğal sonuçları verir çünkü orijinal relevance'ı korur ve üzerine boost ekler.replacekullanırsanız metin benzerliği tamamen göz ardı edilir.
2. weight — En Basit Fonksiyon
weight fonksiyonu, eşleşen dokümanlara sabit bir çarpan uygular. Genellikle filter ile birlikte kullanılır:
GET /products/_search
{
"query": {
"function_score": {
"query": { "match": { "title": "laptop" } },
"functions": [
{
"filter": { "term": { "is_promoted": true } },
"weight": 5
},
{
"filter": { "term": { "is_in_stock": true } },
"weight": 2
},
{
"filter": { "term": { "brand.keyword": "Apple" } },
"weight": 1.5
}
],
"score_mode": "multiply",
"boost_mode": "multiply"
}
}
}Bu örnekte:
Tanıtılan ürünler 5x boost alır
Stokta olan ürünler 2x boost alır
Apple ürünleri 1.5x boost alır
Stokta olan, tanıtılan bir Apple laptop: 5 × 2 × 1.5 = 15x boost
2.1 Filter + Weight Kombinasyonu
Her fonksiyonun bir filter'ı olabilir. Filter eşleşmezse o fonksiyon skoru 1 olur (yani etkisiz):
"functions": [
{
"filter": { "range": { "rating": { "gte": 4.5 } } },
"weight": 3
}
]
// rating >= 4.5 olan dokümanlar 3x boost alır
// Diğerleri 1x (boost yok)3. field_value_factor — Alan Değerine Göre Boost
3.1 Temel Kullanım
Dokümanın bir sayısal alanının değerini skor hesaplamasında kullanır:
GET /products/_search
{
"query": {
"function_score": {
"query": { "match": { "title": "laptop" } },
"functions": [
{
"field_value_factor": {
"field": "sales_count",
"factor": 1.2,
"modifier": "log1p",
"missing": 1
}
}
],
"boost_mode": "multiply"
}
}
}3.2 modifier Seçenekleri
modifier, field değerine uygulanacak matematiksel dönüşümü belirler:
┌──────────────┬──────────────────┬──────────────────────────────────┐
│ modifier │ Formül │ Açıklama │
├──────────────┼──────────────────┼──────────────────────────────────┤
│ none │ value × factor │ Ham değer (varsayılan) │
│ log │ log(value×factor)│ Logaritmik — çok büyük değerleri │
│ │ │ baskılar │
│ log1p │ log(1+value×f) │ log ama 0 değeri handle eder │
│ log2p │ log(2+value×f) │ log1p gibi, 2 offset │
│ ln │ ln(value×factor) │ Doğal logaritma │
│ ln1p │ ln(1+value×f) │ ln ama 0 handle eder │
│ ln2p │ ln(2+value×f) │ ln1p gibi, 2 offset │
│ square │ (value×f)² │ Kare — yüksek değerleri aşırı │
│ │ │ ödüllendirir │
│ sqrt │ √(value×factor) │ Karekök — yüksek değerlerin │
│ │ │ etkisini azaltır │
│ reciprocal │ 1/(value×factor) │ Ters orantı │
└──────────────┴──────────────────┴──────────────────────────────────┘modifier seçimi pratikte:
sales_count = 0, 10, 100, 1000, 100000
none: 0, 12, 120, 1200, 120000 ← Aşırı fark!
log1p: 0, 2.5, 4.8, 7.1, 11.7 ← Dengeli ✅
sqrt: 0, 3.5, 11, 35, 355 ← Orta
square: 0, 144, 14400, 1.4M, 14.4B ← Aşırı!💡 İpucu: Çoğu durumda `log1p` en iyi seçimdir. Değer 0 olduğunda güvenlidir (
log(1+0) = 0) ve çok büyük değerlerin (100K satış vs 1K satış) makul bir skor farkı oluşturmasını sağlar.
3.3 factor ve missing
`factor`: Field değerini bu sayıyla çarpar. Boost'un "şiddetini" ayarlar
`missing`: Field değeri yoksa (null/eksik) kullanılacak varsayılan değer
{
"field_value_factor": {
"field": "popularity",
"factor": 0.5, // Popularity'nin etkisini yarıya indir
"modifier": "log1p",
"missing": 0 // Popularity yoksa 0 varsay (log1p(1+0) = 0)
}
}⚠️ Dikkat:
missingdeğeri belirtmezseniz ve dokümanın ilgili alanı yoksa, Elasticsearch hata verir! Her zamanmissingbelirtin.
4. random_score — Rastgele Sıralama
4.1 Temel Kullanım
Arama sonuçlarına kontrollü rastgelelik ekler. A/B testi, "keşfet" özelliği veya "her refresh farklı sonuç" senaryoları için kullanılır:
GET /products/_search
{
"query": {
"function_score": {
"query": { "match_all": {} },
"functions": [
{
"random_score": {
"seed": 12345,
"field": "_seq_no"
}
}
]
}
}
}4.2 seed ve Tekrarlanabilirlik
seed parametresi aynı değer verildiğinde aynı rastgele sıralama üretir (deterministic random):
// Aynı seed → aynı sıralama (aynı kullanıcı her zaman aynı sonuçları görür)
"random_score": { "seed": "user_123", "field": "_seq_no" }
// Farklı seed → farklı sıralama
"random_score": { "seed": "user_456", "field": "_seq_no" }
// Seed vermezsen → her seferde farklı sıralama
"random_score": {}Yaygın seed stratejileri:
Kullanıcı ID → Her kullanıcı kendi tutarlı sıralamasını görür
Kullanıcı ID + Tarih → Günlük farklı sıralama ama gün içinde tutarlı
Timestamp → Her istekte farklı (gerçek rastgele)
4.3 field Parametresi
field, rastgelelik hesaplamasında kullanılan alan. _seq_no önerilir çünkü her dokümanda vardır ve unique'tir:
"random_score": {
"seed": 42,
"field": "_seq_no"
}⚠️ Dikkat:
fieldparametresi verilmezse, Elasticsearch dahili Lucene doc ID kullanır. Ancak merge sonrası doc ID'ler değişebileceğinden, aynı seed ile farklı sonuçlar alabilirsiniz. Her zaman"field": "_seq_no"kullanın.
5. script_score — Özel Skor Hesaplama
5.1 Painless Script ile Custom Scoring
En esnek fonksiyon. Painless script ile istediğiniz formülü yazabilirsiniz:
GET /products/_search
{
"query": {
"function_score": {
"query": { "match": { "title": "laptop" } },
"functions": [
{
"script_score": {
"script": {
"source": """
double popularity = doc['popularity'].value;
double recency = 1.0 / (1.0 + Math.exp(-0.1 * (doc['days_since_publish'].value - 30)));
return Math.log(1 + popularity) * (1 - recency);
"""
}
}
}
],
"boost_mode": "multiply"
}
}
}5.2 Parametreli Script
GET /products/_search
{
"query": {
"function_score": {
"query": { "match": { "title": "laptop" } },
"functions": [
{
"script_score": {
"script": {
"source": """
double base = doc[params.field].value;
return Math.log(1 + base) * params.weight;
""",
"params": {
"field": "sales_count",
"weight": 2.0
}
}
}
}
]
}
}
}5.3 Stored Script
Sık kullanılan script'leri saklayabilirsiniz:
// Script'i kaydet
PUT _scripts/popularity-boost
{
"script": {
"lang": "painless",
"source": """
double pop = doc[params.pop_field].value;
double factor = params.containsKey('factor') ? params.factor : 1.0;
return Math.log1p(pop) * factor;
"""
}
}
// Kullanım
GET /products/_search
{
"query": {
"function_score": {
"query": { "match": { "title": "laptop" } },
"functions": [
{
"script_score": {
"script": {
"id": "popularity-boost",
"params": {
"pop_field": "sales_count",
"factor": 1.5
}
}
}
}
]
}
}
}5.4 Script Performans İpuçları
// ❌ YAVAŞ — Her dokümanda string arama
"source": "doc['tags'].value.contains('premium') ? 2.0 : 1.0"
// ✅ HIZLI — Filter ile ayır, weight ile boost ver
"functions": [
{ "filter": { "term": { "tags": "premium" } }, "weight": 2 }
]⚠️ Dikkat:
script_scoreher eşleşen doküman için çalıştırılır. 1 milyon doküman eşleşiyorsa, script 1 milyon kez çalışır! Mümkünsefield_value_factorveyafilter + weightkullanın — bunlar daha optimize edilmiştir.
6. Decay Functions — Mesafe/Zaman/Sayısal Azalma
6.1 Decay Nedir?
Decay fonksiyonları, bir origin (merkez) noktasından uzaklaştıkça skorun azalmasını sağlar. Üç tip vardır:
Skor
▲
│ ██████████
│ █ █
│ █ █ gauss (çan eğrisi)
│ █ ██
│ █ ████████████
│
│ ██████████
│ █ █
│ █ █ exp (üstel azalma)
│ █ █
│ █ ██
│ █ ████████████
│
│ ██████████
│ █ ████
│ █ ████
│ █ ████ linear (doğrusal azalma)
│ █ ████
│ █ ████
└──────────────────────────────► Mesafe/Zaman/Değer
origin scale6.2 Decay Parametreleri
Her decay fonksiyonunun dört parametresi vardır:
┌──────────┬──────────────────────────────────────────────────────┐
│ Parametre│ Açıklama │
├──────────┼──────────────────────────────────────────────────────┤
│ origin │ Merkez nokta — "en iyi" değer. Skor burada 1.0 │
│ scale │ origin'den bu kadar uzaklıkta skor = decay │
│ offset │ origin ± offset aralığında skor 1.0 kalır │
│ │ (tolerance zone) │
│ decay │ origin + offset + scale mesafesindeki skor değeri │
│ │ Varsayılan: 0.5 │
└──────────┴──────────────────────────────────────────────────────┘Görselleştirme:
Skor
1.0 │ ████████████████████
│ ← offset → ██
│ ██
0.5 │ ........................██............ ← decay = 0.5
│ ██
│ ████
0.0 │ ████████
└──────────────────────────────────────────
origin scale
|← offset →|← scale →|6.3 Geo Distance Decay — Yakınlık Boost
GET /restaurants/_search
{
"query": {
"function_score": {
"query": { "match": { "cuisine": "türk mutfağı" } },
"functions": [
{
"gauss": {
"location": {
"origin": { "lat": 41.0082, "lon": 28.9784 },
"scale": "5km",
"offset": "500m",
"decay": 0.5
}
}
}
],
"boost_mode": "multiply"
}
}
}Bu sorgu:
Sultanahmet'ten (origin) 500m içindeki restoranlar → skor 1.0
500m + 5km = 5.5km uzaklıkta → skor 0.5
5.5km'den uzakta → skor hızla azalır (gauss eğrisi)
6.4 Date Decay — Güncellik Boost
GET /articles/_search
{
"query": {
"function_score": {
"query": { "match": { "content": "elasticsearch" } },
"functions": [
{
"gauss": {
"publish_date": {
"origin": "now",
"scale": "30d",
"offset": "7d",
"decay": 0.5
}
}
}
],
"boost_mode": "multiply"
}
}
}Bu sorgu:
Son 7 gün içinde yayınlanan makaleler → skor 1.0 (offset)
7 + 30 = 37 gün önce yayınlanan → skor 0.5
Daha eski → skor hızla düşer
6.5 Numeric Decay — Sayısal Değer Yakınlığı
GET /products/_search
{
"query": {
"function_score": {
"query": { "match": { "category": "laptop" } },
"functions": [
{
"exp": {
"price": {
"origin": 15000,
"scale": 5000,
"offset": 1000,
"decay": 0.3
}
}
}
],
"boost_mode": "multiply"
}
}
}Bu sorgu:
Fiyatı 14000-16000 (±1000 offset) arası → skor 1.0
Fiyatı 9000 veya 21000 (±6000) → skor 0.3
Fiyat origin'den uzaklaştıkça skor azalır
6.6 Gauss vs Exp vs Linear
gauss exp linear
─────────────────────────────────────────────────────────────────
Azalma şekli Çan eğrisi Üstel Doğrusal
Başlangıçta (yakın) Yavaş azalır Hızlı azalır Sabit hızda
Ortada Hızlı azalır Yavaşlar Sabit hızda
Uzakta Çok yavaş azalır Çok yavaş Tam 0 olur
Ne zaman kullan?
gauss: "Ortadaki değerler önemli değil" — restoran yakınlığı
exp: "Hemen azalsın" — haber güncelliği
linear: "Eşit hızda azalsın" — fiyat aralığıSayısal örnek (scale=10, decay=0.5):
Mesafe: 0 2 5 8 10 15 20
gauss: 1.0 0.98 0.88 0.68 0.50 0.22 0.06
exp: 1.0 0.93 0.79 0.64 0.50 0.32 0.20
linear: 1.0 0.90 0.75 0.60 0.50 0.25 0.00 ← 0'a ulaşır!⚠️ Dikkat:
lineardecay, belirli bir noktadan sonra skor 0 olur.gaussveexpise asimptotik olarak 0'a yaklaşır ama asla tam 0 olmaz. Sonuçlardan tamamen çıkmasını istemiyorsanızgaussveyaexpkullanın.
7. Birden Fazla Fonksiyonun Birleşimi
7.1 E-Commerce Örneği — Tam Kapsamlı
GET /products/_search
{
"query": {
"function_score": {
"query": {
"bool": {
"must": [
{ "multi_match": {
"query": "kablosuz kulaklık",
"fields": ["title^3", "description", "brand^2"]
}}
],
"filter": [
{ "term": { "is_active": true } },
{ "range": { "price": { "gte": 50, "lte": 2000 } } }
]
}
},
"functions": [
{
"filter": { "term": { "is_promoted": true } },
"weight": 3
},
{
"field_value_factor": {
"field": "sales_count",
"modifier": "log1p",
"factor": 0.5,
"missing": 0
}
},
{
"field_value_factor": {
"field": "rating",
"modifier": "none",
"factor": 1,
"missing": 3.0
}
},
{
"gauss": {
"created_at": {
"origin": "now",
"scale": "90d",
"offset": "7d",
"decay": 0.5
}
}
}
],
"score_mode": "sum",
"boost_mode": "multiply",
"max_boost": 50
}
}
}Bu sorgu ne yapıyor?
query: "kablosuz kulaklık" için BM25 text relevance skoru üretiris_promoted: true→ 3 puan eklesales_count→ log1p ile popülerlik puanı (log(1 + sales × 0.5))rating→ Doğrudan puan değeri (1-5 arası)created_at→ Yeni ürünlere bonus (7 gün içi tam puan, 97 gün → yarı puan)score_mode: sum→ Fonksiyon puanları toplanırboost_mode: multiply→ BM25 skoru × fonksiyon toplamımax_boost: 50→ Fonksiyonların toplam etkisi max 50 ile sınırlı
7.2 Haber Sitesi Örneği
GET /articles/_search
{
"query": {
"function_score": {
"query": {
"multi_match": {
"query": "yapay zeka",
"fields": ["title^5", "summary^2", "content"]
}
},
"functions": [
{
"exp": {
"publish_date": {
"origin": "now",
"scale": "3d",
"offset": "1h",
"decay": 0.3
}
},
"weight": 5
},
{
"field_value_factor": {
"field": "view_count",
"modifier": "log2p",
"factor": 0.1,
"missing": 0
}
},
{
"filter": { "term": { "is_breaking": true } },
"weight": 10
},
{
"filter": { "term": { "category": "teknoloji" } },
"weight": 1.5
}
],
"score_mode": "sum",
"boost_mode": "multiply"
}
}
}8. Java ile Function Score
8.1 Temel Function Score Query
public class FunctionScoreSearchService {
private final ElasticsearchClient client;
public FunctionScoreSearchService(ElasticsearchClient client) {
this.client = client;
}
public SearchResponse<Product> searchWithBoost(String queryText) throws IOException {
return client.search(s -> s
.index("products")
.query(q -> q
.functionScore(fs -> fs
.query(fq -> fq
.multiMatch(mm -> mm
.query(queryText)
.fields("title^3", "description")
)
)
.functions(
// Popülerlik boost
fn -> fn
.fieldValueFactor(fvf -> fvf
.field("sales_count")
.modifier(FieldValueFactorModifier.Log1p)
.factor(0.5)
.missing(0.0)
),
// Stokta olanlar 2x
fn -> fn
.filter(f -> f.term(t -> t
.field("in_stock")
.value(true)
))
.weight(2.0),
// Güncellik decay
fn -> fn
.gauss(g -> g
.date(d -> d
.field("created_at")
.placement(p -> p
.origin("now")
.scale("30d")
.offset("3d")
.decay(0.5)
)
)
)
)
.scoreMode(FunctionScoreMode.Sum)
.boostMode(FunctionBoostMode.Multiply)
.maxBoost(100.0)
)
)
.size(20),
Product.class
);
}
public SearchResponse<Product> searchWithRandomization(
String queryText, String userId) throws IOException {
return client.search(s -> s
.index("products")
.query(q -> q
.functionScore(fs -> fs
.query(fq -> fq
.match(m -> m.field("category").query(queryText))
)
.functions(fn -> fn
.randomScore(rs -> rs
.seed(userId)
.field("_seq_no")
)
)
.boostMode(FunctionBoostMode.Replace)
)
)
.size(20),
Product.class
);
}
}8.2 Script Score ile Custom Ranking
public SearchResponse<Product> searchWithCustomScore(
String queryText, double userLat, double userLon) throws IOException {
return client.search(s -> s
.index("products")
.query(q -> q
.functionScore(fs -> fs
.query(fq -> fq
.match(m -> m.field("title").query(queryText))
)
.functions(fn -> fn
.scriptScore(ss -> ss
.script(sc -> sc
.inline(i -> i
.source("""
double popularity = Math.log1p(doc['sales_count'].value);
double rating = doc['rating'].value;
double freshness = 1.0 / (1.0 + (System.currentTimeMillis()
- doc['created_at'].value.toInstant().toEpochMilli())
/ 86400000.0 / 30.0);
return (popularity * 0.3 + rating * 0.5 + freshness * 0.2);
""")
)
)
)
)
.boostMode(FunctionBoostMode.Multiply)
)
)
.size(20),
Product.class
);
}9. Performans ve Best Practices
9.1 Performans Kuralları
┌──────────────────────────────────┬──────────┬──────────────────────────┐
│ Fonksiyon │ Hız │ Not │
├──────────────────────────────────┼──────────┼──────────────────────────┤
│ weight (filter ile) │ ⭐⭐⭐⭐⭐ │ En hızlı — sadece çarpma │
│ field_value_factor │ ⭐⭐⭐⭐ │ Doc values'dan okur │
│ random_score │ ⭐⭐⭐⭐ │ Hash hesaplama │
│ decay (gauss/exp/linear) │ ⭐⭐⭐ │ Matematik hesaplama │
│ script_score (basit) │ ⭐⭐⭐ │ Script compile + execute │
│ script_score (karmaşık) │ ⭐⭐ │ Her doküman için çalışır │
└──────────────────────────────────┴──────────┴──────────────────────────┘9.2 Best Practices
✅ YAP:
• filter + weight kullan mümkünse (en hızlı)
• field_value_factor'da log1p modifier kullan (büyük değerleri dengele)
• random_score'da seed + _seq_no field kullan (tutarlılık)
• max_boost ile üst sınır koy (outlier'ları engelle)
• Stored script kullan (compile cache'lenir)
• explain: true ile skoru debug et
❌ YAPMA:
• Her isteğe script_score ekleme (performans maliyeti)
• modifier: none ile büyük değerli alanları kullanma (patlama riski)
• boost_mode: replace kullanma (text relevance kaybolur) — bilerek yapmıyorsan
• Çok fazla fonksiyon ekleme (5-6'dan fazlası nadir gerekir)
• missing parametresini unutma (hata kaynağı)9.3 Debug — explain ile Skor Analizi
GET /products/_search
{
"explain": true,
"query": {
"function_score": {
"query": { "match": { "title": "laptop" } },
"functions": [
{
"field_value_factor": {
"field": "sales_count",
"modifier": "log1p",
"missing": 0
}
}
]
}
}
}explain: true yanıtı, her dokümanın skor hesaplamasını adım adım gösterir — hangi fonksiyonun ne kadar etki ettiğini görürsünüz.
10. Özet
function_score, BM25 text relevance skorunu iş mantığına göre modifiye etmenizi sağlar — popülerlik, güncellik, konum gibi sinyaller ekler
score_mode fonksiyonlar arası birleştirmeyi (multiply, sum, avg, max, min, first), boost_mode fonksiyon + query skoru birleştirmesini belirler
weight en basit ve en hızlı fonksiyondur — filter ile birlikte koşullu boost verir
field_value_factor doküman alanını skora dahil eder.
modifier: log1pbüyük değerlerin etkisini dengeler,missingparametresi zorunludurrandom_score kontrollü rastgelelik sağlar.
seedile aynı kullanıcıya tutarlı sıralama, seed değiştirerek farklı sonuçlar sunabilirsinizscript_score en esnek ama en yavaş fonksiyondur. Mümkünse filter+weight veya field_value_factor tercih edin
Decay fonksiyonları (gauss, exp, linear) origin noktasından uzaklaştıkça skorun azalmasını sağlar: geo distance, tarih güncelliği, fiyat yakınlığı gibi senaryolar için idealdir.
gaussçoğu durumda en doğal sonuçları verir
AI Asistan
Sorularını yanıtlamaya hazır