← Kursa Dön
📄 Text · 35 min

Türkçe Full-Text Search Tam Rehberi

Giriş — Türkçe Neden Zor?

Bir Amerikalı geliştirici Elasticsearch'te İngilizce arama yapıyorsa hayatı kolaydır. standard analyzer seçer, belki bir english stemmer ekler, işi biter. Ama siz Türkçe bir proje geliştiriyorsanız — hoş geldiniz cehennemin yedinci katına.

Türkçe, sondan eklemeli (agglutinative) bir dildir. "ev" kelimesinden "evlerinizdekilerden" gibi bir canavar türeyebilir. "İstanbul" yazarsınız, lowercase filtresi bunu "i̇stanbul" yapar. "ÇALIŞTIRILAMAYACAKLARINDAN" kelimesini stemmer'a verirsiniz, geri "çal" diye bir şey döner. Türkçe apostrofu ("İstanbul'un") tokenizer yanlış yerde böler.

Bu ders, Türkçe arama sorunlarını kökten çözecek. Kopyala-yapıştır yapıp production'a koyabileceğiniz analyzer'lar, mapping'ler ve pattern'lar öğreneceksiniz.


1. Türkçe'nin Text Analysis Zorlukları

1.1 Sondan Eklemeli Yapı (Agglutination)

Türkçe'de bir kelime köküne onlarca ek gelebilir:

ev → ev-ler → ev-ler-imiz → ev-ler-imiz-de → ev-ler-imiz-de-ki-ler-den

"ev" arayan kullanıcı, "evlerinizdekilerden" içeren dokümanı da bulabilmelidir. Stemmer olmadan bu imkansızdır.

1.2 Türkçe Büyük-Küçük Harf Sorunu (İ/I Problemi)

Türkçe'nin en meşhur teknik sorunu budur:

BüyükKüçükStandard lowercaseDoğru lowercase
İii ✓i ✓
Iıi ✗ı ✓

standard analyzer'ın lowercase filter'ı İngilizce kuralları uygular: Ii yapar. Ama Türkçe'de Iı olmalıdır! "IŞIK" araması "ışık" bulamaz, "isik" olarak arar.

// ❌ Yanlış: standard lowercase
POST _analyze
{
  "tokenizer": "standard",
  "filter": ["lowercase"],
  "text": "IŞIK ve İSTANBUL"
}
// Sonuç: ["işik", "ve", "istanbul"] — "ışık" değil "işik"!

// ✅ Doğru: Turkish lowercase
POST _analyze
{
  "tokenizer": "standard",
  "filter": [{"type": "lowercase", "language": "turkish"}],
  "text": "IŞIK ve İSTANBUL"
}
// Sonuç: ["ışık", "ve", "istanbul"] — Doğru!

1.3 Apostrof Sorunu

Türkçe'de özel isimlerin eklerini ayırmak için apostrof kullanılır: "İstanbul'un", "Atatürk'ün". Standard tokenizer apostrofü kelime içi karakter olarak görür — "İstanbul" araması "İstanbul'un" bulamaz!

1.4 Türkçe Stop Words

"ve", "ile", "bir", "bu", "de", "da", "ki", "için" gibi kelimeler arama kalitesini düşürür. Elasticsearch'ün built-in _turkish_ stop words listesi var ama bazen yetersiz kalır.


2. Built-in Turkish Analyzer

Elasticsearch kutudan çıkan bir turkish analyzer sunar:

POST _analyze
{
  "analyzer": "turkish",
  "text": "Türkiye'deki evlerin fiyatları çok yükseldi"
}
// Sonuç: ["türkiy", "evler", "fiyat", "çok", "yüksel"]

Turkish analyzer şu bileşenlerden oluşur:

turkish analyzer =
  standard tokenizer
  + apostrophe token filter
  + lowercase (Turkish locale)
  + stop (_turkish_)
  + keyword_marker
  + stemmer (Turkish snowball)

İyi yanları: I→ı dönüşümü doğru, apostrof filter dahil, stop words dahil, temel stemming var.

Eksikleri: Stemmer bazen agresif ("araba" → "arab"), synonym yok, edge ngram yok, diacritics normalization yok ("şehir" ve "sehir" eşleşmez).


3. ICU Analyzer — Unicode Dostu Alternatif

ICU (International Components for Unicode) plugin'i Türkçe dahil birçok dil için gelişmiş analiz sunar.

3.1 ICU Plugin Kurulumu

bin/elasticsearch-plugin install analysis-icu

# Docker'da:
RUN bin/elasticsearch-plugin install analysis-icu

3.2 ICU Folding — Diacritics Normalization

icu_folding filter'ı aksanlı/özel karakterleri ASCII karşılıklarına dönüştürür:

PUT icu_test
{
  "settings": {
    "analysis": {
      "analyzer": {
        "folded": {
          "type": "custom",
          "char_filter": [{"type": "icu_normalizer", "name": "nfkc_cf"}],
          "tokenizer": "icu_tokenizer",
          "filter": ["icu_folding"]
        }
      }
    }
  }
}

POST icu_test/_analyze
{
  "analyzer": "folded",
  "text": "Şehirdeki çalışanlar güneşli günü"
}
// Sonuç: ["sehirdeki", "calisanlar", "gunesli", "gunu"]

Kullanıcılar Türkçe karakter olmayan klavyelerde "calisan", "gunes", "sehir" yazabilir. ICU folding bunu çözer.

⚠️ Dikkat: ICU folding tek başına kullanılırsa "şık" ve "sık" aynı token'a dönüşür. Bu yüzden multi-field yaklaşımı şarttır — bir field orijinal Türkçe ile, diğeri folded ile.


4. Custom Turkish Analyzer — Production-Ready

4.1 Temel Custom Turkish Analyzer

PUT turkish_search
{
  "settings": {
    "analysis": {
      "char_filter": {
        "quotes_normalizer": {
          "type": "mapping",
          "mappings": [
            "\\u2018 => '", "\\u2019 => '",
            "\\u201C => \"", "\\u201D => \""
          ]
        }
      },
      "filter": {
        "turkish_lowercase": {
          "type": "lowercase",
          "language": "turkish"
        },
        "turkish_stop": {
          "type": "stop",
          "stopwords": "_turkish_"
        },
        "turkish_stemmer": {
          "type": "stemmer",
          "language": "turkish"
        },
        "apostrophe_filter": {
          "type": "apostrophe"
        }
      },
      "analyzer": {
        "turkish_custom": {
          "type": "custom",
          "char_filter": ["quotes_normalizer"],
          "tokenizer": "standard",
          "filter": [
            "apostrophe_filter",
            "turkish_lowercase",
            "turkish_stop",
            "turkish_stemmer"
          ]
        }
      }
    }
  }
}

Test:

POST turkish_search/_analyze
{
  "analyzer": "turkish_custom",
  "text": "İstanbul'daki IŞIKLI evlerin fiyatları düşecek mi?"
}
// Sonuç: ["istanbul", "ışıklı", "ev", "fiyat", "düş"]

Mükemmel! Apostrof atıldı, Türkçe lowercase doğru, stemming çalışıyor, stop words temizlendi.

4.2 Türkçe Synonym Filter

PUT turkish_synonym_search
{
  "settings": {
    "analysis": {
      "filter": {
        "turkish_lowercase": { "type": "lowercase", "language": "turkish" },
        "turkish_stop": { "type": "stop", "stopwords": "_turkish_" },
        "turkish_stemmer": { "type": "stemmer", "language": "turkish" },
        "apostrophe_filter": { "type": "apostrophe" },
        "turkish_synonyms": {
          "type": "synonym_graph",
          "synonyms": [
            "araba, otomobil, araç, vasıta",
            "ev, konut, daire, mesken",
            "güzel, hoş, şirin, latif",
            "büyük, iri, kocaman, devasa",
            "hızlı, çabuk, süratli, seri",
            "doktor, hekim, tabip",
            "telefon, cep telefonu, mobil",
            "bilgisayar, pc, kompüter",
            "okul, mektep, eğitim kurumu"
          ]
        }
      },
      "analyzer": {
        "turkish_index_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "apostrophe_filter", "turkish_lowercase",
            "turkish_stop", "turkish_stemmer"
          ]
        },
        "turkish_search_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": [
            "apostrophe_filter", "turkish_lowercase",
            "turkish_stop", "turkish_synonyms", "turkish_stemmer"
          ]
        }
      }
    }
  }
}

💡 İpucu: synonym_graph filter'ını search-time analyzer'da kullanın. Index-time'da kullanırsanız, yeni synonym eklediğinizde reindex gerekir. Search-time'da sadece index close/open yeterlidir.

⚠️ Dikkat: Synonym filter stemmer'dan önce gelmelidir. Stemmer kelimeyi değiştirirse synonym eşleşmez.

4.3 Genişletilmiş Stop Words

_turkish_ listesi temel kelimeleri içerir. Daha kapsamlı bir liste:

{
  "type": "stop",
  "stopwords": [
    "acaba", "ama", "aslında", "az", "bazı", "belki", "beri", "bile",
    "bir", "birçok", "birkaç", "biz", "bu", "buna", "bunda", "bundan",
    "bunlar", "bunu", "bunun", "burada", "çok", "çünkü", "da", "daha",
    "de", "değil", "diğer", "diye", "eğer", "en", "gibi", "göre",
    "hala", "hangi", "hatta", "hem", "henüz", "hep", "hepsi", "her",
    "hiç", "hiçbir", "için", "ile", "ise", "işte", "kadar", "karşı",
    "kendi", "ki", "kim", "kimse", "mi", "mu", "mü", "mı", "nasıl",
    "ne", "neden", "nerede", "o", "olan", "olarak", "oldu", "olup",
    "ona", "onlar", "onu", "onun", "orada", "öyle", "pek", "şey",
    "siz", "şu", "tamam", "tek", "üzere", "var", "ve", "veya",
    "ya", "yani", "yine", "yoksa", "zaten", "zira"
  ]
}

4.4 Synonym Dosyasından Yükleme

{
  "type": "synonym_graph",
  "synonyms_path": "analysis/turkish_synonyms.txt"
}

config/analysis/turkish_synonyms.txt:

# Ulaşım
araba, otomobil, araç, vasıta
otobüs, belediye otobüsü
# Konut
ev, konut, daire, mesken
# Teknoloji
bilgisayar, pc, kompüter
telefon, cep telefonu, mobil
# Marka kısaltmaları (tek yönlü)
THY => türk hava yolları
PTT => posta

5. Edge N-gram ile Türkçe Autocomplete

"ist" yazan kullanıcı "İstanbul", "istasyon", "istifa" bulabilmelidir.

5.1 Edge N-gram Analyzer

PUT turkish_autocomplete
{
  "settings": {
    "analysis": {
      "filter": {
        "turkish_lowercase": { "type": "lowercase", "language": "turkish" },
        "autocomplete_filter": {
          "type": "edge_ngram",
          "min_gram": 2,
          "max_gram": 15
        }
      },
      "analyzer": {
        "autocomplete_index": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["turkish_lowercase", "autocomplete_filter"]
        },
        "autocomplete_search": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["turkish_lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "analyzer": "autocomplete_index",
        "search_analyzer": "autocomplete_search"
      }
    }
  }
}

⚠️ Kritik: Index-time'da edge_ngram kullanın, search-time'da kullanmayın. Aksi halde "ist" araması "is" ve "i" token'larına da bölünür.

POST turkish_autocomplete/_bulk
{"index":{}}
{"name": "İstanbul"}
{"index":{}}
{"name": "İstasyon"}
{"index":{}}
{"name": "Ankara"}
{"index":{}}
{"name": "Eskişehir"}

GET turkish_autocomplete/_search
{
  "query": { "match": { "name": "ist" } }
}
// Sonuç: İstanbul, İstasyon

5.2 Diacritics-Aware Autocomplete

Kullanıcı Türkçe karakter kullanmadan da arayabilmeli:

PUT turkish_autocomplete_v2
{
  "settings": {
    "analysis": {
      "char_filter": {
        "turkish_diacritics": {
          "type": "mapping",
          "mappings": [
            "ş => s", "Ş => S", "ç => c", "Ç => C",
            "ğ => g", "Ğ => G", "ü => u", "Ü => U",
            "ö => o", "Ö => O", "ı => i", "İ => I"
          ]
        }
      },
      "filter": {
        "autocomplete_filter": {
          "type": "edge_ngram", "min_gram": 2, "max_gram": 15
        }
      },
      "analyzer": {
        "autocomplete_folded_index": {
          "type": "custom",
          "char_filter": ["turkish_diacritics"],
          "tokenizer": "standard",
          "filter": ["lowercase", "autocomplete_filter"]
        },
        "autocomplete_folded_search": {
          "type": "custom",
          "char_filter": ["turkish_diacritics"],
          "tokenizer": "standard",
          "filter": ["lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": {
        "type": "text",
        "fields": {
          "autocomplete": {
            "type": "text",
            "analyzer": "autocomplete_folded_index",
            "search_analyzer": "autocomplete_folded_search"
          }
        }
      }
    }
  }
}

Artık "eskis" de "Eskişehir" bulur!


6. Completion Suggester ile Türkçe

Completion suggester, FST (Finite State Transducer) kullanır — bellekte çalışır ve çok hızlıdır.

6.1 Completion Field Tanımlama

PUT turkish_suggest
{
  "settings": {
    "analysis": {
      "filter": {
        "turkish_lowercase": { "type": "lowercase", "language": "turkish" }
      },
      "analyzer": {
        "suggest_analyzer": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["turkish_lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "name": { "type": "text" },
      "suggest": {
        "type": "completion",
        "analyzer": "suggest_analyzer"
      }
    }
  }
}

6.2 Veri ve Sorgu

POST turkish_suggest/_bulk
{"index":{}}
{"name": "İstanbul", "suggest": {"input": ["İstanbul", "Istanbul", "istanbul"], "weight": 100}}
{"index":{}}
{"name": "İzmir", "suggest": {"input": ["İzmir", "Izmir", "izmir"], "weight": 80}}
{"index":{}}
{"name": "Eskişehir", "suggest": {"input": ["Eskişehir", "Eskisehir"], "weight": 50}}

GET turkish_suggest/_search
{
  "suggest": {
    "city": {
      "prefix": "ist",
      "completion": {
        "field": "suggest",
        "size": 5,
        "fuzzy": { "fuzziness": 1 }
      }
    }
  }
}

💡 İpucu: input alanına hem Türkçe karakterli hem de ASCII versiyonlarını ekleyin. fuzzy ile 1 harf hata toleransı ekleyin.

6.3 Context Suggester

Sonuçları kategoriye göre filtreleme:

PUT turkish_suggest_v2
{
  "mappings": {
    "properties": {
      "suggest": {
        "type": "completion",
        "contexts": [
          { "name": "category", "type": "category" }
        ]
      }
    }
  }
}

POST turkish_suggest_v2/_bulk
{"index":{}}
{"suggest": {"input": "İstanbul", "contexts": {"category": ["şehir"]}}}
{"index":{}}
{"suggest": {"input": "İstanbul Havalimanı", "contexts": {"category": ["havalimanı"]}}}

GET turkish_suggest_v2/_search
{
  "suggest": {
    "filtered": {
      "prefix": "ist",
      "completion": {
        "field": "suggest",
        "contexts": { "category": ["şehir"] }
      }
    }
  }
}

7. Diacritics — Multi-field Yaklaşımı

Türkiye'de kullanıcıların önemli bir kısmı "şehir" yerine "sehir" yazar. Çözüm: multi-field.

PUT turkish_multi_field
{
  "settings": {
    "analysis": {
      "char_filter": {
        "diacritics_filter": {
          "type": "mapping",
          "mappings": [
            "ş => s", "Ş => S", "ç => c", "Ç => C",
            "ğ => g", "Ğ => G", "ü => u", "Ü => U",
            "ö => o", "Ö => O", "ı => i", "I => I"
          ]
        }
      },
      "filter": {
        "turkish_lowercase": { "type": "lowercase", "language": "turkish" },
        "turkish_stop": { "type": "stop", "stopwords": "_turkish_" },
        "turkish_stemmer": { "type": "stemmer", "language": "turkish" },
        "apostrophe_filter": { "type": "apostrophe" }
      },
      "analyzer": {
        "turkish_standard": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["apostrophe_filter", "turkish_lowercase", "turkish_stop", "turkish_stemmer"]
        },
        "turkish_folded": {
          "type": "custom",
          "char_filter": ["diacritics_filter"],
          "tokenizer": "standard",
          "filter": ["apostrophe_filter", "lowercase", "turkish_stop", "turkish_stemmer"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "turkish_standard",
        "fields": {
          "folded": { "type": "text", "analyzer": "turkish_folded" },
          "keyword": { "type": "keyword" }
        }
      }
    }
  }
}

Arama:

GET turkish_multi_field/_search
{
  "query": {
    "multi_match": {
      "query": "sehirdeki calisanlar",
      "fields": ["title^2", "title.folded"],
      "type": "best_fields"
    }
  }
}

title field'ına ^2 boost veriyoruz — doğru Türkçe yazanlar daha yüksek skor alır.


8. Tam Production Mapping

Her şeyi birleştiren, production-ready mapping:

PUT production_turkish_search
{
  "settings": {
    "number_of_shards": 3,
    "number_of_replicas": 1,
    "analysis": {
      "char_filter": {
        "html_cleaner": { "type": "html_strip" },
        "quotes_normalizer": {
          "type": "mapping",
          "mappings": [
            "\\u2018 => '", "\\u2019 => '",
            "\\u201C => \"", "\\u201D => \"",
            "\\u2013 => -", "\\u2014 => -"
          ]
        },
        "diacritics_map": {
          "type": "mapping",
          "mappings": [
            "ş => s", "Ş => S", "ç => c", "Ç => C",
            "ğ => g", "Ğ => G", "ü => u", "Ü => U",
            "ö => o", "Ö => O", "ı => i", "I => I"
          ]
        }
      },
      "filter": {
        "turkish_lowercase": { "type": "lowercase", "language": "turkish" },
        "turkish_stop": { "type": "stop", "stopwords": "_turkish_" },
        "turkish_stemmer": { "type": "stemmer", "language": "turkish" },
        "apostrophe_filter": { "type": "apostrophe" },
        "turkish_synonyms": {
          "type": "synonym_graph",
          "synonyms": [
            "araba, otomobil, araç",
            "ev, konut, daire",
            "telefon, cep telefonu, mobil",
            "bilgisayar, pc, laptop"
          ]
        },
        "autocomplete_filter": {
          "type": "edge_ngram", "min_gram": 2, "max_gram": 15
        }
      },
      "analyzer": {
        "turkish_index": {
          "type": "custom",
          "char_filter": ["html_cleaner", "quotes_normalizer"],
          "tokenizer": "standard",
          "filter": ["apostrophe_filter", "turkish_lowercase", "turkish_stop", "turkish_stemmer"]
        },
        "turkish_search": {
          "type": "custom",
          "char_filter": ["quotes_normalizer"],
          "tokenizer": "standard",
          "filter": ["apostrophe_filter", "turkish_lowercase", "turkish_stop", "turkish_synonyms", "turkish_stemmer"]
        },
        "turkish_folded_index": {
          "type": "custom",
          "char_filter": ["html_cleaner", "quotes_normalizer", "diacritics_map"],
          "tokenizer": "standard",
          "filter": ["apostrophe_filter", "lowercase", "turkish_stop", "turkish_stemmer"]
        },
        "turkish_folded_search": {
          "type": "custom",
          "char_filter": ["quotes_normalizer", "diacritics_map"],
          "tokenizer": "standard",
          "filter": ["apostrophe_filter", "lowercase", "turkish_stop", "turkish_stemmer"]
        },
        "autocomplete_index": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["turkish_lowercase", "autocomplete_filter"]
        },
        "autocomplete_search": {
          "type": "custom",
          "tokenizer": "standard",
          "filter": ["turkish_lowercase"]
        }
      }
    }
  },
  "mappings": {
    "properties": {
      "title": {
        "type": "text",
        "analyzer": "turkish_index",
        "search_analyzer": "turkish_search",
        "fields": {
          "folded": {
            "type": "text",
            "analyzer": "turkish_folded_index",
            "search_analyzer": "turkish_folded_search"
          },
          "autocomplete": {
            "type": "text",
            "analyzer": "autocomplete_index",
            "search_analyzer": "autocomplete_search"
          },
          "keyword": { "type": "keyword" }
        }
      },
      "description": {
        "type": "text",
        "analyzer": "turkish_index",
        "search_analyzer": "turkish_search",
        "fields": {
          "folded": {
            "type": "text",
            "analyzer": "turkish_folded_index",
            "search_analyzer": "turkish_folded_search"
          }
        }
      },
      "category": { "type": "keyword" },
      "tags": { "type": "keyword" },
      "suggest": {
        "type": "completion",
        "analyzer": "autocomplete_search"
      },
      "created_at": { "type": "date" }
    }
  }
}

Bu Mapping Ne Sağlıyor?

ÖzellikNasıl Çalışıyor
Türkçe lowercaseIı doğru dönüşüyor
Apostrof"İstanbul'un" → "istanbul"
Stemming"evlerin" → "ev"
Stop words"ve", "bir", "bu" filtreleniyor
Synonym"araba" ararken "otomobil" de buluyor
Diacritics"sehir" yazınca "şehir" buluyor
Autocomplete"ist" yazınca "istanbul" öneriyor
CompletionHızlı suggest desteği
HTML temizlik<b> etiketleri temizleniyor
Exact match.keyword ile tam eşleşme

Arama Sorgusu

GET production_turkish_search/_search
{
  "query": {
    "bool": {
      "should": [
        {
          "multi_match": {
            "query": "sehirdeki evler",
            "fields": ["title^3", "title.folded^1.5", "description^2", "description.folded"],
            "type": "best_fields",
            "fuzziness": "AUTO"
          }
        }
      ],
      "filter": [
        { "term": { "category": "Emlak" } }
      ]
    }
  },
  "suggest": {
    "title_suggest": {
      "prefix": "ist",
      "completion": {
        "field": "suggest",
        "size": 5,
        "fuzzy": { "fuzziness": 1 }
      }
    }
  },
  "highlight": {
    "fields": { "title": {}, "description": {} },
    "pre_tags": ["<mark>"],
    "post_tags": ["</mark>"]
  }
}

9. Yaygın Hatalar ve Çözümleri

Hata 1: Standard Lowercase Kullanmak

// ❌ Standard lowercase I→i yapar
"filter": ["lowercase"]

// ✅ Turkish lowercase
"filter": [{"type": "lowercase", "language": "turkish"}]

Hata 2: Stemmer'ı Synonym'den Önce Koymak

// ❌ Stemmer kelimeyi değiştirir, synonym eşleşmez
"filter": ["turkish_stemmer", "turkish_synonyms"]

// ✅ Önce synonym, sonra stemmer
"filter": ["turkish_synonyms", "turkish_stemmer"]

Hata 3: Autocomplete'te Search-time Edge Ngram

// ❌ "İstanbul" araması "İ","İs","İst"... ile de eşleşir
"search_analyzer": "autocomplete_index"

// ✅ Search-time'da sadece lowercase yeterli
"search_analyzer": "autocomplete_search"

Hata 4: ICU Folding'i Tek Field'da Kullanmak

// ❌ "şık" ve "sık" ayırt edilemez
"analyzer": "folded_only"

// ✅ Multi-field: orijinal + folded ayrı field
"title": {
  "type": "text",
  "analyzer": "turkish_standard",
  "fields": { "folded": { "type": "text", "analyzer": "turkish_folded" } }
}

Hata 5: Completion Input'a Sadece Orijinal Hali Eklemek

// ❌ "istanbul" yazınca "İstanbul" bulunamaz
{"suggest": {"input": ["İstanbul"]}}

// ✅ Tüm varyantları ekle
{"suggest": {"input": ["İstanbul", "Istanbul", "istanbul"]}}

10. Test Kontrol Listesi

Production'a almadan önce bu testleri geçirin:

// Test 1: Türkçe lowercase
POST production_turkish_search/_analyze
{ "analyzer": "turkish_index", "text": "IŞIK" }
// Beklenen: ["ışık"] — "isik" DEĞİL

// Test 2: Apostrof
POST production_turkish_search/_analyze
{ "analyzer": "turkish_index", "text": "İstanbul'un" }
// Beklenen: ["istanbul"]

// Test 3: Stemming
POST production_turkish_search/_analyze
{ "analyzer": "turkish_index", "text": "evlerinizdeki" }
// Beklenen: kök bulunmalı ("ev" veya benzeri)

// Test 4: Diacritics
POST production_turkish_search/_analyze
{ "analyzer": "turkish_folded_index", "text": "Şehirdeki güneş" }
// Beklenen: ASCII karşılıkları

// Test 5: Stop words
POST production_turkish_search/_analyze
{ "analyzer": "turkish_index", "text": "bu bir ve için" }
// Beklenen: [] — hepsi filtrelenmeli

11. Performans Notları

Multi-field Index Boyutu

4 field'lı yapı (orijinal, folded, autocomplete, keyword) yaklaşık 3-4x daha fazla disk alanı kullanır.

Tavsiye: Autocomplete field'ını sadece title/name gibi kısa alanlara ekleyin. Description gibi uzun alanlara edge ngram eklemeyin — index boyutu patlar.

Edge Ngram Ayarları

// ❌ Çok geniş — her kelime onlarca token üretir
{"min_gram": 1, "max_gram": 20}

// ✅ Makul aralık
{"min_gram": 2, "max_gram": 15}

min_gram: 1 tek harflik token üretir — "a" araması her dokümanı döndürür.

Synonym Dosyası

Binlerce synonym varsa synonyms_path dosya kullanın. Her node'da aynı path'te olmalı. Index close/open yapılmadan güncellenemez.


Özet

  • Türkçe lowercase mutlaka "language": "turkish" ile kullanılmalı — Iı dönüşümü kritiktir

  • Apostrophe filter Türkçe özel isimlerinin eklerini düzgün ayırır: "İstanbul'un" → "istanbul"

  • Turkish stemmer sondan eklemeli yapıyı çözer: "evlerinizdekilerden" → "ev"

  • Diacritics normalization multi-field ile yapılmalı — tek field'da "şık" ve "sık" karışır

  • Edge ngram autocomplete için index-time'da kullanılır, search-time'da kullanılmaz

  • Completion suggester hızlı öneri için ideal — Türkçe + ASCII varyantlarını input'a ekleyin

  • Synonym filter search-time analyzer'da olmalı — yeni eşanlamlı eklendiğinde reindex gerekmez