Elasticsearch v6 - 101

Introduction

Ali Kizildag
10 min readAug 25, 2018

Bu kısımda Elasticsearch’e giriş yaptıktan sonra Windows OS üzerine Elasticsearch ve Kibana’nın kurulumunu yapıyoruz. Temel kavramlardan bahsederek basit bir index oluşturup içerisine dokümanlarımızı ekliyoruz.

Bu yazımı olabildiğince kısa tutmak istedim ancak mümkün olmadığını farkettim. O nedenle mantıksal olarak kısımlara bölerek ilerlemenin hem okuma hem de yazma açısından daha kolay olacağını düşündüm.

Bu makalede Elasticsearch’e yeni başlayanlara ilk adımı attırmayı ve makalenin sonunda basit bir search uygulaması yazdırabilecek duruma getirmeyi hedefledim. Okurken düşüncelerinizi benimle paylaşmanızı rica ederim. Ayrıca ekleme veya düzeltme yapmak isterseniz katkılarınızı bekliyorum. Keyifli okumalar.

Makaleyi yazarken şu anki release edilmiş versiyon olan 6.4 versiyonunu baz alacağım. Belirtmeden geçemeyeceğim official sitedeki dokümantasyonlarını çok beğeniyorum. En güvenilir kaynak olarak da orayı kullanıyorum(https://www.elastic.co/guide/en/elasticsearch/reference/current/index.html). Üstteki dropdown’dan versiyon seçerek ilgili versiyon için aradığınız bilgiyi bulabiliyorsunuz.

Öncelikle Elasticsearch nedir ile başlayalım. Kendileri şöyle tanımlamış :

“Elasticsearch giderek artan kullanım ihtiyaçlarını giderme kapasitesine sahip, açık kaynak, dağıtık ve RESTful bir arama ve analiz motorudur.”

Bu makalede analiz kısmından ziyade arama motoru kısmı ile ilgileneceğiz.

Elasticsearch sadece arama motoru olarak kullanılmamaktadır. Aynı zamanda bir data store olarak da kullanılmaktadır. Kişisel olarak sadece bir data store olarak kullanılmasını doğru bulmuyorum. Tabi ki duruma ve ihtiyaca göre değişiklik gösterebilir tartışmaya açık bir konudur.

Elasticsearch tam olarak real-time olmasa da real-time’a yakın (near real time) olarak çalışmaktadır. Bunun nedeni ise bir dokümanın indekslenmesinin ardından search edilebilir olması, kısa da olsa bir miktar zaman almaktadır (bu kısmı ileride daha net anlayacaksınız o nedenle şimdilik real-time’a yakın çalıştığını bilmeniz yeterli).

Terminology

Terminolojiye hakim olmak açısından makalede bolca kullanacağımız terimleri kısaca açıklayalım:

Index: Kolay anlaşılması açısından Index’i SQL’deki database kavramına benzetebiliriz. Kısaca Index içerisinde benzer dokümanları barındıran bir koleksiyondur.

Document Type: SQL’deki tabloya karşılık gelen birimdir.

Dikkat: Index’e farklı tiplerdeki dökümanlar ekleyemezsiniz. Versiyon 6.0 ile gelen bir karar ile bir Index içerisinde sadece tek tip bir doküman bulunabilir.

Document: Index’in SQL’deki mantıksal olarak karşılığının database olduğunu belirtmiştik. Doküman ise tablodaki her bir kayda karşılık gelen, veriyi JSON formatında saklayan basit bir birimdir.

Dikkat: Terminolojinin kolay anlışılması için SQL üzerinden örnekler verdim ancak bu pek de iyi bir bağdaştırma olmadı. İlerleyen konularda da anlayabileceğiniz gibi bazı yanlış varsayımlara sebebiyet verebiliyor. Özellikle de SQL’in relational database olmasından kaynaklı bazı yaklaşımları Elasticsearch ile de bağdaştırabilirsiniz. O nedenle Index ve doküman kavramlarını özümsediysek artık SQL’i silip atabiliriz kafalarımızdan.

Cluster & Node: Cluster içerisinde birden fazla sunucu bulunduran bir kümedir. Cluster içerisindeki tüm sunuculara “node” adı verilir. İndekslenen data Cluster içerisinde belirli kurallar çerçevesinde node’lara dağıtılmış bir biçimde saklanır. Bu arada cluster kurmak zorunda değilsiniz. Dilerseniz tek node’lu bir elasticsearch sunucusu da kurmanız mümkündür.

Shard & Replica : Bildiğiniz gibi dağıtık mimarilerde donanımsal kısıtlar nedeni ile büyük veriler daha ufak parçalara bölünerek farkı node’lar üzerine dağıtılır. Bu ufak parçalara Shard denir. Hatta node’lardan birisi down olduğunda yerine geçmesi için yedekte aslının birebir aynısı olan bir shard daha tutulur. Bu shard’lara ise replica denir.

Görsel olarak kafanızda canlandırmanız açısından aşağıda 4 node’lu bir cluster paylaştım. Elasticsearch default olarak 5 shard ve 1 replica açmaktadır. Farklı bir konfigürasyon kullanmak istiyorsanız index’in mapping’ini oluşturduğunuz aşamada belirtmelisiniz.

Installation

Öncelikle hangi ortamlarda geliştirme yapacaksanız uygun yükleme paketini buradan indirebilirsiniz. Ben makale boyunca Windows ortamında çalışacağım o nedenle bütün kurulumu windows üzerinde yapacağım.

Uyarı: Doğrudan varsayılan konfigürasyonlar ile bir kurulum yapmak isterseniz Elasticsearch ve Kibana kurulumu için bu videodaki adımları takip edebilirsiniz ve kurulum bittiğinde Kibana başlığından devam edebilirsiniz. Aşağıdaki açıklamalar Command Prompt üzerinden farklı konfigürasyonlar ile kurulum yapmak içindir.

Elasticsearch java tabanlı bir uygulama olduğundan Java’nın en az 8'li versiyonlarından birisinin yüklü olması gerekiyor. Ayrıca desteklenen işletim sistemlerine aşağıdaki tablodan göz atabilirsiniz.

Windows için kuruluma başlıyoruz. Windows OS yukarıdaki tabloda yoktu nasıl kuracağız derseniz; batch olarak çalıştırabileceğimiz bir uygulama hazırlamışlar. Buradan uygulama dosyalarını indiriyoruz. Dosyaları kolay ulaşabileceğimiz bir yere çıkardıktan sonra command prompt’tan batch dosyasını çalıştırıyoruz ve elasticsearch’ümüzü ayağa kaldırıyoruz.

Hemen hemen her uygulamanın olduğu gibi Elasticsearch’ün de bir konfigürasyon dosyası bulunmaktadır. Bu konfigürasyon dosyası, indirdiğiniz Elasticsearch uygulaması içerisindeki …\elasticsearch-6.x\config\elasticsearch.yml dosyasıdır. Siz özel bir konfigürasyon kullanmak istiyorsanız gereksinimlerinize uygun olarak bu dosyayı değiştirebilirsiniz.

Örneğin: içerisinde node_1 adında bir node bulunduran, test_cluster adında bir elasticsearch cluster’ı ayağa kaldıralım.

elasticsearch.yml dosyasından da kontrol edebileceğiniz gibi elasticsearch default olarak 9200 portundan çalışır. Herhangi bir browser’dan http://localhost:9200 adresini çağırdığınızda sağlıklı bir kurulum yapıldı ise elasticsearch cluster’ı ile ilgili bilgilerin geldiğini görebilirsiniz.

Kibana

Başlamadan önce bahsetmemiz gereken ve ilerleyen zamanlarda bol bol kullanacağımız Elastic Stack altında yer alan bir ürün daha var. “Kibana” Elasticsearch verilerinizi görselleştirebildiğiniz, sunmuş olduğu editör üzerinden Elasticsearch servislerine request gönderebileceğiniz bir arayüzdür. Daha önce Elasticsearch’ün servislerinin RESTful olduğunu söylemiştik. İstediğiniz arayüzden HTTP request’ler atabilirsiniz. Ancak Kibana’nın sunmuş olduğu nimetler sayesinde hızlıca elinizdeki data’yı kontrol edebilir, grafik veya chart’lar ile görsellleştirebilirsiniz.

Kibana’nın güncel versiyonunu aşağıdaki link üzerinden indirebilir ve aşağıdaki gibi bin içerisinde yer alan .bat dosyası üzerinden çalıştırabilirsiniz.

Download : https://www.elastic.co/downloads/kibana

Eğer Kibana ayağa kalktı ise aşağıdaki ekrana benzer bir ekran göreceksiniz.

Artık Kibana hazır olduğuna göre browser üzerinden çağırıp bakabiliriz. Kibana aksi belirtilmediği sürece 5601 portundan çalışır. http://localhost:5601 adresine gittiğimizde karşımıza Kibana’nın dashboard’u çıkacaktır.

Kibana bu makalenin konusu olmadığı için üzerinde çok durmayacağım. Sadece Kibana üzerinde yer alan editör üzerinden Elasticsearch servisine sorgularımızı atacağız. Bu editör Dev Tools altında yer almaktadır.

Creating Index

Elasticsearch servislerinin RESTful olduğunu daha önce belirtmiştik. RESTful olmasından mütevellit basit HTTP verbleri (GET, PUT, POST, DELETE) kullanılmaktadır. Automatic ve Manuel Index Creation olmak üzere indeks yaratmanın birden fazla yolu bulunmaktadır.

Automatic Index Creation

Bir dokümanı indekslemek için önceden bir index yaratmak ve mapping’i oluşturmak zorunda değilsiniz. Eğer daha önce o indeks yaratılmamışsa Elasticsearch dokümanı indekslemeden önce otomatik olarak o indeksi yaratır. Bu birinci ve en basit olan yöntemdir.

Örnek: Dev Tools üzerinden aşağıdaki gibi bir request attığınızda id’si 1 olan product tipinde bir dokümanı ecommerce indeks’ine atmış olursunuz.

PUT ecommerce/product/1
{
“name” : “Black Jacket”,
“price” : 120.0,
“creationDate” : “2018–08–17T14:12:12”
}

Dikkat : Elasticsearch 6.0 ile gelen bir değişiklik ile bir index içerisinde sadece bir adet doküman tipi tanımlayabiliyoruz.

Önceden ecommerce adında bir indeksimiz yoktu ve product tipinde bir dokümanın hangi field’ları içerdiğini önceden belirtmedik. Gelen response’u incelediğimizde ecommerce adında bir index oluşturduğunu ve içerisinde product tipinde bir doküman bulunduğunu görebilirsiniz.

{
“_index”: “ecommerce”,
“_type”: “product”,
“_id”: “1”,
“_version”: 1,
“result”: “created”,
“_shards”: {
“total”: 2,
“successful”: 1,
“failed”: 0
},
“_seq_no”: 0,
“_primary_term”: 1
}

Eklediğiniz dokümanları çekmek için search api’yi kullanabilirsiniz. Aşağıdaki request eklemiş olduğunuz tüm dokümanları getirecektir.

GET ecommerce/product/_search
{
“query”: {
“match_all”: {}
}
}

Id belirtmezseniz Elasticsearch sizin yerinize bir Id belirler.

Örnek: bir önceki request’i id vermeden bir kez daha gönderelim. Burada dikkat etmemiz gereken nokta PUT yerine POST kullanmamız gerekmektedir.

POST ecommerce/product
{
“name” : “Black Jacket”,
“price” : 120.0,
“creationDate” : “2018–08–17T14:12:12”
}

Gelen reponse’ta id vermediğimiz halde bir id oluşturulduğunu görebiliriz.

{
“_index”: “ecommerce”,
“_type”: “product”,
“_id”: “G6–0XGUBLImM-tHPpSBe”,
“_version”: 1,
“result”: “created”,
“_shards”: {
“total”: 2,
“successful”: 1,
“failed”: 0
},
“_seq_no”: 0,
“_primary_term”: 1
}

Dikkate değer bir başka nokta ise gelen response’da result ve versiyon alanlarıdır. Elasticsearch’te aynı id’li dokümanı indekslemek için birden fazla kez request gönderebilirsiniz. Elasticsearch birden fazla doküman oluşturmak yerine mevcut dokümanı update eder ve versiyonunu arttırır. Bu nedenle ilk kez doküman oluşturulduğunda response’daki “result” alanı “created” gelir.

Örnek: Product tipinde, id’si 1 olan dokümanı indekslemek için bir kez daha request gönderelim.

POST ecommerce/product/1
{
“name” : “Blue Jacket”,
“price” : 120.0,
“creationDate” : “2018–08–17T14:12:12”
}

Gelen response’da versiyonun artık 2 olduğunu ve result alanının “updated” olarak değiştiğini görebiliriz.

{
“_index”: “ecommerce”,
“_type”: “product”,
“_id”: “1”,
“_version”: 2,
“result”: “updated”,

“_shards”: {
“total”: 2,
“successful”: 1,
“failed”: 0
},
“_seq_no”: 1,
“_primary_term”: 1
}

Manuel Index Creation

Automatic Index Creation ile indeks oluşturmak her ne kadar kolay olsa da gerçek hayatta kullanılacak bir indeks için çoğu zaman yetersiz kalmaktadır. Örneğin oluşturacağımız indeksin kaç shard’ı veya replica’sı olacağını önceden belirtmek isteyebiliriz veya indeks’in hangi tip dokümanları içereceğini, bu dokümanlardaki field’ların data tiplerini veya dokümanlar arasındaki ilişkileri önceden tanımlamak isteyebiliriz(mapping). Bu gibi sebeplerle Manuel olarak indeks yaratabilir ve mapping’i oluşturabiliriz.

PUT ecommerce
{
“settings” : {
“index” : {
“number_of_shards” : 5,
“number_of_replicas” : 1
}},

“mappings”: {
“product”: {
“properties”: {
“id” : {
“type”: “integer”
},
“name”: {
“type”: “text”
},
“price” : {
“type”: “double”
},
“creationDate” : {
“type”: “date”
}}}}}

Bu request ile 5 shard’ı ve birer replica’sı olan bir elasticsearch indeksi yaratmış olduk. Indeks içerisinde bir tane “product” adında bir doküman tipi tanımladık. Properties altında ise doküman içerisinde hangi field’ların bulunduğunu ve hangi tiplerde veri kabul ettiğini belirtmiş olduk.

{
“acknowledged”: true,
“shards_acknowledged”: true,
“index”: “ecommerce”
}

Dikkat : “Replica sayısını indeks oluştuktan sonra değiştirebilirsiniz ancak shard sayısını sadece indeksi oluşturma anında belirtebilirsiniz.”

Field Data Types

Temel veri tipleri:

Numeric : long, integer, short, byte, double, float, half_float, scaled_float

Date : date

Boolean : boolean

Binary : binary

String : String olarak tanımlacak field’larda iki seçenek vardır. Eğer field üzerinde birebir eşleşecek bir arama yapacaksanız “keyword” kullanmalısınız. Ancak field üzerinde full-text arama yapacaksak “text” tipini kullanmamız gerekir.

Kompleks veri tipleri:

Elasticsearch dokümanlar içerisinde Dizi, Obje ve Nested Obje veri tiplerini desteklemektedir. Dizi ve Obje tiplerine aşina olduğumuzu varsayıyorum.

Nested obje, doküman içerisinde bir obje koleksiyonu tutmak gibi bir ihtiyaç doğduğunda kullanılmaktadır.

En çok kullanılan veri tiplerini yukarıda paylaştım. Veri tipleri bunlarla sınırlı değil elbette daha özel veri tiplerine ihtiyaç duyarsanız dokümantasyonu inceleyebilirsiniz.

Örnek: Tüm temel veri tiplerini öğrendiğimize göre product doküman tipimizi biraz kompleks hale getirip diğer veri tiplerinde field’lar ekleyebiliriz. Öncelikle mevcut indeksimizi silelim ve baştan oluşturalım.

DELETE ecommerce

Yeni indeksimizde product tipinde daha kompleks bir doküman tanımlayalım.

Yukarıdaki tabloya göre oluşturulacak indeks ve mapping aşağıdaki gibi olmalıdır:

PUT ecommerce
{
“settings” : {
“index” : {
“number_of_shards” : 5,
“number_of_replicas” : 1
}
},

“mappings”: {
“product”: {
“properties”: {
“id” : {
“type”: “integer”
},
“name”: {
“type”: “keyword”
},
“description”: {
“type”: “text”
},
“price” : {
“type”: “double”
},
“size”: [],
“manufacturer” : {
“properties”: {
“name”: {
“type”: “keyword”
},
“website”:{
“type” : “keyword”
}
}
},
“category” : {
“type”: “nested”
},
“creationDate” : {
“type”: “date”
} } } }}

İstediğimiz gibi oluşup oluşmadığını mapping API ile kontrol edebilirsiniz.

GET ecommerce/_mapping

Eğer indeks düzgün bir şekilde oluşmuş ise aşağıdaki gibi bir mapping yapısı gözükecektir:

{
“ecommerce”: {
“mappings”: {
“product”: {
“properties”: {
“category”: {
“type”: “nested”
},
“creationDate”: {
“type”: “date”
},
“description”: {
“type”: “text”
},
“id”: {
“type”: “integer”
},
“manufacturer”: {
“properties”: {
“name”: {
“type”: “keyword”
},
“website”: {
“type”: “keyword”
}
}
},
“name”: {
“type”: “keyword”
},
“price”: {
“type”: “double”
} } } } }}

Şimdi bir kaç tane doküman ekleyelim.

PUT ecommerce/product/1
{
“name” : “Black Jacket”,
“description” :”It’s a kind of jacket. Made by Polo.”,
“price” : 120.525,
“size”:[“small”,”medium”,”large”,”xl”],
“manufacturer” : {
“name”:”Polo”,
“website”:”www.polo.com
},
“category": {
“id” : 1,
“name”:”Dress”
},
“creationDate” : “2018–08–17T14:12:12”
}

PUT ecommerce/product/2
{
“name” : “Blue Jacket”,
“description” :”It’s a blue jacket. Made by Zara.”,
“price” : 200.213,
“size”:[“small”,”medium”],
“manufacturer” : {
“name”:”Zara”,
“website”:”www.zara.com
},
“category": {
“id” : 1,
“name”:”Dress”
},
“creationDate” : “2018–08–20T23:22:12”
}

PUT ecommerce/product/3
{
“name” : “Red Jacket”,
“description” :”Red Levis jacket.”,
“price” : 50.245,
“size”:[“small”,”medium”,”large”],
“manufacturer” : {
“name”:”Levis”,
“website”:”www.levis.com
},
“category": {
“id” : 1,
“name”:”Dress”
},
“creationDate” : “2018–08–02T14:52:32”
}

Ben 3 adet doküman ekledim dilerseniz siz daha fazla ekleyebilirsiniz. Search API başlığı altında bir çok query yazacağımız için ne kadar fazla doküman olursa o kadar iyi olur.

“Multiple mapping types are not supported in indices created in 6.0”

Bu başlık altında bahsetmeden geçemeyeceğim bir konu daha var. Elasticsearch 6.0 versiyonunda bazı radikal kararlar alındı. Bunlardan birisi de bir index içerisinde yalnızca bir adet doküman tipine izin veriliyor. Yani örneğimiz üzerinden konuşacak olursak ecommerce indeksimizin içerisinde product tipinde bir adet doküman tipi vardı. Farz edelim ki kullanıcılarımızı saklayacağımız user tipinde bir doküman tipine daha ihtiyacımız var. Bunu ecommerce indeksi içerisinde ayrı bir doküman tipi olarak tanımlamamıza izin vermiyor. İki alternatif var birincisi join tip olarak tanımlamak. İkincisi ise user tipindeki dokümanlar için ayrı bir index oluşturmak.

Join Type

Önceki Elasticsearch versiyonlarda child doküman olarak geçen join tipler, nested dokümanlar ile benzerlik göstermektedirler. Nested objeler dokümanın içerisinde yer alırken Join objeler ayrı birer doküman olarak tanımlanırlar. Ancak bağlı oldukları bir parent doküman bulunmaktadır.

Nested vs Child

Nested tipler write-heavy iken Join read-heavy. Yani Nested tipleri yazmak maliyetlidir. Eğer nested dokümanı update etmek isterseniz içerisinde bulunduğu dokümanı komple update etmek zorundasınız. Join tiplerin ise yazma maliyeti düşükken okuma maliyeti çok yüksektir. Search işlemlerinde performans kaybına yol açmaktadır.

--

--