C# / MongoDb – MapReduce

Herkese merhaba. Bugün yazacağım makalede MongoDb ile MapReduce işlemleri yapacağız. Öncelikle MapReduce yapısı hakkında kısaca bir giriş bölümü yazacağım.

MapReduce dağıtık mimari üzerinde büyük verilerin kısa zamanda analiz edilebilmesini sağlayan bir sistemdir. Verileri analiz edip onlardan aggregate sonuçlar üretmek için kullanılır. Map fonksiyonu ile belirtilen key/value değerlerine göre veriler toplanır. Ardından Reduce fonksiyonu ile toplanan veriler aggregate sonuçlara çevrilir.

  • Map fonksiyonunu SQL select sorgusu olarak düşünebiliriz.
  • Reduce fonksiyonunu ise; count, having, avg gibi SQL sorguları olarak düşünebiliriz.

Hesaplama map fonksiyonu içerisinde key/value değerleri alır ve reduce işlemi sonrasında key/value değerlerine göre bir çıktı üretir. Her iki fonksiyonda kullanıcı tarafından yazılmaktadır.

Aşağıda gösterilen örnekte her kelimeden kaç adet bulunduğu hesaplanıyor. Öncelikle değerler 3 gruba ayrılıyor. Ardından mapping kısmında her grupta bulunan kelimeler sayılıyor. Sonrasında her grupta aynı olan kelimeler bir bölümde toplanıyor. Reduce aşamasına geçildiği zaman ise her bölümde toplanan kelimeler sayılıyor ve en son değerimiz ekrana çıkarılıyor. Giriş değerimizin büyük boyutta olduğunu düşünelim. Böylece istenilen sorgu map reduce ile kolayca elde edilmektedir. Map reduce ile ilgiyi geniş bilgi internette fazlasıyla mevcuttur. Detaylı bilgi için; research.google, wikipedia

map-reduce-flow

Örnek: Bu yazıda göstereceğim map reduce işlemi daha önce üzerinde örnekler yaptığım restaurants collection üzerinde olacaktır. Collectionda bulunan her documentta restaurantın bulunduğu semt adı bulunmaktadır. Map fonksiyonu ile semt değerine göre gruplama yapılacak. Ardından Reduce fonksiyonu ile her semt değeri için mevcut olan restaurant değerleri toplanıp çıkış değeri olacak gösterilecektir. Ekstra olarak restaurantları yemek türüne göre filtreleyip hangi yemek tipinden nerede kaç restaurant var görebiliriz.

  • Veritabanı için gerekli bağlantılar

1

  • MapReduce işlemleri için gerekli javascript fonksiyonlarını yazalım. MongoDb’de MapReduce işlemini uygulamak için fonksiyonlar javascript formatında yazılmalıdır. Map fonksiyonu ile borough (ilçe) değeri anahtar olarak belirtilmiştir. Value değeri olarak 1 yani her value değeri için o değer üzerine +1 eklenecektir. Reduce fonksiyonu ile values dizisine biriken değerler her key değeri için toplanıyor. Finalize fonksiyonu içerisinde toplanan değerler integer olarak ekrana döndürülüyor. Finalize fonksiyonu reduce işleminden sonra yapılacak olan düzenlemelerin uygulandığı fonksiyondur.

 

2

  • Restaurant tipine göre filtreleme yapmak istersek;

3

  • Öncelikle MapReduceOptions ile gerekli ayarları yapıyoruz. Giriş değeri restaurant sınıfı, çıkış değeri ise BsonDocument olarak belirtilmiştir. MapReduce metodunda tanımlarını yaptığımız fonksiyonlar (map-reduce) ile options parametresine belirttiğimiz ayar değerlerini yazıyoruz. Ardından tüm sonuçları await results.ToListAsync() ile docs değişkenine atıyoruz. Bütün bu işlemleri yaptığımız metod async değer döndürmelidir. Çünkü MongoDb yeni sürümü ile async/await olarak sorguları çekmekteyiz. Foreach kısmında ekrana yazma işlemleri yapılmaktadır.

4

  • Filtresiz ekran çıktısı. Sonuçta görüldüğü gibi 25.360 değer mevcuttur. MapReduce işlemi ile tüm verileri tarayıp az sürede sorgu gerçekleşmektedir.

restaurantoutput

  • Filtre kullanılarak yapılan sorgu sonucu oluşan ekran çıktısı. Restaurant yemek tipi “irish” olan restaurantları sorguluyor.

restaurantoutputfilter

Mevcut veriler için MapReduce işlemini gerçekleştirdik. Peki yeni veriler eklendiği zaman tekrar tüm veriler aynı işlemden geçirilmeli mi? Geçirilirse büyük veriler için maliyet kaybı olacaktır. Bu durumlar için Incremental MapReduce uygulanır. Sadece yeni eklenen verilere işlem uygulamak için, örneğin belli bir tarihten sonraki eklenen değerleri almak için bir sorgu yazarız. Böylece sadece yeni veriler MapReduce işlemine tabi olur. İşlem bitince eski sonuçlara yeni sonuçlar eklenir.

İngilizce versiyonu

Kaynaklar

MapReduce Doc

Asp.NET Web API – MongoDB

Bir süredir ara verdiğim MongoDB serisine devam ediyorum. Bu yazıda Asp.NET Web API framework ile yapılan projede MongoDB veritabanından çekilmiş olan verileri REST yapısında tüm kullanıcılara göstereceğiz. Ardından bir diğer yazıda JSON biçiminde dönen verileri sorgu ile web api’den çekip kullanacağız. Veri seti olarak MongoDB sitesi üzerinde örneklerde kullanılmak üzere paylaşılan restaurants veri setini kullanacağım. Bu linkten indirilebilir.image001

Uygulamayı local üzerinde çalıştıracağımız için cmd ekranı üzerinden mongod komutu yazılarak, server başlatılmalıdır. Eğer kurulum yapmadıysanız MongoDB giriş makelesinde kuruluş için gerekli linkler mevcuttur. İlk başta temel olarak verilerin ekranda gösterilmesi, belirli bir restaurant id değerine göre gözükmesi, güncellenmesi ve silinmesi gibi REST’in temel işlemlerini ekleyeceğim.

Öncelikle visual studio üzerinden web api projesi açıyoruz ve nuget paketlerinden mongodb offical driver’ı yükleriz. Proje yapısı aşağıdaki gibidir.  DAL yani veri ile direk temas yapacak olan kısım ayrı bir sınıf kütüphanesi olarak eklenecektir. Bu kütüphanede veriler ile yapılacak işlemler için Generic Repository ve Unit of Work patternleri uygulayarak daha güzel ve esnek bir yapı oluşturuyoruz. Oluşturulan bu esnek yapı sayesinde uygulamanın test edilebilirliği ve yönetilebilmesi kolaylaşmaktadır. Ana proje bölümünde şimdilik sadece resturantcontroller sınıfı içerisinde işlemler yapılmaktadır. Dependency Injection, authorize ve log işlemleri yapmak istersek projeye ilaveler ekleriz.

Detaylı olarak bu yapıyı bu yazıda anlatmayacağım. Bu linkte bulunan yazıda generic repository ve unit of work yapısı hakkında detaylı bilgi mevcuttur.

1

MongoDb sitesi üzerinden indirdiğimiz örnek veri setinin yapısı aşağıdaki gibidir. Bu veri setindeki yapıya uygun olarak model sınıflarımızı oluşturacağız.

2

Temel model sınıfı olan restaurant aşağıdaki gibi tanımlanmıştır. Address sınıfı restaurant sınıfı içerisine yerleştirilmiştir. Address için ayrı bir sınıf oluşturup restaurant sınıfı içerisinden çağırmaktayız. Grades bölümünde sınıflar liste biçiminde eklenmektedir. Bu sınıfı oluşturup aynı Address sınıfını eklediğimiz gibi restaurant içerisine eklemekteyiz.

35

4

Öncelikle repository sınıfı oluşturuyoruz. REST mimarisinde bulunan GET, GET by id, POST, PUT ve DELETE gibi işlemler controller içinde tanımlanır. Controller içerisinde olan REST işlemlerinin uygulayacağı işlemler repository sınıfında tanımlanmıştır. Bu tanımlanan işlemler unit of work sınıfı aracılığı ile çağrılacaktır. Aşağıda repository sınıfının tanımlanması ve constructor içerisinde yapılan tanımlamaları gösterilmektedir. Sınıf generic yapıdadır. T ile belirtilen değişkene, repository sınıfı çağrılırken data modelimiz olan Restaurant sınıfını atayacağız. Repository sınıfını UnitOfWork sınıfımız içinde örnekleyeceğiz.

6

Aşağıdaki resimde repository sınıfında tanımlanmış olan metotlar gösterilmiştir. Bu metotlar controller kısmında gerekli işlemleri yapmak için çağrılacaktır.

7

UnitOfWork sınıfı aşağıdaki gibi oluşmaktadır. Constructor içerisinde veritabanına bağlanmak için gerekli işlemler yapılıyor. Oluşturduğumuz repository sınıfı için değişken tanımlanmıştır. Bu değişken repository sınıfını döndürüyor. Eğer örneklenmemiş yani değeri boş ise new ile örnekleniyor. Eğer daha önceden örneklenmesi yapılmış ise mevcut değer tekrar dönüyor. Controller içinden GET metodunu döndürmek istersek; unitofwork.Restaurant.GetAll() yazmamız gerekiyor.

8

Controller sınıfında constructor içerisinde unitofwork örneklenmiştir. Controller sınıfında REST yapısında kullanılan işlemler tanımlanmıştır. Tüm verilerin gösterilmesi için çağrılan GETfonksiyonu ve sadece belirli ObjectId değerine göre sadece tek bir değer çekmemiz için çağrılan diğer GET fonksiyonuda gösterilmiştir.

11

Aşağıda veri eklemek için kullanılan Post metodu gösterilmiştir. Kullanıcı tarafından yollanan Restaurant modeline uygun olan veri unitofwork aracılığı ile repositoryde bulunan add fonksiyonuna gönderilip veritabanına eklenmiştir.

12

Delete metodu, silinmek istenilen verinin id değerini parametre olarak alır. Yapılacak işlem için unit of work sınıfında örneklenmiş repository sınıfında olan metod çağrılmaktadır.

13

Put metodu parametre olarak Restaurant model sınıfı formatında veri alır. Güncelleme yapmak için gerekli metoda yollar.

14

Örnek olarak belirli bir id değerine göre değer çekmeye bakalım. 57601c6da9fba760e3aeed8a ObjectId değerine karşılık gelen restaurant değeri aşağıdaki gibidir. Yapılacak REST işlemlerine göre veriler kullanılmak üzere paylaşılmaktadır.

15

Projenin kaynak kodları

MongoDB – Giriş

Sıkça kullanılan NoSQL veritabanlarından biri olan MongoDB’yi anlatmak için başladığım yazı serisinin, ilk yazısında MongoDB kurulumu ve shell üzerinden yapılan işlemleri göstereceğim.

NoSQL kavramını anlattığım yazı

Kendi sitesinde geniş bir anlatım bulunmaktadır. İncelemek için link

MongoDB ilişkisel olmayan(NoSQL) veritabanıdır. Kısaca özelliklerine bakalım;

  • Verileri JSON document olarak tutmaktadır. MongoDB’de BSON olarak adlandırılmaktadır.
  • Doküman tabanlı bir NoSQL veritabanıdır.
  • Verileri JSON formatında tutarken herhangi bir format zorunluluğu yoktur.(Schemaless)
  • İlişkisel veritabanlarında bulunan join yapısı ve transactionlar kullanılmamaktadır.

{ a:3, b:7 } , { a:3, b:7, c:8 } ( Schemaless özelliği )

MongoDB kurulumu için; İndirme linki – Kurulum , Kurulum 

MongoShell ile işlemler

MongoShell ekranını kullanarak, MongoDB üzerinde işlemleri yaparız. Eğer C#,Java veya başka bir dil ile birlikte kullanmak istersek o diller için hazırlanmış mongodb driver indirilip uygulamaya bağlanmalıdır.

Windows kullanıyorsak cmd kullanarak, ilgili dizinde mongod komutu ile serverı çalıştırıyoruz. Ardından mongo.exe’yi çalıştırmak için mongo komutunu yazarak shell ekranı cmd üzerinde açılmaktadır.

Help komutu ile yapabileceklerimiz gösteriliyor.

1

Shell üzerinde yapacaklarımızı inceleyelim. Aşağıda doc adında bir json document yaratıyoruz ve bu doc değişkenini test veritabanımıza kaydediyoruz. Kayıt işlemi yaptığımız zaman MongoDB otomatik olarak _id değerini eklemektedir. Save ile kayıt yaparsak o id değeri ile kayıtlı değer varsa, değeri güncelleyecektir. Insert kullanırsak sadece kayıt yapacaktır. Eğer aynı id ile kayıt değer varsa hata verecektir. MongoDB ile her oluşturulan id değeri birbirinden bağımsız olup, aynı id ile kayıt işlemini shell üzerinden yaparsak farkı göreceğiz.

Daha sonrasında db.test.find() komutu ile veritabanında olan kayıtları getirecektir. .pretty() kullanarak düzenli gösterilmeyi sağlıyoruz. Eğer rastgele olarak tek bir kayıt getirmek istersek findOne() metodunu kullanırız.

mongo2

Veriyi güncellemek için aşağıda bulunan yapıyı kullanırız. Json documentlar içinde John adlı değer tutan kısımda yaş değerini 30 yapıyoruz. Bu işlemi gerçekte isim değeri yerine, id değeri ile yaparız. Çünkü birden fazla john isimli kullanıcı olabilir.

db.test.update({ “name”: “john” },{ $set :{ “age”:30 } })

Veriyi silmek için ise;

db.test.remove({ “name”:”john” })

MongoDB giriş yazısını burada sonlandırıyorum. Bir sonraki yazımda find ve update komutlarını özelleştiren filtreler ile devam edeceğim.

NoSQL Kavramı

NoSQL(Not only sql, non sql) kavramı,ilişkisel veritabanı yönetim sistemlerinden farklı olan veritabanlar için kullanılır. Google, Facebook ve Amazon gibi büyük şirketlerin ihtiyaçları doğrultusunda kullanımı yaygınlaşmaya başlamıştır.Veri boyutları arttıkça, verilere daha hızlı erişebilmek ve onları daha kolay biçimde tutma ihtiyaçları oluşmuştur.

Sql – NoSQL kıyasları

sql_nosql_2

RDBMSvsNoSQL

Yukarıda belirtildiği gibi NoSQL veritabanlı object oriented tabanlıdır.Esnektir , ölçeklenebilir ve nihai tutarlılığı vardır.Sql veritabanları yapısaldır.

Temel hedeflerinden biri veritabanı tasarımlarının kolaylaşmasıdır. Yapılarına göre 3 tip sınıflandırma yapabiliriz.Doküman tabanlı(document),çizelge(graph) ve Anahtar-değer deposu(key-value) olarak sınıflandırılır.Çeşitli işlemlerin daha hızlı yapılması amaçlanmaktadır.

NoSQL veritabanları büyük veri(big data) ve gerçek zamanlı web uygulamaları(real time web applications) projelerinde sıklıkla kullanılmaya başlanmıştır.

Şimdi NoSQL veritabanlarını inceleyecek olursak;

  • Column: Accumulo, Cassandra, Druid, HBase, Vertica
  • Document(doküman tabanlı): Apache CouchDB, Clusterpoint, Couchbase, DocumentDB, HyperDex, Lotus Notes, MarkLogic, MongoDB, OrientDB, Qizx, RethinkDB
  • Key-value(anahtar-değer): Aerospike, CouchDB, Dynamo, FairCom c-treeACE, FoundationDB, HyperDex, MemcacheDB, MUMPS, Oracle NoSQL Database, OrientDB, Redis, Riak
  • Graph(çizelge): AllegroGraph, InfiniteGraph, MarkLogic, Neo4J, OrientDB, Virtuoso, Stardog
  • Multi-model: Alchemy Database, ArangoDB, CortexDB, FoundationDB, MarkLogic, OrientDB

NoSQL veritabanı türlerinin performans tablosu

nosqlperformance

NoSQL veritabanlarında sql veritabanlarında kullanılan join yapısı bulunmamaktadır.Join yapısı yerine 3 farklı yöntem kullanılabilir.

  • Multiple Queries(çoklu sorgu): İstenilen veriyi tek bir sorguda getirmek yerine çoklu sorgular yaparak getirebiliriz.NoSQL veritabanlarında sorgu yapmak daha hızlıdır.Bu sebeple belli sayıda çoklu sorgu kullanarak istenilen veriyi elde edebiliriz.
  • Caching/Replication: Bu yöntem genellikle okuma işlemlerinin fazla olduğu durumlarda kullanışlıdır.
  • Nesting data(iç içe veri): Genelde doküman tabanlı MongoDB’de çok kullanılan bir yöntemdir.Gerekli olan veriler tek bir dokümanda tutulur.Örneğin blog yazılarını tutan bir doküman içinde,o blog posta ait olan etiketleri ve yorumları tek bir doküman içerisinde tutabiliriz.

Yukarıda söylediğim örneğe yönelik örnek yapı aşağıda gösterilmiştir.Blog post dokümanı içerisinde etiketler ve yorumları aynı yerde tutulmaktadır.Bu yapıya MongoDB yazılarını yazdığım zaman daha detaylı değineceğim.

Günümüzde en çok kullanılan ve en yaygın olan NoSQL veritabanı çözümü document-oriented tabanlı olan MongoDB’dir. MongoDB üzerine daha detaylı makaleler ve örnekler paylaşıyor olacağım.

Daha detaylı bilgileri aşağıdaki sitelerde bulabilirsiniz.

NoSQLMartin fowlermongodb-nosql

Ayrıca Martin Fowler’ın nosql kavramını anlattığı bir konferans