Lucene ve Memory Problemleri

Bir süredir içinde yuvarlandığım bir konuda Lucene. Lucene Java da geliştirilmiş bir arama motoru belkemiği olarak tanımlanabilir. Arama ve indeksleme işlemlerini yüksek performanslı olarak yapan Apache bünyesinde bulunan bir açık kaynaklı kütüphane. Lucene hakkında yakında daha detaylı bir yazı yazmayı düşünüyorum. Fakat şimdilik yakın zamanda beni uzun süre uğraştıran bir konu hakkında ufak birşeyler yazmak istedim. Lucene gerçekten çok hızlı ve de çok başarılı sonuçlar veren bir kütüphane. Fakat gerçekten dikkatli olunduğunda. Dikkatli olunmadığı zaman işleri cehnneme çeviren bir canavarada dönüşebilmekte. En basitinden sunucunun hafızasını aç bir canavar gibi amansıca sömürebilir :) Ve buda yetmezmiş gibi çılgınlar gibi OutOfMemoryExceptionalarını peşpeşe dizebilir. Maalesef bu köprüden geçen biri olarak söylemeliyimki gerçektende tadılması güzel olan bir deneyim değil.

Arama motorları genelde yüksek işlem gücü yanından büyük hafızalarada ihtiyaç duymaktadır. Fakat büyük hafza diyince de ipin ucunu da kaçırmamak lazım tabii ki :) . Benim geliştirdiğim ortamda yaklaşım 13GB lık bir indeks dosyasından (12 alana göre indekslenmiş) 6 değişkenle arama yapılabilmekte. Bu da gerçekten Lucene için ağır bir işlem gibi. Full text search e yönelik yazılan Lucene i daha çok bir veritabanı araması yapar gibi kullanmak gerektiğim bu projede kompleks bir Query geçmem gerekti. Gerçekten de bazen query süreleri gerektiğinden uzun sürmekte. Bununla ilgili performans çalışmalarım devam ediyor.

Bu yazımda bahsetmek istediğim ise şimdiye kadar kullandığım kadarı ile Lucene içinden çıkarttığım dersler. Lucene kullanmış olanlar IndexSearcher'ı da tanıyordurlar. IndexSearcher denilen yapı sizin arama yaptığınız indeks dosyalarını hafızaya alıp bunların içinde gerekli işlemleri yapan sınıftır. Bu sınıf gerçektende çok dikkat edilerek kullanılması gerekmekte. Çünkü her açılan IndexSearcher hafızada sahip olduğunuz indeks dosyalarının boyutuna göre yer kaplamakta ve de jvm ölmediği sürece bu alanı kesinlikle bırakmamakta. Eğer sunucunuza güveniyorsanız o zaman çoklu IndexSearcher kullanmak belki bi ihtimal olabilir ama yoğun arama yapılacak alanlarda bunun olumsuz bir sonuç ortaya koyacağını söylemeliyim.

Deminde dediğim gibi çıkarmış olduğum birkaç ders var ve bunları şu şekilde sınıflandırabilirim:

1. İhtiyacınız olandan daha fazla searchers/readers açmayın/yaratmayın/kullanmayın

Her IndexSearcher/IndexReader açtığınızda hafızanızdan bir parça daha alacaktır. Static olarak tanımlanmış bir uygulama yapısı içinde sadece bir adet IndexSearcher/IndexReader ihtiyacınızı görecektir. Sadece hafızada paylaşılan ve çoklu bir thread yapısında paylaşılabiilinen bir IndexSearcher/IndexReader yapısına ihtiyacınız var.

2. İşinizin bittiği kaynakları mutlaka kapatın

Araştırmamda en çok hata yapıldığını gördüğüm hatalardan biride işi biten IndexSearcher veya IndexReader ları kullanıcıların kapatmaması durumu. Herşeyi GarbageCollector un yapacağını düşünmemek ve işi bittiğinde bu yapıları kapatmayı unutmamak gerkmektedir.

3. İhtiyacınız olandan daha fazla kolonu sıralamayın.

Her sıralama yaptığınızda sıralama yaptığınız alan için hafızada bir FieldCache dizisi (array) yaratılır. Eğer hafızadan bir miktar kurtarmak istiyorsanız sıralama yapılmasına izin verilen alanların sayısını azaltabilirsiniz. 30 alana göre sıralama yapmak yerine önemli olan daha az alana göre sıra yapmak çok daha mantıklı ve hafızadan kurtarıcı bir yapı olacaktır.

4. RangeQuery, PrefixQuery ve WildCardQuery Hafızadan alan demektir.

Eğer RangeQuery, PrefixQuery ve WildCardQuery yapılarından birini kullanıyorsanız, hele birde TooManyClauses hatası almamak için BooleanQuery.maxClauseCount değeri ile oynadıysanız hafızanızdan büyük bir miktarı bu işlere ayırmayı çoktan kabul etmişsiniz demektir; hafızanızın yoğun ve ağır kullanılmasına hazırlıklı olun. Bunu düşünerek query lerinizi olabildiğince optimize kullanmaya dikkat etmeniz gerekmektedir. eğer "field:a*" gibi bir query hazırladıysanız; Lucene bunu field alanında bulunan ve de a ile başlayan tüm değerler için bir TermQuery oluşturup bunları BooleanQuery altında birleştirecektir. Buda devasa bir query demektir. Devasa bir query ise hafızada büyük bir alanın kullanılması demektir.

5. Kullanmayacağınız alanları ayrı ayrı alanlarda (field) indekslemeyin

İndekslenmiş birçok alanınız var ise bu problemle karşılaşabilirsiniz. FieledNorms yapısı her dökümanın (yada girdinin) her indekslenmiş alanı için 1 byte kaplamaktadır. İndekslenmiş alanın değeri boş bile olsa genede bu alan kaplanacaktır. Internette indeksleme sürecinde bu normların hesaplanmamasını sağlanabileceği hakkında bazı şeyler okudum. Fakat bu konuda hala araştırma düzeyidne olduğum için çok yardımcı olamayacağım. En azından şu an için

Bu sıraladığım problem çözüm önerilerinden en çok baş ağrıtanı 1. sırada yer alan IndexSearcher/IndexReader konusu. OutOfMemory hatalarında ilk bakacağınız yer bu olsun.

Lucene gerçekten çok başarılı bir kütüphane fakat en başta da söylediğim gibi dikkatli kullanılmadığı zaman uykuları da kaçırabilecek bir yapı. Gene başta söylediğim gibi Lucene ile ilgili genel bir yazı yazmak istiyorum ve bunun hazırlıklarına başladım. O zamana kadar herkese iyi aramalar dilerim :)

randomHero tarafından 17.02.2006 tarihinde yazılmıştır.

Labels: , , ,

1 Comments:

Anonymous Anonymous said...

cok guzel bır yazı olmus bende bu gunlerde lucene ıle ugrasıyorum bu arada bana onerebılecegınız kaynak varmı ? ya da source code lar falan ?
sımdıden tesekkurler
mailim:dejasjli@gmail.com

8/07/2008 6:11 AM  

Post a Comment

Subscribe to Post Comments [Atom]

<< Home