fatiherikli

Bildiğiniz üzere MongoDB document-oriented bir NoSQL veritabanıdır. Verileri JSON şeklinde saklayıp, JSON şeklinde erişiyoruz. Daha doğrusu BSON (Binary JSON) şeklinde.

NoSQL database sistemleri üzerinde group, distinct gibi işlemler ilişkisel veritabanlarına (mysql, postgresql) nazaran biraz daha karmaşık. Bunun gibi sorgular fonksiyonel programlama'nın temellerinden olan MapReduce işlemi ile yapılmaktadır. MapReduce MongoDB üzerinde built-in olarak gelmektedir.

Map ve Reduce fonksiyonları

Sorgular için iki adet fonksiyon yazıyorsunuz; map ve reduce. Şimdilik MongoDB üzerinde sadece javascript ile yazılabiliyor.

Bir örnek yapalım

Myadslot.com üzerinden örnek vermek istiyorum; istatistik dataları benim üşengeçliğimden dolayı MySQL database üzerinde diğer kayıtlar ile birlikte saklanmaktaydı. Bu gece vaktimi eski verileri MongoDB'ye aktarmak için data-migration yazarak geçirdim. MongoDB üzerinde saklanan datalar şu şekilde;

{
    "last_visit_date": "2012-01-26 18:05:41",
    "slot_id": 9,
    "user_agent": "Mozilla/5.0 (iPhone; CPU iPhone OS 5_0_1 like Mac OS X) ",
    "last_visit_url": "http://dbdsgnr.appspot.com/",
    "visit_count": 2,
    "ip_address": "72.179.56.244",
    "advertisement_id": 7
}

Problem şu;

Slot istatistikleri sayfasında slota ait tüm reklamların görüntülenme sayısının toplamının alınması gerekiyor. Aslında bu data zaten slot üzerinde denormalize edilmiş durumda, maksat örnek olsun :)

Örnekte MongoDB client'i olarak pymongo kullanacağız. Veritabanına bağlanmak için şöyle bir fonksiyon kullanabiliriz;

import pymongo
def get_db(db_name="myadslot"):
    return pymongo.Connection()[db_name]

Map ve reduce fonksiyonlarımızı yazalım.

map_slots = """
function () {
    emit(this.slot_id, this.visit_count);
}
"""

Gördüğünüz üzere map edilen dökümana (row) this keyword'ü ile ulaşabilmekteyiz. slot_id'sini key, visit_count'u ise value olarak belirledik. Şimdi reduce fonksiyonumuzu yazalım.

reduce_slots = """
function (key, values) {
    var total = 0;
    for (var i in values) {
        total += values[i]
    }
    return total
}
"""

Reduce fonksiyonumuza slot_id ve visit_count parametre olarak geliyor. Biz burada slota ait tüm reklamların visit_count'unun toplamını döndürüyoruz. Python içinde javascript birazcık pis oluyor gördüğünüz üzere. Ancak MongoDB'nin sonraki versiyonlarında ek olarak başka script dilleri kullanabileceğiz. Şimdi bu fonksiyonlarımızı MongoDB üzerinde çalıştıralım.

db = get_db()
result = db["visitors"].map_reduce(map_slots, reduce_slots, "slot_stats")
for item in result.find():
    print item

Map reduce işleminden sonra bize geçici bir koleksiyon oluşturulmakta. Geçici koleksiyonumuzun adını slot_stats olarak belirledik. Bu koleksiyon üzerinden tekrar filtreleme yapabilmekteyiz ancak biz hepsini yazdırdık. İşlemin sonucu şu şekilde olacaktır;

{u'_id': 4L, u'value': 17.0}
{u'_id': 5L, u'value': 335909.0}
{u'_id': 6L, u'value': 3L}
{u'_id': 9L, u'value': 3736.0}
{u'_id': 10L, u'value': 4.0}  
...

Ayrıca django ile birlikte MongoDB kullanımı için aşağıdaki bağlantıları göz atmanızı tavsiye ederim.

comments powered by Disqus