Asp.Net Core 3.0 ElasticSearch Kurulum Konfigürasyon ve Sorgulama

Adem Olguner
Devops Türkiye☁️ 🐧 🐳 ☸️
12 min readJan 19, 2020

ElasticSearch nedir?

ElasticSearch Lucene alt yapısı üzerine kurulmuş, Java programlama dili ile open-source olarak geliştirilmiş, ölçeklenebilir(scalable), full text search tabanlı bir search engine dir.

Basit bir kurulum işlemi vardır. Kurulum işlemi için bu linkten indirip kuralım.

Kurulum işlemlerinden sonra localhost:9200 portundan erişebiliriz.
Kurulum işleminin tam ve eksiksiz olarak bittiğini kontrol etmek için browserdan http://localhost:9200/ adresine gittiğimizde bu ekran ile karşılaşacağız.

Kurmuş olduğunuz versiyona göre “version” bilgileri değişkenlik gösterebilir.

Kurulum işleminden sonra izleme (monitoring) işlemi için Kibana kurabilirsiniz. Ben kullanmış olduğum eklenti ( ElasticSearch Head) ile devam edeceğim. ElasticSearch Head ile elasticsearch query işlem sonuçlarını görüntülemek için kullanacağız.

Elasticsearch verileri JSON tipinde saklar.

Neler Yapacağız?

  • Blog Sitesi uygulaması geliştireceğiz ve .Net Core 3.0 ile bir Web API Uygulaması oluşturacağız. ( Katmanlı yapı)
  • ElasticSearch operasyonlarına giriş yapıp Relational DataBase ile ElasticSearch karşılaştırması yapacağız.
  • ElasticSearch işlemlerine değineceğiz.
    - Konfigürasyon
    - Index oluşturma , Index silme
    - Object Mapping işlemine değineceğiz, Alias nedir?
    - Tekil ve Çoğul (Bulk) Insert, Update-Delete işlemlerine değineceğiz.
    - Analyzer işlemlerine değineceğiz. Türkçe karakter indexlenmesi, arama yapılması, küçük büyük harf kombinasyonlarına değinip, eş anlamlı kelimelerde arama işlemlerine bakacağız.
    - Özel filtreleme işlemlerine bakacağız.

Elastic üzerinde verilerimizi kaydederken, ilgili dokümanın yanı entitynin her propertysini indexlememeliyiz. ElasticSearch sadece search işlemlerimizi hızlı bir şekilde yapabilmemizi sağlayan bir araçtır, veritabanı değildir.

ElasticSearch ve RDBM

İlişkisel veritabanı (RDBM)ve ElasticSearch arasındaki benzerlikleri alttaki şekilden bakabiliriz.

.Net Core Solution ve Proje Katmanları

MyBlog adında bir blog projesi oluşturacağız.

Create a new project => Next

Blank Solution=> Next

Solution Project (MyBlogProject)’e
Sağ Tık => Add => New Project

Bu şekilde 4 adet Class Library(.Net Core) Projesi daha ekliyoruz.

Katmanlar ve isimlendirme
* MyBlogProject.Entities
* MyBlogProject.DataAccess
* MyBlogProject.Business
* MyBlogProject.Core

Şimdi Web API projemizi oluşturacağız.
Solution Project => Sağ tık => Add => New Project

ASP.NET Core Web Application ve ardından çıkan ekranda API seçeceğiz.

NOT:
Katmanlara ait detayları yazımdan inceleyebilirsiniz. Bu yazımızda ElasticSearch işlemleri üzerine yoğunlaşıyor olacağız.

MyBlogProject.Business İş katmanında Nuget Paket Yöneticisinden gerekli paketlerin kurulumu yapalım.

Kurulum işlemlerinin ardından MyBlogProject.Business İş katmanında ElasticSearchOptions adında bir klasör açıp elasticsearch ile ilgili operasyonları buraya yazacağız.

Konfigürasyon işlemleri için API projesi içerisinde bulunana appsetting.json dosyasını düzenleyelim.

1- ElasticSearch Konfigürasyon İşlemleri

ElasticSearch servisine bağlantı kurabilmemiz için bizden Kullanıcı adı, şifre ve bağlantı bilgisi istenmektedir.

appsetting.json dosyasında konfigüre ettiğimiz alanları okuyarak IElasticSearchConfigration nesnesinde bulunan alanlara setliyoruz.

ElasticSearch Metotları Tanımlama İşlemleri

ElasticSearch işlemleri için Index ekleme,silme, güncelleme, indexi yenileme ve search işlemleri için IElasticSearchService.cs sınıfı içerisinde metot imzalarını oluşturalım.

ElasticSearchManager.cs sınıfında (IElasticSearchService) soyut sınıfına ait operasyonların implementasyonunu yapalım ve metot içeriklerini kullandıkça tek tek yazıp açıklayacağız.

ElasticSearch ile Suggest — Önerme İşlemi

Elasticsearch içerisinde autocomplete/suggest özelliğini implemente edebilmenin “ngrams, “prefix queries ve “completion suggester” gibi bir kaç farklı yolu vardır.

Suggest önerme işlemi için CompletionField attribute alanını kullanacağız. Index işlemini yapacağımız nesneye bu alanı ekleyerek yapacağız.

suggest işleminde kelimelerin eş anlamlıları da eklenerek frekans arttırılır.

Google ile suggest örneği

public virtual CompletionField Suggest { get; set; }

Mappings ve Alias

Mappings ile elasticsearch üzerinde verilerimizin nasıl tutulacağını tanımlarken, Aliases sadece indeximizin takma ismidir. Yani sorgulama yaparken daha kısa bir isim üzerinden ilgili index’e erişebilmek içindir.

Bu sebeple aliaslar unique (benzersiz) olmalıdır.

Index Oluşturma

Index oluşturma işleminde en sade haliyle altta görüldüğü şekilde yapabiliriz.

Not:ElasticSearchManager.cs sınıfı içerisinde yazılan metot içeriğidir.

İndexleme işlemleri yapılırken arama sonuçlarının daha verimli sonuçlar verebilmesi adına bazı düzenlemeleri ekleyeceğiz.

Analyzer

Analyzer indeksleme ve arama zamanında metinlerin üzerinden geçip değişiklik yapar.

NOT: Dokümanı indexlerken kullanmış olduğunuz analyzer tipini, doğru scoring alabilmek ve sonuçları elde edebilmek adına search işleminde de kullanmanız gerekmektedir .

Örneğin indexlerken kullanmış olduğunuz analyzerin birinde StandardFilter olduğunu düşünün. Noktalama işaretlerini ve belirli kısaltmaları kaldırıyordu. (C.E.O = CEO) Arama işleminde ise StandardFilter olmadığını varsayarsak ve sizin search için keywordünüz eğer C.E.O’ise o dokümanı bulamazsınız.

Filters:

Her ne kadar queryler ile istediğimiz düzeyde işlem yapabiliyor olsak da, bazı durumlarda queryleri filter kullanarak daha fazla özelleştirmeye ihtiyaç duyabiliriz

Filterları tıpkı SQL’de olduğu gibi “WHERE” işlemine benzetebiliriz. İki farklı filter bulunmaktadır. Bunlar:

  • Filtered: Sorgu execute edilirken filtreleme işlemini yapmaktadır bir nevi prefiltering
  • Filter: Sorgu execute edildikten sonra filtreleme işlemini gerçekleştirmektedir yani postfiltering
İncele

Token Filterlar arasına Ascii Folding Token Filter eklersek tokenlar içerisindeki Türkçe karakterler Ascii benzerlerine dönüşecektir. İki türde de arama yaparsanız döküman eşleşecektir.

Analyzer ve Filter bilgileri doğrultusunda ilk oluşturduğumuz Index işlemine ait değişiklikleri yapalım.

Index oluşturduğumuzda ElasticSearch Head eklentisi ile görünümü alttaki gibi olacaktır.

İndexleme işlemlerinde Analyzer ve Filter gibi ayarlamalar yapılmadan önce ve sonraki index bilgileri karşılaştırılması:

Analyser ve Filter eklemeden ÖNCE oluşturulan index
Analyser ve Filter eklemeden SONRA oluşturulan index

Yeni Bir Kayıt Ekleme İşlemi

Yeni bir kayıt ekleme için PostInputDto tipinde bir class oluşturuyoruz.

PostController sınıfında HttpPost (Action Verbs) türünde bir metot oluşturalım.

GetElasticIndexItem metotu ile index atacağımız nesnemizin oluşturulma işlemi.

Veri girişi olarak gönderdiğimiz PostInputDto nesnesinin alanlarından yararlanarak PostElasticIndexDto nesnesi oluşturmaya çalışıyoruz.

  • PostInputDto arayüzden girdiğimiz veri modelinin tipi,
  • PostElasticIndexDto ise index atabilmek için oluşturacağımız modelin tipidir.

Index işlemi için oluşturacağımız PostElasticIndexDto nesnemiz.

PostElasticIndexDto nesnesi değiştirilebilir bir nesnedir. Örnek olması açısından bu alanları tutuyoruz. (Değiştirebilirsiniz)

Kaydedilen bir dökümana (document) ait bilgiler.

ElasticManager sınıfında yazmış olduğumuz AddOrUpdateAsync metot içeriğini inceleyelim.

Bu işlemler incelendiğinde Id değerine göre kontrol edip var ise güncelleme yok ise kayıt ekleme işlemi yapıyoruz.

Önerme (suggest) İşlemi

Önerme işlemi index kayıtlarını attığımız nesnenin suggest olarak tanımladığımız alanlarında arama işlemi yapacaktır. Bu işlemi ihtiyaçlar doğrultusunda iş kurallarına göre farklılık gösterebilir.

Çalışma mantığını daha iyi anlayabilmemiz için Elastic Engineering Blog’u üzerinde bulunan örneğe bir bakalım. “hotel“, “marriot“, “mercure“, “munchen” ve “munich” kelimelerinin olduğunu varsayalım.

Suggest işlemi için PostController sınıfında metot tanımlayalım.

PostManager sınıfında gelen searchText bilgisi ve diğer parametreler ile elasticsearch query işlemi yapacağız.

Öneri (Suggest) işlemine ait metot içeriği

Kaydetmiş olduğumuz indexi incelediğimizde suggest — önerme işlemi için PostElasticIndexDto nesnesindeki Suggest özelliği (property) dir.

Arama işlemini incelediğimizde c => c.Field(f => f.Suggest) alanında arama yapıldığını görebiliriz.

Searching İşlemleri

Çeşitli ihtiyaçlar türetip bu ihtiyaçlar doğrultusunda search Queryler yazacağız.

PostController da bir adet HttpGet türünde metot tanımlayalım.

Sayfalama (Pagination) işlemleri için skipItemCount ve maxItemCount parametrelerini gönderiyorum varsayılan (default) olarak değerlerini atıyoruz.

ElasticSearch işlemleri için IElasticSearchService soyut sınıfında tanımladığımız metot imzalarını inceleyelim.

SimpleSearchAsync:
Search işlemleri girdi olarak SearchDescriptor<T> türünde query ve indexName bilgisi istemektedir, geri dönüş türü ise ISearchResponse<T> şeklindedir. Gözümüze <T> genel (generic type) alabilmektedir.

SearchAsync:
SimpleSearchAsync metoduna ek olarak skip, size, highlight gibi bir dizi parametre daha alabilmektedir. Peki buradaki diğer parametreler ne anlama geliyor?

  • Highlight : ElasticSearch de arama yapıldığı zaman, bulunan sonuçların ilgili metnin nerelerinde eşlediğinin gösterildiği güzel bir yapıdır.

Google da “bir dizi ara” şeklinde bir query (arama metni) girdim, google benim yazdığım kelimelerden eşleşmeyenleri bold (kalın) , eşleşen değerleri normal olarak göstermektedir. Bu bize arama yaptığımız işlemlerde görsel olarakta değiştirebilme imkanı sunuyor.
(Renkli, eğik yazı (italik), vb… düşünebiliriz.)

  • PreTags: İlgili filtrelerden sonra bulunan resultın başına konacak karakter belirlenir.
  • PostTags: İlgili filtrelerden sonra bulunan resultın sonuna konacak karakter belirlenir.
  • Fields: Highlight amaçlı bakılacak kolon belirlenir.

Nest kütüphanesi ile Search işlemi sonucu bize ISearchResponse döndüğünü belirtmiştik.

Dönüş nesnesine ait bilgilerinden Hit değerlerine bakalım.

Hit: Toplam geri dönüş adedine, toplam score’u gibi bilgileri veren, her bir dönen row’un “_id”‘sini, “_Score”‘unu, “Highlights”‘ını ve bunun gibi birçok kritik veriyi dönen çok önemli bir özelliktir(property).

Search işlemi için Nest kütüphanesi bizden SearchDescriptor<T> türünde bir nesne istediğini söylemiştik ve T olarak biz post bilgilerini elasticsearch map ederken PostElasticIndexDto türünde bir nesne ile indexleme işlemini yapmıştık.

Peki bu SearchDescriptor<T> nesnesini nasıl oluşturacağız, nedir bu SearchDescriptor<T>?

ElasticSearch işlemlerinde SearchDescriptor query oluşturmak için kullanılan bir nesnedir.

Buraya kadar elasticsearch hakkında ufak tefek bilgiler ile anlamaya çalıştık, şimdi sorgular oluşturarak search işlemlerinde neler yapabiliriz bunları konuşacağız.

SORGULAMA ÖRNEKLERİ VE SORGU PARAMETRELERİ

* Term — Terms

Bire bir eşleşme gerektiren alanların aranmasında kullanılır.

Benim indexlerimden UserId değeri 1 olan indexleri getir diye bir ihtiyacım var? [Term]

Benim indexlerimden UserId değeri 1 ve CategoryId değeri 6 olan indexleri getir diye bir ihtiyacım var. [Terms]

* MatchPhrase-MatchPhrasePrefix

* Term(s) ve MatchPharese birleşik sorgu yazalım.

* MultiMatch

Çok alanlı sorgulara izin vermek için eşleme sorgusu üzerine kurulur.
Core işlemleri sql” cümleciğini arayalım.

MutiMatch adından da anlaşılacağı üzere arama işlemini birden çok alan üzerinde gerçekleştirebilmek için kullanılır. SearchableText ve Title parametrelerinde arama yaptık.

Field(ff => ff.SearchableText, 2.0) ve Field(ff => ff.Title, 1.0) alanlarının içerisinde 2.0 ve 1.0 ne anlama geliyor?

Burada 2.0 ve 1.0 alanlarını boost olarak tanımlanmaktadır. “Tek tek alanlar, sorgu parametresindeki gibi boost parametresi ile otomatik olarak artırılabilir — alaka düzeyine daha fazla sayılabilir

boost: öncelik ve katsayı(ölçeklendirme) işlemidir.

Arama yapmak için girdiğim cümle veya kelime dizesi (.Net core da işlevsel arama) indexlerimde SearchableText ve Title alanlarında arama yap, SearchableText alanındaki eşleşmeyi, Title alandaki eşleşmeye göre 2 kat daha fazla önemse olarak yorumlayabiliriz.

multi_match sorgusunun dahili olarak yürütülme şekli type parametresine bağlıdır (TextQueryType)

  • (varsayılan) Herhangi bir alanla eşleşen dokümanları bulur, ancak en iyi alandan _score kullanır. [ BestFields]
  • Herhangi bir alanla eşleşen dökümanları bulur ve her alandan _score’u birleştirir.[ MostFields]
  • Alanlara aynı analizörle büyük bir alanmış gibi davranır. Herhangi bir alandaki her kelimeyi arar.[ CrossFields]
  • Her alanda bir match_phrase sorgusu çalıştırır ve en iyi alandan _score kullanır.[ Phrase]
  • Her alanda bir match_phrase_prefix sorgusu çalıştırır ve en iyi alandan _score kullanır.[ PhrasePrefix]

* Operator ve minimum_should_match

Eşleşmesi gereken minimum koşul cümlesi sayısı minimum_should_match parametresi kullanılarak ayarlanabilir.

Operator And ve Or işlemi aramanın kelime bazında (Or) olarak arar herhangi bir kelimenin bulunması, And ise yazılan cümlenin birleşik olarak aranması yönündedir.

* Sort — Sıralama

Bir önceki multi-match query örneğine ek olarak sıralama işleminide katalım.

Query işlemine cevaplar döndükten sonra filtreleme sırasında değil de search (arama) yaparken CreatedDate alanına göre sıralayarak alırız.

* Range , GreaterThan , GreaterThanOrEquals vb… (Operators)

Sorgularımızı karmaşık hale getirelim. Arama işlemlerini yaparken TagNameValues(List<string>) alanının adeti 2 den fazla veya CategoryId alanının CategoryId≥3 olarak isteğimizi özelleştirelim.

Detaylı bilgi için tıklayın…

* Skip, Take

Linq işlemlerinden hatırlayacağımız ve genelde sayfalama (pagination) işlemi için kullandığımız bir yapı olan Skip-Take parametrelerinin ElasticSearch Query işlemlerinde kullanılış şekli;

* Boolean Query

Döndürülen belgelerin eşleşmesi gereken koşulların sayısını veya yüzdesini belirtmek için minimum_should_match parametresini kullanabilirsiniz

Sorgularımızı bu şekilde çoğaltarak devam edebiliriz. Yukarıda yazmış olduğumuz query nesnesini elasticsearch için search metodunda kullanalım.

Search metodundan geriye dönen değeri PostElasticIndexDto olarak mapping işlemini gerçekleştiriyoruz.

Test işlemleri

Test işlemlerimizi ben Swagger üzerinden yapacağım. Swagger ile ilgili bilgi edinmek için .Net Core Swagger yazımı okuyabilirsiniz.

API projemizde PostController isminde bir API Controller oluşturuyoruz. İşlemleri gerçekleştirmek için bir kaç metot ekliyoruz.

AraBakalim HttpGet metodunu kullanarak “Core işlemleri sql” cümleciğini yazıp çalıştırıyoruz.

Oluşturmuş olduğumuz querye ait parametreleri searchQuery içerisinde görüntüleyebiliriz.

Arama işlemi sonucu dönen Documents değerlerine göz atalım.

Search işlemi için göndermiş olduğumuz SearchDescriptor nesnesini Json olarak elde edebiliriz (Ne işimize yarayacağını belirteceğim). Bunun için bir metot tanımlayalım.

Oluşturduğumuz SearchDescriptor nesnesini metoda gönderelim ve geriye json bilgilerini alalım.

Json bilgileri.

Bu json bilgisini kurmuş yada kullanmış olduğumuz ElasticSearch-Head arayüzünde Any Request tabına yapıştıralım ve kod ile almış olduğumuz değeri buradan da elde ettiğimizi görebiliriz. Bu json bilgilerini değiştirerek sonuçları test edebiliriz.

ElasticSearch işlemleri deniz derya tek tek anlatmak zor. Ben yazdığım projelerde kullandığım metot ve sorguları ve bunlardan esinlenerek değiştirip daha farklı query oluşturdum.

En azından ElasticSearch kurup, index oluşturup ve bu indexlerden giriş düzeyinde sorgulamalar yapabilecek kadar bilgi aktarmaya çalıştım.

Makaleyi yazarken onlarca blog yazısı ve elasticsearch dökümantasyonu okuyup temiz anlaşılır ve kısa cümleler ile aktarım yapmaya çalıştım umarım faydalı olmuştur.

--

--