13 Ekim 2015 Salı

Elastic'le Join İşlemleri

1.Application-side Joins

Elastic'te Gamze kullanıcısına ait bloglara ulaşabilmek için 2 ayrı sorgu ile ulaşılabilir.

GET /gamze/user/_search
{
  "query": {
    "match": {
      "title": "Gamze"
    }
  }
}

GET /gamze/myblog/_search
{
  "query": {
    "filtered": {
      "filter": {
        "terms": { "user": [1] }  
      }
    }
  }
}

Bu join işleminin temel avantajı; veriyi normalize etmesidir, dezavantajı ise fazla sorgunun çalıştırılmasıdır. Bu yaklaşım, yukarıdaki örnekte user dökümanının küçük boyutlarda olması durumunda avantaj sağlayacaktır. Durum boyutu büyük olan dökümanlarda ise oldukça zorlaşacaktır.

2.Denormalizing Data

Bu yol Elastic'te istenen en iyi arama performansına sahiptir.

PUT /gamze/user/1
{
  "name":     "Gamze Ercan",
  "email":    "gamze@ercan.com",
  "dob":      "1985/10/24"
}

PUT /gamze/myblog/2
{
  "title":    "Relationships",
  "body":     "It's complicated...",
  "user":     {
    "id":       1,
    "name":     "Gamze Ercan" 
  }
}

Gamze kullanıcısına ait bloğa ulaşabilmek bu yöntemde blog dökümanında user verisi denormalize edilir.
Sorguyu aşağıdaki gibi gerçekleştiririz.

GET /gamze/myblog/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title":     "relationships" }},
        { "match": { "user.name": "Gamze "          }}
      ]
    }
  }
}

Denormalize olmuş verinin avantajı hızıdır. Çünkü her döküman istenen sorgu sonucuna ulaşılabilmesi için gerekli olan bütün verilere sahiptir.

3. Nested Objects

PUT /gamze/myblog/1
{
  "title": "Nest eggs",
  "body":  "Making your money work...",
  "tags":  [ "cash", "shares" ],
  "comments": [ 
    {
      "name":    "Gamze Ercan",
      "comment": "Great article",
      "age":     28,
      "stars":   4,
      "date":    "2015-10-01"
    },
    {
      "name":    "Alice White",
      "comment": "More like this please",
      "age":     31,
      "stars":   5,
      "date":    "2015-10-05"
    }
  ]
}

Yukarıda da görüldüğü gibi blog dökümanı bütün yorum bilgilerini içeriyor. Yani hepsi tek bir döküman içerisindedir. Bütün içerik tek bir dökümanda olursa hiç bir join işlemine gerek kalmaz. Böylece aramada iyi bir performans sergilenir.

Ama cross-object matching sebebiyle oluşan nesne aşağıdaki gibi gözükmektedir.

{
  "title":            [ eggs, nest ],
  "body":             [ making, money, work, your ],
  "tags":             [ cash, shares ],
  "comments.name":    [ alice, ercan, gamze , white ],
  "comments.comment": [ article, great, like, more, please, this ],
  "comments.age":     [ 28, 31 ],
  "comments.stars":   [ 4, 5 ],
  "comments.date":    [ 2015-10-01, 2015-10-05 ]
}

Yani Alice 28 ile, Gamze' de 2015-10-05 tarihiyle eşlemiş oluyor. Bu durum yüzünden veri kaybı gerçekleşiyor.

Aşağıdaki gibi Nested Objects bu duruma çözüm olmuştur.

{ 
  "comments.name":    [ gamze, ercan],
  "comments.comment": [ article, great ],
  "comments.age":     [ 28 ],
  "comments.stars":   [ 4 ],
  "comments.date":    [ 2015-10-01 ]
}
{ 
  "comments.name":    [ alice, white ],
  "comments.comment": [ like, more, please, this ],
  "comments.age":     [ 31 ],
  "comments.stars":   [ 5 ],
  "comments.date":    [ 2015-10-05 ]
}
{ 
  "title":            [ eggs, nest ],
  "body":             [ making, money, work, your ],
  "tags":             [ cash, shares ]
}

Sorgusu da bu şekilde gerçekleştirilir.

GET /my_index/blogpost/_search
{
  "query": {
    "bool": {
      "must": [
        { "match": { "title": "eggs" }}, 
        {
          "nested": {
            "path": "comments", 
            "query": {
              "bool": {
                "must": [ 
                  { "match": { "comments.name": "gamze" }},
                  { "match": { "comments.age":  28     }}
                ]
        }}}}
      ]
}}}

4.Parent-Child Relationship

Nested modele benzer bir yaklaşımdır. Nested modelde bütün verilerin tek bir dökümanda olmasına karşın bu yöntemde tamamiyle parent ve child'ın farklı dökümanlarda yer alır. Tek farkı budur. Bire çok ilişkisine sahiptir. 1 parent birden çok child a sahiptir.

Nested modele karşı avantajları ise;

  • Parent dökümanı child dökümanını etkilemeden güncellenebilir.
  • Child dökümanlara, diğer childları yada parentı etkilemeden veri ekleme, güncelleme veya silme işlemleri gerçekleştirilebilir.

PUT /company
{
  "mappings": {
    "branch": {},
    "employee": {
      "_parent": {
        "type": "branch" 
      }
    }
  }
}

Bu örnekte branch tipinde bir parent ve employee tipinde child ilişkisi gösteriliyor.

Bu örnekle ilgili ayrıntılı açıklamalar buradadır.



12 Ekim 2015 Pazartesi

Elastic Search'e Başlarken

Lafı uzatmadan Elastic Search'e başlarken aklımda kalmasını istediğim en temel şeyleri yazacağım.

Elastic Search için bazı keywordler
  • cluster = birden çok node
  • node = server
  • index = database
  • type = table
  • document = indexlenebilir en küçük bilgi parçası
  • shards = bir indexi birden çok parçaya bölmemizi sağlayan yapı
Daha ayrıntılı açıklamalar buradadır.
Başka bir tutorial daha.

Elastic Search kurulumunu tamamladıktan sonra Sense eklentisiyle oluşturduğumuz clusterlar üzerinde işlemler yapabiliyoruz.

Sense üzerinde deneme olarak yaptığım bazı sorgular;

GET /_cluster/health
* Oluşturduğumuz clusterın durumu hakkında bilgi verir.

Sonuç olarak alınan ekran :
{
   "cluster_name": "elasticreport",
   "status": "yellow",
   "timed_out": false,
   "number_of_nodes": 1,
   "number_of_data_nodes": 1,
   "active_primary_shards": 11,
   "active_shards": 11,
   "relocating_shards": 0,
   "initializing_shards": 0,
   "unassigned_shards": 11,
   "delayed_unassigned_shards": 0,
   "number_of_pending_tasks": 0,
   "number_of_in_flight_fetch": 0
}

PUT /gamze?pretty
* "gamze" adında bir index oluşturuldu.


PUT /gamze/myblog/2
{
  "title": "My blog",
  "text":  "My first blog entry",
  "date":  "2015/10/11"
}
*gamze indexine myblog typeında veri eklendi.


GET /gamze/myblog/2
* gamze indexinde myblog typeında 2 idli veri sorgulama

Sorgu sonucu :
{
   "_index": "gamze",
   "_type": "myblog",
   "_id": "2",
   "_version": 1,
   "found": true,
   "_source": {
      "title": "My blog",
      "text": "My first blog entry",
      "date": "2015/10/11"
   }
}

GET /gamze/myblog/2?_source=title
* sadece title alanını istersek

Çıktısı:
{
   "_index": "gamze",
   "_type": "myblog",
   "_id": "2",
   "_version": 1,
   "found": true,
   "_source": {
      "title": "My blog"
   }
}