Merhaba, Elasticsearch (ES) genel olarak metin arama, log analizi ve analitik işler gibi farklı amaçlar ile kullanabildiğimiz ve sorgular gönderebildiğimiz doküman odaklı bir araçtır. Bu yazımda dokümanlara sorguların atıldığı genel yaklaşımdan farklı olarak. Sorguları indeksleyerek dokümanları sorgu olarak kullanabildiğimiz Percolate yapısını anlatacağım.

Percolate sorgu yapısı Elasticsearch üzerinde bir doküman ararken kullandığımız sorguların indekslenerek saklanmasıyla oluşturulan ve bu indekse bir dokümanı  sorguladığımızda eşleşen indekslenmiş sorguların sonuç olarak döndürüldüğü yapıdır.

Percolate sorgu yapısını nerede kullanabiliriz?

Hepiminizin düzenli olarak kullandığı bir alışveriş sitesi yazılımını geliştirdiğimizi düşünelim ve gereksinim olarak kullanıcıların ürün aradıkları kriterleri saklayarak uygun ürün geldiğinde bilgilendirme  e-mail atılması isteniyor olsun. Percolate sorgusunu bu sorunu çözmek için kullanabiliriz. 

Örnek olarak bir kullanıcının siyah Iphone 11 marka ürünün fiyatı  4000 TL’in altında ise e-mail olarak bilgilendirmek istiyor olsun, bu yapıyı hazırlamak için aşağıdaki adımlarla ilerleyebiliriz.

1.Kayıtlı sorgular için gerekli olan indeksin oluşturulması

Oluşturacağımız indeksimizde alışveriş sitesinde ürünleri arayacağımız alanlara uygun olarak bir şema tasarlıyoruz.

PUT /kayitli-sorgu-index
{
  "mappings": {
    "properties": {
      "marka":{
        "type": "keyword"
      },
      "model":{
        "type":"keyword"
      },
      "hafiza":{
        "type": "integer"  
      },
      "renk":{
        "type": "keyword"  
      },
      "urun_adi": {
        "type": "text"
      },
      "query": {
        "type": "percolator"
      }
    }
  }
}

2. Arama sorgularının indekse yazılması

Alışveriş sitesi arama sitemizde kullanıcın bildirim almak istediği sorguyu Elasticsearch’de sorguladığımız format ile aynı formatta oluşturduğumuz indekse yazıyoruz. İndekse yazarken daha sonra kullanmak için ilgili kullanıcı bilgisini de meta özelliği ile kayıt ediyoruz.

PUT /kayitli-sorgu-index/_doc/1?refresh
{
  "meta":{"kullanici_id":12},
  "query": {
    "bool": {
      "must":[{
      "term":{"marka":"Apple"}},
        {"term":{"model":"Iphone 11"}},
      {"match":{"hafiza":128}},
      {"match":{"renk":"Siyah"}},
      {"range": {"fiyat": {"lte": 4000}}}
      ]
    }
  }
}

Put işleminden sonra sonuçları karşılaştırmak için farklı birkaç sorgu daha kayıt edelim.

PUT /kayitli-sorgu-index/_doc/2?refresh
{
  "meta":{"kullanici_id":14},
  "query": {
    "bool": {
      "must":[{
      "term":{"marka":"Samsung"}},
      {"match":{"hafiza":200}},
      {"match":{"renk":"Gri"}},
      {"range": {"fiyat": {"lte": 6000}}}
      ]
    }
  }
}
PUT /kayitli-sorgu-index/_doc/3?refresh
{
  "meta":{"kullanici_id":15},
  "query": {
    "bool": {
      "must":[{
      "term":{"marka":"Apple"}},
      {"term":{"model":"Iphone 8"}},
      {"match":{"hafiza":64}},
      {"match":{"renk":"Beyaz"}}
      ]
    }
  }
}

Bu adımla birlikte artık sistemde kayıtlı aramalar percolator tipinde kayıt edilmiş ve kullanılabilir durumda:

GET /kayitli-sorgu-index/_search
{
  "took" : 0,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 3,
      "relation" : "eq"
    },
    "max_score" : 1.0,
    "hits" : [
      {
        "_index" : "kayitli-sorgu-index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "meta" : {
            "kullanici_id" : 12
          },
          "query" : {
            "bool" : {
              "must" : [
                {
                  "term" : {
                    "marka" : "Apple"
                  }
                },
                {
                  "term" : {
                    "model" : "Iphone 11"
                  }
                },
                {
                  "match" : {
                    "hafiza" : 128
                  }
                },
                {
                  "match" : {
                    "renk" : "Siyah"
                  }
                },
                {
                  "range" : {
                    "fiyat" : {
                      "lte" : 4000
                    }
                  }
                }
              ]
            }
          }
        }
      },
      {
        "_index" : "kayitli-sorgu-index",
        "_type" : "_doc",
        "_id" : "2",
        "_score" : 1.0,
        "_source" : {
          "meta" : {
            "kullanici_id" : 14
          },
          "query" : {
            "bool" : {
              "must" : [
                {
                  "term" : {
                    "marka" : "Samsung"
                  }
                },
                {
                  "match" : {
                    "hafiza" : 200
                  }
                },
                {
                  "match" : {
                    "renk" : "Gri"
                  }
                },
                {
                  "range" : {
                    "fiyat" : {
                      "lte" : 6000
                    }
                  }
                }
              ]
            }
          }
        }
      },
      {
        "_index" : "kayitli-sorgu-index",
        "_type" : "_doc",
        "_id" : "3",
        "_score" : 1.0,
        "_source" : {
          "meta" : {
            "kullanici_id" : 15
          },
          "query" : {
            "bool" : {
              "must" : [
                {
                  "term" : {
                    "marka" : "Apple"
                  }
                },
                {
                  "term" : {
                    "model" : "Iphone 8"
                  }
                },
                {
                  "match" : {
                    "hafiza" : 64
                  }
                },
                {
                  "match" : {
                    "renk" : "Beyaz"
                  }
                }
              ]
            }
          }
        }
      }
    ]
  }
}

3. Bir üründe güncelleme yapıldığında veya kayıt edildiğinde ilgili kullanıcıların bulunması

Alışveriş sitemize yeni bir ürün girildiğinde veya ürünlerde güncelleme yapıldığında, bildirim gönderilmesini istediğimiz kullanıcıları bulmak için ilgili ürünü kayitli-sorgu-index yapısına sorgulatarak eşleşen kişileri buluyoruz.

Örneğin; Apple Iphone 11 128 Gb Siyah ürününün 3888 liraya düştüğünde, kayıt işlemi tamamlandıktan sonra alışveriş sitemizde ürünleri aradığımız indekse indexlediğimiz dokümanı Percolator yapımızın bulunduğu kayitli-sorgu-index’ine sorguladığımızda hangi kullanıcılara bildirim gitmesi gerektiğini elde edebiliyoruz.

GET /kayitli-sorgu-index/_search
{
  "query": {
     "percolate": {
      "field": "query",
      "document": {
        "urun_adi":"Iphone 11 128 GB Siyah Telefon",
        "marka": "Apple",
        "model":"Iphone 11",
        "hafiza":128,
        "renk":"Siyah",
        "fiyat":3888
      }
    }
  }
}

Yukarıda bulunan sorgunun sonucu olarak aşağıdaki sonucu bekliyoruz:

{
  "took" : 4,
  "timed_out" : false,
  "_shards" : {
    "total" : 1,
    "successful" : 1,
    "skipped" : 0,
    "failed" : 0
  },
  "hits" : {
    "total" : {
      "value" : 1,
      "relation" : "eq"
    },
    "max_score" : 2.3922937,
    "hits" : [
      {
        "_index" : "kayitli-sorgu-index",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 2.3922937,
        "_source" : {
          "meta" : {
            "kullanici_id" : 12
          },
          "query" : {
            "bool" : {
              "must" : [
                {
                  "term" : {
                    "marka" : "Apple"
                  }
                },
                {
                  "term" : {
                    "model" : "Iphone 11"
                  }
                },
                {
                  "match" : {
                    "hafiza" : 128
                  }
                },
                {
                  "match" : {
                    "renk" : "Siyah"
                  }
                },
                {
                  "range" : {
                    "fiyat" : {
                      "lte" : 4000
                    }
                  }
                }
              ]
            }
          }
        },
        "fields" : {
          "_percolator_document_slot" : [
            0
          ]
        }
      }
    ]
  }
}

Percalotor yapısında birden çok dokümanı aynı anda sorgulatabiliyoruz, yukarıdaki sonuçta bulunan _percolator_document_slot alanında bulunan 0 değeri sorguladığımız dokümanın sorgu içerisindeki sırasına denk gelmektedir.

Zaman ayırıp okuduğunuz için teşekkürler, görüşmek dileğiyle.