Elasticsearch: Leb deyince leblebi

Her web geliştiricisinin hayatı boyunca en az 1 defa bulaştığı bir kavram; “otomatik tamamlama — autocomplete — ” kavramından bahsediyorum.

Bir önceki Elasticsearch yazımda, bu teknolojinin “arama dünyası” içerisindeki önemine gönderme yapmıştım. Yukarıdaki gif’i, bu yazıyı yazarken oluşturdum. Google’ın otomatik önerilerinden de görebileceğimiz üzere “hız”, “iyi”, “kullanım” gibi anahtar kelimeler Elasticsearch’ü IT dünyasında tanımlamak için biçilmiş kaftan durumunda.

Sevgili dostum Kemal Ogün Işık’la da tartışığımız ve global dünyada kabul edildiği üzere “arama” eylemi bir mühendislik dalı artık. Bu mühendisliğin en temel gereksinimleri üzerine (hız, veri tutarlılığı, stabilite) ürünler ve ürünlere ait özellikler her gün geliştirilmeye devam ediyor. Bu yazının konu başlığı olarak da Elasticsearch, aramaların yine bir başka temel gereksinimi olan “öneri sistemi” üzerine bir fonksiyonaliteyi biz geliştiricilere sunmuş durumda.

Elasticsearch: Completion Suggester

Elasticsearch, sunmuş olduğu bu suggester (tavsiye) özelliği ile kullanıcılara search-as-you-type (yazdığın gibi ara) fonksiyonalitesini sunuyor (1).

Hemen bu noktada belirtmekte fayda var ki, yazının devamında değineceğimiz tip; verinin genel yapısı, saklanması ve aranması konusunda sunabileceği maksimum hız için optimize edilmiş durumda. Dolayısıyla canlı ortamda kullanılırken Elasticsearch’ün resmi web sitesinde yapılan uyarıları dikkate almakta fayda var.
Tarihin en hızlı otomatik tamamlanabilen süper kahramanı :)

Vakit kaybetmeden bize sunulan bu özelliği inceleyelim derim. Bunun için öncelikle örnek bir index oluşturalım:

Yukarıdaki mapping komutunda “title_autocomplete” olarak isimlendirilmiş alan, öneri sonuçları için kullanacağımız alan. Type : completion ifadesi bu öneri sistemini aktif etmek için aslında yeterli. Bu tiple ilgili bazı opsiyonel parametreler tanımlanabiliyor. Bu parametrelerden önemli olduğunu düşündüğüm ise preserve_separators isimli özellik. Bu özellik varsayılan olarak true değerini taşıyor. Eğer bunu false olarak ayarlarsak metin içerisindeki boşluklar gözardı edilecek. Yani “Elasticsearch autocomplete” diye bir arama yaparken elasticsearchau şeklinde de bir prefix gönderseniz size sonuç dönecektir. Öneri sisteminizin mantığına göre bu özelliği değiştirebilirsiniz.

Veriyi indexleme

Aslına bakarsanız Elasticsearch’e herhangi bir veri eklemekten bir farkı yok. Ancak dilerseniz input ve weight özelliklerini vererek bu alanı özelleştirebilirsiniz.

  • Input: Bir metin dizisi olabileceği gibi, direkt olarak metnin kendisi olabilir.
  • Weight: Önerilecek olan anahtar kelimelerinize sıralama ağırlığı verebilirsiniz. Örneğin; “otomatik tamamlama” yazılırken bir öneri sunmak istiyorsunuz. İlk sırada “Elasticsearch”, ikinci sırada ise “Solr” önereceksiniz. Bunun için pozitif sayısal ifadeler ile bu anahtar kelimelere ağırlıklı not verebilirsiniz.

Örnek verilerimiz ise şu şekilde:

E ne duruyorsun! Önersene

En temel haliyle örnek aramamızı yapalım:

Prefix özelliği can alıcı olan kısım. Burada kullanıcının yazdığı değer yer alıyor. Ben şu anda önümdeki text alanına “do” yazdım ve Completion.Field alanında belirttiğim; index mapping’imdeki “title_autocomplete” alanında bir öneri araması gerçekleştiriyorum:

Sonuçlar tam beklediğim gibi! 1 ve 2 id’li kayıtlarımı bana öneri olarak getirdi. _source özelliği, öneri olarak getirilen kaydın orijinalini üzerinde taşıyor. Dilerseniz sorgunuzu aşağıdaki gibi değiştirerek ilgili özellikte sadece arama yapılan alanın gelmesini de sağlayabilirsiniz (6. satıra dikkat).

Peki lep demeden leblebi istesem

Hatalı yazımların tolere edilmesi (fuzziness) özelliği de suggester içerisinde sağlanan özelliklerden bir tanesi. “do” değil de “dög” yazsam da (o yerine ö, k yerine g hatası) aynı sonuçları vermesini istiyorsanız bu özelliği kullanabilirsiniz. Bunun için sorgunuzu aşağıdaki şekilde güncellemeniz yeterli olacaktır.

fuzzy.fuzziness parametresi sayısal değerler alabilmesine rağmen, girilen metnin uzunluğuna göre kendini optimize edebilmesine olanak sağlayan “auto” değerini taşıması önerilir. Hatalı metnin tolere edilmesi esnasında kullanılan Levenshtein Edit Distance algoritmasını merak ediyorsanız ilgili (2) linke göz gezdirebilirsiniz.

Regex araması

İnternette sıklıkla rastladığım bir alıntı ile giriş yapmak isterim:

Some people, when confronted with a problem, think “I know, I’ll use regular expressions.” Now they have two problems.

Buna rağmen regex ile arama yapmak isterseniz, suggester bu özelliği de sağlıyor. NOT: Performans konusunda sorun yaratabileceği ihtimalini lütfen gözünüzün önünden ayırmayın.

Sorguyu aşağıdaki şekilde değiştirdiğimizde regex ile arama yapabilme potansiyeline erişmiş oluyoruz:

Gelen cevap da bizi tatmin eder düzeyde:

Regex ile aramanın önemli parametrelerinden bir tanesi flags isimli parametre. Varsayılan olarak ALL değerini almakla birlikte ANYSTRING, COMPLEMENT, EMPTY, INTERSECTION, INTERVAL ve NONE değerlerini de üzerinde taşıyabiliyor. Detaylı bilgiye ise ilgili (3) adresten erişmeniz mümkün.

Bu satırlara kadar bana eşlik ettiğiniz için teşekkür ediyorum. Gördüğünüz eksik gedik ne varsa bana iletirseniz sevinirim. O zamana dek; arama sonuçlarına döndüğünüz öneriler hep tamamlayıcı olsun :)

Kaynak

(1) https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html

(2) https://en.wikipedia.org/wiki/Levenshtein_distance

(3) http://lucene.apache.org/core/4_9_0/core/org/apache/lucene/util/automaton/RegExp.html