Fuzzy Query Nedir? Elasticsearch ve Kibana Console – Dev Tools Örneği

Bu makalede Fuzzy Query’den bahsedeceğim. Örneklerimizi Docker Desktop ‘a kuracağımız elasticsearch ve kibana konteynerleri üzerinde gerçekleştireceğiz. Bu şekilde daha hızlı uygulanabilir örnekler elde edebileceğimizi düşünüyorum. Ek olarak bonus bir framework ten de bahsedeceğim. Özetle akış şu şekilde olacak :

  • Fuzzy Query Nedir?
  • Docker Desktop ‘a Elasticsearch ve Kibana Kurulumu
  • Kibana Console – Dev Tools
    • Yeni Index Oluşturma
    • Bulk Data Girişi
    • Fuzzy Query Örneği
    • Boosting Kullanımı

Fuzzy Query Nedir?

Fuzzy Query, arama sorgularında hatalı yazılmış, eksik, fazla karakter içeren veya benzer kelimeleri de eşleştirmek için kullanılan bir tekniktir. Kısaca “benzer eşleşme” yapar. Yani ilgili data içerisinde sorgulanan terim ile tam olarak eşleşmeyen ama benzer olan sonuçları da getirir. Bu işlem arka planda genellikle Levenshtein Distance (Levenshtein Mesafesi) algoritması kullanılarak gerçekleştirilir. Konuyla ilgili detayları incelemek isterseniz daha önce yazdığım “Levenshtein Mesafesi (Levenshtein Distance) Nedir?” blog yazısını inceleyebilirsiniz.

Docker Desktop ‘a Elasticsearch ve Kibana Kurulumu

Docker-compose.yml dosya içeriği aşağıdaki gibi. Dosyayı herhangi bir klasöre attıktan sonra docker-compose up komutu ile konteyner larını kurulmasını ve ayağa kalkmasını sağlayabilirsiniz.

YAML
version: '3.8'
services:
  elasticsearch:
    image: docker.elastic.co/elasticsearch/elasticsearch:8.7.1
    expose: 
      - 9200
    environment:
      - xpack.security.enabled=false
      - "discovery.type=single-node"
      - ELASTIC_USERNAME=elastic
      - ELASTIC_PASSWORD=DkIedPPSCb
    networks:
      - es-net
    ports:
      - 9200:9200
    volumes:
      - elasticsearch-data:/usr/share/elasticsearch/data
  kibana:
    image: docker.elastic.co/kibana/kibana:8.7.1
    environment:
      - ELASTICSEARCH_HOSTS=http://elasticsearch:9200
    expose:
      - 5601
    networks:
      - es-net
    depends_on:
      - elasticsearch
    ports:
      - 5601:5601
    volumes:
      - kibana-data:/usr/share/kibana/data
networks:
  es-net:
    driver: bridge
volumes:
  elasticsearch-data:
    driver: local
  kibana-data:
    driver: local

Kibana Console – Dev Tools

Kurulumu tamamladıysanız, Kibana Console Dev Tools arayüzüne http://localhost:5601/app/dev_tools#/console bu şekilde erişebiliyor olmalısınız. Öncelikle örnek verilerimizi tutacağımız products_st adında yeni bir index oluşturalım.

JSON
PUT /products_st
{
  "mappings": {
    "properties": {
      "name": {
        "type": "text"
      },
      "price": {
        "type": "float"
      }
    }
  }
}

Daha sonra index içerisine bulk olarak dummy data gönderelim. Sorgu sonucunda bulacağımız her sonuç score unun farklı olduğunu görebilmek için yazım hataları olan veya benzer kayıtları bilerek ekledim.

JSON
POST /products_st/_bulk
{ "index": { "_id": 1 } }
{ "name": "Ekran Kartı", "price": 8500.0 }
{ "index": { "_id": 2 } }
{ "name": "Anakart", "price": 3200.0 }
{ "index": { "_id": 3 } }
{ "name": "İşlemci", "price": 6700.0 }
{ "index": { "_id": 4 } }
{ "name": "RAM Bellek", "price": 1200.0 }
{ "index": { "_id": 5 } }
{ "name": "SSD Disk", "price": 2100.0 }
{ "index": { "_id": 6 } }
{ "name": "HDD Disk", "price": 950.0 }
{ "index": { "_id": 7 } }
{ "name": "Kasa", "price": 1800.0 }
{ "index": { "_id": 8 } }
{ "name": "Güç Kaynağı", "price": 1100.0 }
{ "index": { "_id": 9 } }
{ "name": "Monitör", "price": 4500.0 }
{ "index": { "_id": 10 } }
{ "name": "Klavye", "price": 650.0 }
{ "index": { "_id": 11 } }
{ "name": "Mouse", "price": 350.0 }
{ "index": { "_id": 12 } }
{ "name": "Kulaklık", "price": 800.0 }
{ "index": { "_id": 13 } }
{ "name": "Ekran Karı", "price": 8400.0 }
{ "index": { "_id": 14 } }
{ "name": "Ekran Kart", "price": 8300.0 }
{ "index": { "_id": 15 } }
{ "name": "Ekraan Kartı", "price": 8600.0 }
{ "index": { "_id": 16 } }
{ "name": "Ankart", "price": 3100.0 }
{ "index": { "_id": 17 } }
{ "name": "Ana Kart", "price": 3300.0 }
{ "index": { "_id": 18 } }
{ "name": "Ram Belleği", "price": 1250.0 }
{ "index": { "_id": 19 } }
{ "name": "Ram Belleg", "price": 1190.0 }
{ "index": { "_id": 20 } }
{ "name": "SsdDisc", "price": 2050.0 }
{ "index": { "_id": 21 } }
{ "name": "HDDDisc", "price": 940.0 }
{ "index": { "_id": 22 } }
{ "name": "Kasaa", "price": 1790.0 }
{ "index": { "_id": 23 } }
{ "name": "Guc Kaynagı", "price": 1120.0 }
{ "index": { "_id": 24 } }
{ "name": "Monotor", "price": 4400.0 }
{ "index": { "_id": 25 } }
{ "name": "Monitr", "price": 4550.0 }

Buraya kadar herşey tamamsa artık Fuzzy Query mizi Dev Tools üzerinde yazarak nasıl çıktı elde ettiğimizi görebiliriz. Öncelikle bütün kayıtları çekerek datamızın varlığını kontrol edelim.

JSON
GET products_st/_search
{
  "size":50,
  "query": {"match_all": {}}
}

Sorguyu çalıştırdığımızda 25 kaydın gelmesi gerekiyor. Burada “size” değerini vermezseniz default olarak 10 kayıt gelecektir.

elasticsearch-kibana-console-dev-tools

Şimdi “ekran” kelimesini Fuzzy Query ile aratarak eşleşmeleri bulalım ve score larını inceleyelim.

JSON
GET /products_st/_search
{
  "query": {
    "bool": {
      "must": {
        "fuzzy": {
          "name": {
            "value": "ekran",
            "fuzziness": "AUTO"
          }
        }
      }
    }
  }
}

Yukarıda gördüğünüz gibi bulunan her sonuç için bir _score değeri üretiliyor. En yüksek score en iyi eşleşen sonuç anlamına geliyor. Sorgudaki “fuzziness”: “AUTO” değeri Fuzzy Query’nin ne kadar toleranslı olacağını otomatik olarak belirlememizi sağlıyor. Fakat sayısal bir değer verirsek : Örneğin değer olarak “2” verilirse, 2 karakter farkı tolere eder.

Alan bazında boosting vererek ağırlığa göre arama yapmak isterseniz, her alan için boost tanımlayabilir, boosting sayesinde her alana bir ağırlık katsayısı (boost) verebilirsiniz. Böylece daha yüksek boost alan, daha yüksek _score üretir ve daha üst sıralara çıkar.

JSON
GET /products_st/_search
{
  "query": {
    "fuzzy": {
      "name": {
        "value": "kart",
        "fuzziness": "AUTO",
        "boost": 3.0
      }
    }
  }
}

Birden fazla alan için tanımlama yapmak isterseniz, multi_match kullanabilirsiniz. Index imizde “description” adında yeni bir alanın daha olduğunu varsayarsak:

JSON
GET /products_st/_search
{
  "query": {
    "multi_match": {
      "query": "kart",
      "fields": [
        "name^2",
        "description^1"
      ],
      "fuzziness": "AUTO"
    }
  }
}

“name” için 2, “description” için 1 olarak ağırlık verebilir ve bu ağırlıklara göre _score ların üretilmesi sağlanabilir.

Bu konu ile ilgili .Net üzerinde örnekte yapmak istiyorum ama makaleyi daha fazla uzatmamak için burada bitiriyorum. .Net için örnek yapmak isterseniz Elastic.Clients.Elasticsearch paketini kullanabilirsiniz (Github: https://github.com/elastic/elasticsearch-net). Elasticsearch ten bağımsız projenizde Fuzzy Query kullanmak isterseniz, yine aynı algoritmayı kullanan FuzzySharp ‘ı (https://github.com/JakeBayer/FuzzySharp) tercih edebilirsiniz.

Başka bir makalede görüşmek üzere.

Leave a Comment

Comments

No comments yet. Why don’t you start the discussion?

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir