Elasticsearch: Özelleştirilmiş Sıralama Algoritması

Selçuk Usta
Aug 7, 2017 · 5 min read

Geçtiğimiz günlerde Kariyer.net, iş bulma uygulamaları konusunda markete yeni bir fikir ile iddialı bir giriş yaptı hepimizin malumu. “İşin Olsun” adlı uygulama “abi Beylikdüzü’nden Ümraniye’ye kim gidecek, olsa şuralara yakın bir iş de biz de trafikte ömür tüketmesek!” veryansınına çare bulacak gibi. Takdire şayan bir iş.

Kariyet.net teknik ekibi, uygulamanın arkaplanında nasıl bir teknoloji, yazılım, sistem kullanıyor; hiç bir fikrim yok açıkçası. Benim de bu yazıdaki derdim, böyle bir ihtiyaca nasıl bir çözüm üretirdim? sorusuna kendimce cevaplar aramak.

O halde beyin fırtınasına başlayalım.

Image for post
Image for post
Kaynak: http://www.innercirclelabs.com/wp-content/uploads/2016/04/brainstorming.png

Hangi arama altyapısını tercih ederdim?

Bu sorunun cevabı benim için çok zor olmuyor elbette. Daha önceki yazılarımda da bol bol güzelleme yaptığım Elasticsearch ürününün bu iş için biçilmiş kaftan olduğunu düşünüyorum.

Yakınımda iş ararken nelere dikkat ederim?

Bu filtreler temel anlamda ilk filtreleme için hepimizin ortak noktası sanıyorum. Üstelik bu filtrelerden geçen her firmaya eşit mesafe ile yaklaşmak da değil niyetim. Örneğin bir firmanın servisi varsa ve yan hakların tamamını sağlıyorsa, bu şartları tam sağlamayan ama en yakın olandan daha önceliklidir. Ya da servisi yok ama yan hakları varsa, servisi olan ancak yan hakların tamamını sağlamayandan daha önceliklidir.

Teknik Analiz

İlk anda dikkatimizi çektiği üzere klasik bir arama sonuç sıralama algoritması (A-Z, Z-A) böyle bir uygulama için yeterli olmayacaktır. Filtreden seçili değerlere göre sonuç setine dahil olacak kayıtların ağırlıklı puanlarını özelleştirilmiş olan hesaplayan bir algoritma uygulamanın kalbinde yer alıyor.

Gelelim asıl soruya, Elasticsearch bu karmaşık hesaplama konusunda biz geliştiricilere ne sağlıyor?

Image for post
Image for post
Kaynak: http://www.vector-eps.com/wp-content/gallery/math-formula-vectors/mechanics-formula-vectors.jpg

Elasticsearch’te Sıralama

Elasticsearch’ün kayıtları sıralarken varsayılan davranışı, kayıtları “_score” değerlerine göre sıralamasıdır. Bu değer hesaplanırken de yine varsayılan bir formül üzerinden işlem yürütülmekte.

Örneğin kayıt modelinizde “Title” ve “Description” adlı iki alan (field) olduğunu varsayalım. “iş” diye bir kelimeyi de bu alanlarda arıyorsunuz. En basit haliyle aradığınız kelime ilgili alanlarda ne kadar sıklıkla geçiyorsa o kaydın _score değeri o kadar yüksek olacaktır.

Ancak özelleştirilmiş bir ağırlıklı puanlama algoritması oluşturduğunuzda bu varsayılan davranış size yetmez hale gelecektir. Yazının temel çıkış noktası da bu yetmeme durumuna bir çözüm senaryosu geliştirmek üzerine.

Function Score Sorgusu

Bu sorgu tipi ile, sorgunuzun sonuç setine dahil olan kayıtların skorlamalarını özelleştirebilirsiniz. Elasticsearch’ün resmi dokümantasyonundan (1) an itibariyle kullanıma sunulmuş 5 farklı fonksiyonun detaylarına da erişmeniz mümkün. Bunlardan önemli gördüğüm ve kullanmaktan büyük keyif aldığım decay fonksiyonlarından gauss tipinin bizim sorunumuza çare üretebileceğini düşünüyorum.

Decay Fonksiyonları — Gauss

Aralık (range) tipine benzer bir işleve sahip bu fonksiyonlar ile, kullanıcının vermiş olduğu değer aralıklarındaki kayıtların skorları özelleştirilebilir. Range filtresi ile en büyük farkı, keskin çizgilerle sorguyu filtrelemek yerine daha yumuşak bir geçişle sorguyu filtreler.

UYARI: Elasticsearch’ün kısıtlarına göre, bu fonksiyonlara gönderebileceğiniz veri tipleri sadece date, numeric ve geo point tipinde olabilir.

Her bir decay fonksiyonunun kendine ait bir hesaplama formülü bulunmakta. Tam bir matematik fırtınası kopuyor aslında içeride. Örneğin, Gauss tipindeki hesaplama için kullanılan formül aşağıdaki gibi:

Image for post
Image for post
Kaynak: https://www.elastic.co/guide/en/elasticsearch/reference/current/images/Gaussian.png

Çok fazla teorik bilgiye dalıp boğulmadan örneğimiz üzerinden bir çalışma gerçekleştirelim. Bunun için de Docker’da bir Elasticsearch instance’ı oluşturalım:

docker pull docker.elastic.co/elasticsearch/elasticsearch:5.4.3docker run --name elastic -d -p 9200:9200 -p 9300:9300 -e "http.host=0.0.0.0" -e "transport.host=127.0.0.1" -e "xpack.security.enabled=false" docker.elastic.co/elasticsearch/elasticsearch:5.4.3

Bir sonraki adımda career_sample_index adıyla yeni bir index oluşturalım. Bu index’in CompanyName, Position, Salary, Servicing ve Location adlarına sahip 5 adet field’ı olacak. Servicing şirketin servis hizmeti olup olmadığını, Location ise şirketin konumunu belirtiyor.

Bu index için örnek kayıtlar oluşturmadan hemen önce bir harita üzerinde rastgele konumlar seçelim:

Image for post
Image for post

Yukarıdaki haritada “mavi” ile işaretlenmiş nokta, evimizin olduğu nokta. Diğerleri ise iş fırsatlarının yer aldığı noktalar. Haritanın açık haline bu linkten ulaşabilirsiniz.

Şimdi de örnek kayıtlarımızı ekleyelim:

Öncelikle yapmak istediğim şey, bulunduğum konuma en yakından en uzağa şeklinde kayıtları sıralı bir şekilde listeleyebilmek. İşte bu noktada gauss fonksiyonu devreye giriyor:

10. satırda kullanacağım fonksiyon tipini (gauss) belirttikten sonra 11. satırda bu fonksiyona hesaplama için vereceğim field’ın adını yazıyorum. Asıl fırtına ise alttaki 4 satırda kopuyor.

Peki sorguyu daha özel bir hale getirmek istesem, tıpkı şunun gibi:

Aranan pozisyonun “Software Developer” olmasını istiyorum. Sıralama yaparken servis hizmeti sunan firmalar, sunmayanlardan 2 kat daha değerlidir. Bununla birlikte bana yakın bir mesafede olması da sıralamanın önem katsayına direkt olarak etki eder.

match_phrase sorgusu ile birebir bir “Software Developer” eşleştirmesi istiyorum ki böylece diğer pozisyonlar sonuç setine dahil edilmesin. gauss fonksiyonunu yukarıda açıklamıştık. Buraya ekstra gelen bir field: weight. Bu alanın değeri hesaplanan _score değerine 1.2 kat sayısı ile katkıda bulunacak.

İki filter alanı ile de ifade etmek istediğim nokta; “Servicing” değeri “true” olarak işaretlenmiş bir kaydın _score değeri, “false” olarak işaretlenmiş kayıttan 2 kat değerli olarak hesaplanmalıdır.

score_mode alanı ile bu ağırlıklara göre çıkan ayrı ayrı formül değerlerinin toplanarak bir kaydın _score değerinin hesaplanacağını belirtiyorum. Yine (1) numaralı referans url’inden bu alanın alternatif değerlerini öğrenebilirsiniz. Gelen sonuç seti ise aşağıdaki gibi:

İki sonuç seti ile son seti(sadece mesafeye göre sıralayan — mesafe ve kriterlere göre sıralayan) karşılaştırdığınızda göreceksiniz ki DEF Tech adlı firma bana daha yakın iken servisi olmadığı için, servisi olan ve benden biraz daha uzak ASD Cloud Solutions firmasının altında kalıyor. Bu da filtrelerimin sağlıklı bir şekilde çalıştığını gösteriyor.

Sonuç

Bu fonksiyonlar yardımı ile Elasticsearch’ün varsayılan sıralama algoritmasını pas geçerek tamamen özelleştirilmiş ve ihtiyaçlarınıza hizmet eden algoritmalar üretebilirsiniz. Özellikle “relevance” algoritmaları için bu servis bir harika çalışıyor! İlham aldığım linkler bölümündeki (2) numaralı link yardımı ile tarihsel bir gauss eğrisinin nasıl hareket edeceğini görmeniz mümkün.

Bir sonraki yazıda tekrar buluşana dek arama sonuçlarınızın hızlı olduğu kadar aradığınız derde derman da olması dileğiyle :)

İlham Aldığım Linkler

(1) https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-function-score-query.html

(2) https://codepen.io/xyu/full/MyQYjN/

(3) https://jontai.me/blog/2013/01/advanced-scoring-in-elasticsearch/

Selçuk Usta

Written by

Software Development Manager (at) Rasyotek. Former trainer & consultant. Family member of C# and Python. Newbie on Unix. Articles are mostly about coding.

Selçuk Usta

Written by

Software Development Manager (at) Rasyotek. Former trainer & consultant. Family member of C# and Python. Newbie on Unix. Articles are mostly about coding.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch

Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore

Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store