Günlük Hayatta Yapay Zekâ Teknikleri – Yazı Dizisi (1)

Bütün bilimlerin ve buluşların kaynağında, “insandan/doğadan esinlenme” bulunmaktadır. Mekanik (pistonlar v.s.) için insan kaslarına, görüntü ve video (fotoğraf makinesi, TV v.s.) için, göz’e, pompa için kalbe, sonar için kulaklara, filtre için akciğerine, skorsky helikopter için yusufcuk böceğine (helikopter böceği)… bakılabilir.

Şüphesiz, yapay zeka yöntemlerinde de, insan beyninden esinlenilmiştir. Bir sorunu çözmek, bir olayı sınıflandırmak veya bir durumda karar vermek için düşünürken, beynimizde kullanılan (ancak biz farkında değiliz) yöntemler incelenerek, makine öğrenmesi algoritmaları geliştirilmiştir. Bu konuda bazı örnekler verelim.

Yapay Zekâ Kısa Bilgi: Sınıflandırma

Bir nesnenin, kaydın, olayın, durumun, hangi sınıfa ait olduğunu bulmaya (tahminleyip) yarayan yönteme sınıflandırma denilir. Bu konuya; bir elmanın çürük olup olmadığı, bir kişinin hangi siyasi partiye oy verdiğinin tahmini, bir kişinin ev alıp almayacağı (yakın vakitte) gibi örnekler verebiliriz.

Sınıflandırma, yapay zekânın en çok yoğunlaştığı konularından biridir. Öyle ki, yüz tanıma, ses tanıma, nesne tanıma, içerik sınıflandırma, kur tahminleme, hastalık tespiti gibi binlerce konuda, sınıflandırma algoritmaları kullanılır.

SVM:

İlk örneğimiz SVM: Bir iş yerine başvuru yapan onlarca adaydan, işe nasıl kabul olunacağını çözmeye çalışıyorsunuz. Varsayalım ki, başvuru yapan 100 kişiden 15 tanesi işe alındı ve siz adayların birçok bilgisine ulaşabiliyorsunuz (demografik, kariyer, referans, karakter vs.). Böyle bir durumda, işe alınma kriterlerini nasıl anlayabiliriz? Ya da yeni bir aday geldiğinde (mülakata girmeden), işe alınıp alınmayacağını nasıl tahmin edebiliriz? İşte burada devreye, “SVM: Support Vector Machines – Türkçesi Destek Vektörü Makineleri” giriyor.

Problemde bahsedilen ayrımı (hangi aday işe kabul edilir/hangisi edilmez) yapabilmek için, en akla yatkın olan yöntem; özellikleri birbirlerine çok yakın olan ancak biri alınan/biri alınmayan adayların, aynı olmayan özelliklerine bakmaktır. Yani, “kabul edilen bir adayı” ele alalım ve kabul edilmeyen diğer bütün (85 kişi) arasında, bu kişiye özellikler (demografik, kariyer, referans, karakter vs.) bakımından en çok benzer olan (yani birçok özelliği aynı olan) adayı buluyoruz.

Bu iki adayın özelliklerini incelediğimizde, yaş, kariyer, oturdukları konum vs. gibi bilgilerde çok fazla farklılık olmadığını, hemen hemen aynı miktarda (adet) ve seviyede (müdürlerinden) referansları olduklarını görüyoruz. Ancak, karakter testlerine baktığımızda farklılık görüyoruz: Kabul edilen adayın karakter testinde, “uyumlu”, kabul edilmeyen adayda da, “baskın” sonucu yazıyor. Böylece, kabul edilme ile ilgili en önemli kriterlerden birinin karakter testi olduğunu öğreniyoruz. Ancak, bu yaptığımız varsayımı desteklemek için, bu testi, diğer bütün kabul edilenler ve kabul edilenlere en yakın (en benzer) kabul olmayanlar için yapmalıyız.

SVM, yöntem olarak, birbirine en yakın (benzer) ama farklı sınıflara ait (kabul edildi / edilmedi gibi) kayıtlara (nesnelere) yoğunlaşmaktadır. Daha sonra, en yakın olan farklı sınıf kümeleri arasına bir “sınır” çekerek, ayrımı yapmaktadır.

(Tabi ki SVM aslında çok daha karmaşık çalışmaktadır ancak biz bu örnek için, sadece temel mantığını gösterdik. SVM; verinin bulunduğu uzayı daha kolay – lineer sınıflandırılabilecek – bir uzaya çevirip, sınıflandırmayı o uzayda yapmaktadır.)

Picture1
Resimde görüldüğü üzere; birbirine en yakın, ama farklı sınıflara ait olan nesneleri ayırmak için bir tür “boundary – sınır” çiziliyor.

Regresyon temelli sınıflandırma:

İkinci olarak, naive bayes veya regresyonlar ile ilgili sınıflandırıcılara bakalım. Regresyon temelli sınıflandırıcılar da günlük hayatta çok sık kullanılır. Örneğin, yine yol kenarında bekleyen bir trafik kontrol polis ekibini izlediğinizi düşünelim. Polis ekipleri bazı araçları durduruyor, bazılarını da durdurmuyor. Polis telsizinden dinlediğimiz üzere de, herhangi bir ihbar yapılmamış. Yani, plaka veya araç cinsine uygun bir arama yapılmıyor (rutin bir kontrol). Yine, trafik polis ekibinin hangi aracı durdurup durdurmayacağını tahmin etmeye çalışıyorsunuz (günlük hayatta nasıl kullanılır: polis beni, ne yaparsam veya ne yapmazsam durdurur :)).

Belirli bir süre sonra gözlem yaptıktan sonra, bazı bilgiler ediniyorsunuz. Örneğin, polisler; eski araçları daha fazla durduruyor, ancak yeni araçlarda da durdurdukları bulunuyor (örneğin, %75 eski, %25 yeni araçlar). Yine gözlemlerde; araç içerisi kalabalık ise (3-4 kişi) araçların daha az durdurulduğunu not alıyorsunuz, ancak yine kesinlik bulunmuyor. Yani, içerisinde 3-4 kişi olan araçlar hiç durdurulmaz genellemesini çıkaramıyorsunuz. Başka birkaç kriter olarak; “aracın hızı, sürücünün polisle göz göze gelip gelmemesi, aracın tipi (jip/sedan/wagon)” gibi bilgileri not alıyorsunuz. En son olarak bu bilgileri kullanarak, polisin ne gibi durumlarda araçları durdurduğunu bulmaya çalışıyorsunuz. İşte bu gibi durumlarda, her kriter yani toplanan her bilgi, sonuca biraz etki etmektedir. Ancak tek bir kriterle sonuca varmak imkânsızdır. Yani sadece aracın hızına bakarak, veya yeni olup olmamasına bakarak, “polis bu aracı durdurur” diyemeyiz. İşte bu gibi durumlarda, regresyon tabanlı sınıflandırıcılar, her kritere belirli bir puan (katsayı) ataması yapar. Daha sonra, bu katsayılar aracın bilgilerine göre toplanır (Örnek; araç hızlı katsayısı: “4” olsun, eğer araç hızlı ise, sonuca “4” puan eklenir, ancak eğer araç hızlı değilse, bu puan eklenmez, yine aynı şekilde, varsayalım ki, araç içinde çok kişi olmasının katsayısı -5 olsun, eğer araç içinde, 3-4 kişi bulunuyorsa, bu “-5” puanı da hesaba katılır). En sonunda, bu yapılan değerlendirmeyle bir sonuç puan ortaya çıkmaktadır. Eğer bu puan belli bir seviyenin üzerinde ise, “olumlu”, değilse, “olumsuz” olarak sonuçlandırılır.

Picture2

Hive Veritabanları Arası Tablo Taşıma

Merhaba arkadaşlar,

Kısa bir aradan sonra BüyükVeri tarafında yeni bir blog yazımda, sizlere sıkça karşılacaşağımız bir problemin beni uğraştırmasından bahsedeceğim.

Bildiğiniz gibi geliştirme safhasında tablolar yapı olarak sürekli değişime uğrar. Bu sebeple tabloyu yedekleyebilir miyiz şeklinde çok istek alırız. Peki Büyük Veri’de bu nasıl olacak?

BüyükVeri dosya sistemi üzerinde kurulduğu için aslında tabloya ait dosyaları yedeklememiz işimizi çözecektir. Ancak dosya seviyesinde işlem yapmamak ve geliştiricilere bu işi paslamak için HIVE veritabanı üzerinde gerçekleştirebiliriz.

Kullandığım HIVE sürümü 1.1.0 ve tablo yeniden adlandırma komutu aşağıdaki gibi.

Test tablomuzu oluşturalım.

hive> create table rn1 ( id int);
hive> insert into rn1 values ( 100);
hive> insert into rn1 values ( 200);
hive> select * from rn1;
hive> alter table rn1 rename to rn2;

Bu komutu default veritabanı altında yolladığınızda tablonuzun yeniden adlandırıldığını göreceksiniz. Ancak default dışındaki veritabanlarınızda bu işlemi yaptığınızda aşağıdaki gibi bir hata almaktayım:

hive> alter table rn2 rename to YENIDB.rn3;

Ancak aşağıdaki hatayı almaktayım.

Your query has the following error(s):
Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.DDLTask. Unable to alter table. Unable to access old location hdfs://CLUSTER/user/hive/warehouse/rn2 for table default.rn2

Bu hatada tablonun HDFS ‘deki dosyalarına erişemediğini görüyoruz ancak bu mümkün değil, çünkü hive kullanıcısına yetkiler verilmiş durumda ( aksi halde hiç çalıştıramazdık )

HIVE loglarında bu hatayı da aynı şekilde görüyorum. Aslında bug durumu var ve HIVE-10719 numaralı bug’a rastlıyorum.

Aslında HIVE metastore’da yeniden adlandırdığımız tablonun özelliklerini değiştirirken bu hatayı almışız. HIVE 1.2.1 sürümünde bu hatanın fix edildiğini görüyoruz.

Bir diğer yöntem ise HIVE tablosunu export/import ile taşımak. Bu noktada HIVE dökümantasyonunda aşağıdaki bilgileri bulabilirsiniz.

EXPORT TABLE tablename [PARTITION (part_column="value"[, ...])]
  TO 'export_target_path'
  
IMPORT [[EXTERNAL] TABLE new_or_original_tablename [PARTITION (part_column="value"[, ...])]]
  FROM 'source_path' [LOCATION 'import_target_path']

Görebileceğiniz gibi kullanımı kolay şimdi bu komutları deneyelim.

Test tablomuzu oluşturalım:

hive> use YENIDB;
hive> create table rn4 (id int);
hive> insert into rn4 values (790);
hive> insert into rn4 values (1);
hive> insert into rn4 values (60);
hive> select * from rn4;

Tabloya fiziksel olarak bakarsak,

HOST]~$hadoop fs -ls  /YENI_DB_DIZINI/YENIDB/
Found 7 items
...
drwxrwx---+  - hive   supergroup          0 2016-01-29 16:20 /YENI_DB_DIZINI/YENIDB/rn4
...

[HOST]~$hadoop fs -ls  /YENI_DB_DIZINI/YENIDB/rn4
Found 3 items
-rwxrwx---+  3 hive supergroup          4 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn4/000000_0
-rwxrwx---+  3 hive supergroup          2 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn4/000000_0_copy_1
-rwxrwx---+  3 hive supergroup          3 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn4/000000_0_copy_2

Şimdi tablomuzu export edelim.

hive> export table rn4 to '/tmp/rn4';

Gördüğümüz gibi tablomuzun metadatası (tanım bilgileri) ve verileri dosyaya çıkmış durumda.

[HOST]~$hadoop fs -ls /tmp/rn4
Found 5 items
drwxrwxrwx   - hive supergroup          0 2016-01-29 16:22 /tmp/rn4/.hive-staging_hive_2016-01-29_16-22-55_385_6263938611577166589-35
drwxrwxrwx   - hive supergroup          0 2016-01-29 16:23 /tmp/rn4/.hive-staging_hive_2016-01-29_16-23-41_894_2004760451112761053-35
drwxrwxrwx   - hive supergroup          0 2016-01-29 16:24 /tmp/rn4/.hive-staging_hive_2016-01-29_16-24-51_981_2863671248049702467-35
-rwxrwxrwx   3 hive supergroup       1165 2016-01-29 16:22 /tmp/rn4/_metadata
drwxrwxrwx   - hive supergroup          0 2016-01-29 16:22 /tmp/rn4/data

_metadata dosyasına bakarsak, tablo tanım bilgilerinin olduğunu görürüz.

[HOST]~$hadoop fs -cat /tmp/rn4/_metadata
{"version":"0.1","table":"{\"1\":{\"str\":\"rn4\"},\"2\":{\"str\":\"YENIDB\"},\"3\":{\"str\":\"hive\"},\"4\":{\"i32\":1454077197},\"5\":{\"i32\":0},\"6\":{\"i32\":0},\"7\":{\"rec\":{\"1\":{\"lst\":[\"rec\",1,{\"1\":{\"str\":\"id\"},\"2\":{\"str\":\"int\"}}]},\"2\":{\"str\":\"hdfs://CLUSTER/YENI_DB_DIZINI/YENIDB/rn4\"},\"3\":{\"str\":\"org.apache.hadoop.mapred.TextInputFormat\"},\"4\":{\"str\":\"org.apache.hadoop.hive.ql.io.HiveIgnoreKeyTextOutputFormat\"},\"5\":{\"tf\":0},\"6\":{\"i32\":-1},\"7\":{\"rec\":{\"2\":{\"str\":\"org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe\"},\"3\":{\"map\":[\"str\",\"str\",1,{\"serialization.format\":\"1\"}]}}},\"8\":{\"lst\":[\"str\",0]},\"9\":{\"lst\":[\"rec\",0]},\"10\":{\"map\":[\"str\",\"str\",0,{}]},\"11\":{\"rec\":{\"1\":{\"lst\":[\"str\",0]},\"2\":{\"lst\":[\"lst\",0]},\"3\":{\"map\":[\"lst\",\"str\",0,{}]}}},\"12\":{\"tf\":0}}},\"8\":{\"lst\":[\"rec\",0]},\"9\":{\"map\":[\"str\",\"str\",6,{\"totalSize\":\"9\",\"numRows\":\"3\",\"rawDataSize\":\"6\",\"COLUMN_STATS_ACCURATE\":\"true\",\"numFiles\":\"3\",\"transient_lastDdlTime\":\"1454077242\"}]},\"12\":{\"str\":\"MANAGED_TABLE\"}}","partitions":[]}[HOST]~$

Tabloyu taşıma adımı:

hive> import table rn42 from '/tmp/rn4';

import komutunu çalıştırtıktan sonra tablomuzun taşındığını görebiliriz.

[HOST]~$hadoop fs -ls  /YENI_DB_DIZINI/YENIDB/
Found 7 items
...
drwxrwx---+  - hive   supergroup          0 2016-01-29 16:20 /YENI_DB_DIZINI/YENIDB/rn4
drwxrwx---+  - hive   supergroup          0 2016-01-29 16:22 /YENI_DB_DIZINI/YENIDB/rn42

Şimdi farklı veritabanları arası taşımayı deneyelim, zaten bir önceki adımda burada tıkanmıştı.

hive> import table BASKADB.rn43 from '/tmp/rn4';

INFO  : Copying file: hdfs://CLUSTER/tmp/rn4/data/000000_0_copy_1
INFO  : Copying file: hdfs://CLUSTER/tmp/rn4/data/000000_0_copy_2
INFO  : Loading data to table YENIDB.BASKADB.rn43 from hdfs://CLUSTER/tmp/rn4/.hive-staging_hive_2016-01-29_16-23-41_894_2004760451112761053-35/-ext-10000
ERROR : Failed with exception Invalid table name YENIDB.BASKADB.rn43
org.apache.hadoop.hive.ql.parse.SemanticException: Invalid table name YENIDB.BASKADB.rn43
 at org.apache.hadoop.hive.ql.exec.Utilities.getDbTableName(Utilities.java:2321)
 at org.apache.hadoop.hive.ql.exec.Utilities.getDbTableName(Utilities.java:2307)
 at org.apache.hadoop.hive.ql.metadata.Hive.getTable(Hive.java:1031)
 at org.apache.hadoop.hive.ql.metadata.Hive.getTable(Hive.java:1019)
 at org.apache.hadoop.hive.ql.exec.MoveTask.execute(MoveTask.java:259)
 at org.apache.hadoop.hive.ql.exec.Task.executeTask(Task.java:160)
 at org.apache.hadoop.hive.ql.exec.TaskRunner.runSequential(TaskRunner.java:88)
 at org.apache.hadoop.hive.ql.Driver.launchTask(Driver.java:1638)
 at org.apache.hadoop.hive.ql.Driver.execute(Driver.java:1397)
 at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java:1181)
 at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1047)
 at org.apache.hadoop.hive.ql.Driver.run(Driver.java:1042)
 at org.apache.hive.service.cli.operation.SQLOperation.runQuery(SQLOperation.java:145)
 at org.apache.hive.service.cli.operation.SQLOperation.access$100(SQLOperation.java:70)
 at org.apache.hive.service.cli.operation.SQLOperation$1$1.run(SQLOperation.java:197)
 at java.security.AccessController.doPrivileged(Native Method)
 at javax.security.auth.Subject.doAs(Subject.java:422)
 at org.apache.hadoop.security.UserGroupInformation.doAs(UserGroupInformation.java:1671)
 at org.apache.hive.service.cli.operation.SQLOperation$1.run(SQLOperation.java:209)
 at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
 at java.util.concurrent.FutureTask.run(FutureTask.java:266)
 at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
 at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
 at java.lang.Thread.run(Thread.java:745)

Gördüğünüz gibi buradaki hata basit , HIVE import edilen tablonun başına bağlı olduğumuz veritabanının adını ekliyor.

Çözüm olarak tabloyu aktaracağımız veritabanına bağlanıp, import komutunu çalıştırmamız gerekiyor.

hive> use BASKADB;
hive> import table rn43 from '/tmp/rn4';

Evet arkadaşlar, import çalıştı, yeni tabloyu fiziksel olarak test edip verilerimizin var olduğunu doğrulayalım.

[HOST]~$hadoop fs -ls  /PATH_TO_BASKADB/BASKADB/rn43
Found 3 items
-rwxrwx---+  3 hive supergroup          4 2016-01-29 16:24 /PATH_TO_BASKADB/BASKADB/rn43/000000_0
-rwxrwx---+  3 hive supergroup          2 2016-01-29 16:24 /PATH_TO_BASKADB/BASKADB/rn43000000_0_copy_1
-rwxrwx---+  3 hive supergroup          3 2016-01-29 16:24 /PATH_TO_BASKADB/BASKADB/rn43/000000_0_copy_2

Sorun gözükmüyor. Bu çalışma ile aslında sık yaptığımız tablo yedekleme/yeniden adlandırma işlerinde aldığımız hataları çözdük arkadaşlar.

Export/import yöntemi dosya seviyesinde kopyalama yaptığı için çok hızlı, aslında hive rename komutu da aynı işi yapmakta ancak 1.1.0 sürümünde hata alınmakta. Bir diğer tablo taşıma yöntemi de CTAS yöntemi, yani yeni tabloyu oluşturup insert komutu ile veriyi taşımak.

Metadata export/import yöntemi ile taşıyacağınız tablonun yapısı ile ilgili bilgi sahibi olmanıza gerek olmadığı için tavsiye ettiğim bir çözüm.

Evet arkadaşlar, yazımız burda sonlanıyor. Umarım faydalı bir çalışma olmuştur.

İyi çalışmalar.

Kaynak:

https://cwiki.apache.org/confluence/display/Hive/LanguageManual+ImportExport
https://issues.apache.org/jira/browse/HIVE-10719
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+DDL#LanguageManualDDL-RenameTable

Basit Lineer Regresyon

Basit lineer regresyon, 2 nicel veri arasındaki ilişkiyi özetleyen istatiksel bir metoddur. X ekseninde gösterilen 1.değişken tahmin edici, bağımsız değişkendir. Y ekseninde gösterilen 2.değişken ise tahmin edilen çıktı ise bağımlı değişkendir.

Basit lineer regresyon ile bulunan bu ilişki, istatistiksel bir ilişkidir. Bu bağlamda istatistiksel ve deterministik ilişkiden bahsedelim.

Deterministik ilişki, 2 değişken arasındaki ilişkiyi kesin olarak tanımlayan bi denklem mevcuttur. Örneğin;

Picture1Fahrenheit ve Celcius arasındaki ilişkisi kesin olarak gösteren bir denklem vardır ve grafikte görüldüğü gibi her Celcius’a karşılık gelen değer kesin denklem sonucu çıkan kesin değerdir.

Fahr = 95Cels+32

İstatistiksel ilişki ise değişkenler arasındaki kesin olmayan ilişkiyi tanımlar. Örneğin, boy uzadıkça doğru orantılı olarak kilonun da artması beklenir ama bu her zaman doğru değildir. Çünkü bu sonucu etkileyen birden fazla durum vardır biz sadece 1 tane durumu alarak sonuç üretmeye çalışıyoruz. Bütün durumlarla çalışmasında bile kesin sonuç üretilmez.

Regresyon konusu boyunca ev fiyat tahminlemesi örneği üzerinden ilerleyeceğiz. Elimizde evlere ait evin fiyatı, alanı, banyo sayısı, bahçe alanı vs gibi özellikler mevcut, bu özelliklere veri setimize dahil olan evin fiyat tahminlemesini yapacağız. Konumuz Basit Lineer Regresyon olduğu için 2 değişkenimiz olacak, evin fiyatı ($) ve alanı(sq.ft). Evin alanı (bağımsız değişken) x ekseninde, evin fiyatı (bağımlı değişken) y ekseninde yer alacaktır.

Veri setimizde ki evler, evi = (xi,yi)  olarak tanımlanır. Regresyonla oluşan model, evin tahminlenen fiyatına (f(x) fonkisyonu) gerçek fiyattan tahminlenen fiyatın çıkarılması ile bulunan değerin (hata) eklenmesi ile bulunan;

Regresyon model:

yi = f(xi) +  εi

Hatanın 0 olması istenilen durumdur, hatanın pozitif yada negatif olması verinin eğrinin üstünde yada altnda kalmasına göre değişir.

Screen Shot 2016-02-11 at 09.25.39

Veri üzerinde Regresyon nasıl çalışır?

Örneğimizde yola çıkarak şema üzerinden ilerleyelim. Eğitim verisi, yazının başında bahsettiğim gibi evlere ait belirli değerlerdir. Özellik çıkarımında modelde oluştururken kullanacağımız x ,evin alanı. Regresyonla oluşan Model’in (f) sonucu tahmin edilen fiyat y kalite metriği olan evin gerçek fiyatı y ile karşılaştırılarak hata (error) bulunur. Hataya göre model güncellenir.

Screen Shot 2016-02-11 at 09.27.50

Basit regresyon sonucunda oluşan lineer doğru  f(x) = w0 + w1 x , oluşan model ise yi = w0 + w1 xi + εi  dir. w0 ve w1  regresyon katsayıları olan intercept ve slope dur. Veriye uygun olan model nasıl bulunur, yada modelin uygun olma kriteri nedir ? Bunun için uygun doğrunun bulunması gereklidir.

Uygun doğru nedir?

Uygun doğru, veri en yakın şekilde tahminleyen dolayısıyla hatanın az olduğu doğrudur. Bu kavramı öğrencilere ait boy ve kilo bilgilerinden oluşturulmuş örnek üzerinde irdeleyelim.

Picture2

Örnekte 10 tane öğrenciye ait olan veriye 2 tane doğru uydurulmuştur, beraberce hangi doğrunun daha uygun olduğunu bulalım.

Doğru için kullandığımız denklem yi = w0 + w1 xi + εi  idi. Şimdi doğru denklemlerinde öğrenciye ait boy bilgisini h yerine koyup, kilo yani tahminlenen w bilgisini elde edeceğiz. Elimizde bu öğrencilere ait gerçek kilo bilgileride yer aldığı için işlemleri yapıp 2 doğrudan hangisinde daha az hata varsa o doğruyu seçeceğiz. 1.öğrencinin boyu 63 inch, kilosu ise 127 pounds, doğruda bilgileri yerine koyduğumuzda;

w = -266.53 + 6.1376h
= -266.53 + 6.1376(63)
= 120.1 pounds

εi = 127- 120.1
= 6.9 pounds

Her bir doğru için her öğrenci bilgileri ile hata bulunur, hataların karesi alınarak toplanır. 1.doğrunun hata karelerinin toplamı ve 2. doğrunun hata karelerinin toplamı bulunur. İşlem sonucunda ;

w = -331.2 + 7.1 h                     ε1 = 766.5
w = -266.53 + 6.1376 h            ε2 = 597.4

Hesaplamalara göre 2.doğrunun hatası daha küçük olduğu için uygun olan doğru 2.doğrudur. Hataların neden direkt toplanması yerine karelerinin alındığını düşünüyor olabilirsiniz. Bunun nedeni negatif ve pozitif hata oranlarının toplanırken birbirlerini götürmesini engellemektir.

Yukarıda her bir doğru için yaptığımız hata hesabı RSS olarak tanımlanır,

Screen Shot 2016-02-11 at 09.32.23Intercept (doğrunun y ekseninde kestiği nokta) ve slope (eğim) üzerinden yazarsak aynı denklemi,

Screen Shot 2016-02-11 at 09.32.56Sonuç olarak uygun doğru bulunurken doğrulara ait RSS değeri bulunur ve minimum RSS’e ait doğru, en iyi doğrudur.

Model’in ve Doğru’nun incelenmesi

Model, bilinmeyen parametrelerden oluşturulan genel bir denklem iken, doğru ise tahmin edilen intercept ve slope ile yazılan spesifik bir denklemdir.

Screen Shot 2016-02-11 at 09.35.41w0 > 0 ise yani slope (eğim) pozitif ise grafik te pozitiftir,  x arttığında y nin de artacağı manasına gelir.

w0 < 0 ise yani slope (eğim) negatif ise grafikte negatiftir, x arttığında y nin de azalacağı manasına gelir.

Öğrencilerin boy ve kilo bilgilerinden oluşturulan doğruda xi = 0 ise

yi = -266.53 + 6.1376 xi

yi = -266.53

Bu değer boyu 0 inç olan bir öğrencinin kilosunun -266.53 çıktığı anlamına gelir ve manasız bir sonuç olur. Bunun nedeni x’in aralığıdır. (the scope of the model). Ayrıca xi = 0 modelinde iyi bir model olmadığını söyler bize, verinin gürültülü bir veri olduğu sonucuna bizi ulaştırır.

Intercept w^1 ise x ekseninde 1 birimlik değişimin y ekseninde ki karşılığı manasına gelir. Örneğin 66 inç ve 67 inç lik 2 kişinin kiloları tahmin edildiğinde 144.38 – 138.24 = 6.14 pounds bulunur, bu da 1 inç in 6.14 pounds değişimi ifade ettiğini anlatır. Fakat bu model oluşturulurken kullanılan birimler ile tahmin değerleri aynı ise bu yaklaşım doğrudur.

Least Square Optimizasyonu

Veriye en uygun doğruyu bulmak için w0 ve w1 değerlerinin minimum tahmin ederek dolayısıyla RSS i de minimum sağlamış oluruz. Pekala w0 ve w1 değerlerinin minimum değerlerini nasıl buluruz?

Screen Shot 2016-02-11 at 09.39.44

Öncelikle genel olarak fonksiyonlarda minimum ve maksimum nokta nasıl bulunur bakalım. Eğer fonksiyon iç bükey (concave) ise maksimum nokta bulmak için fonksiyonun türevi 0 eşitlenirken, dış bükey (conxex) ise minimum nokta bulmak için fonksiyonun türevi 0 eşitlenir.

Screen Shot 2016-02-11 at 09.40.27

Hill climbing: İç bükey fonksiyonlarda maksimum noktayı bulmak için kullanılan iterative bir algoritmadır. Eğrinin herhangi bir yerinden başlayarak ilerlediğimiz noktayı sağa yada sola doğru kaydırır. Sağa yada sola doğru kayacağımızı fonksiyonun türevinden anlarız. Eğer türev pozitif ise sağa doğru w yi artırarak ilerleriz, negatif ise sola doğru w yi azaltrak ilerleriz. Her attığımız adımla fonksiyonun türevi küçülmeye başlar bu da optimum noktaya yaklaştığımız anlamına gelir. Türev yeteri kadar küçüldüğünde max noktaya ulaşırız ve w u artırmayı bırakırız.

Screen Shot 2016-02-11 at 09.41.34t iterasyonundaki değerler kullanılarak n adım boyu ile t+1 deki değer bulunur.

Hill descent : dış bükey fonksiyonlarda minimum nokta noktayı bulmak için kullanılan iterative bir algoritmadır. Hill climbing algoritması gibi, eğrinin bir yerinden başlayarak sağa yada sola doğru ilerlenir. Sağa yada sola doğru ilerleyeceğimizi fonksiyonun türevi üzerinden anlarız. Türev negatif ise sağa ilerleyip w yi artırıyoruz, pozitif ise sola doğru w yi azaltarak ilerliyoruz.

Screen Shot 2016-02-11 at 09.42.40

Adım boyu seçimi önemli bir konudur 2 algoritma içinde.

  • Sabit adım boyu ile ilerlendiğinde minimum yada maksimum noktaya ulaşmak zaman alabilir.
  • Adım boyunun azaltıralarak ilerlenilmesi ise daha çok tercih edilen bir yöntemdir.

Screen Shot 2016-02-11 at 09.43.24

Adım boyumuz da belli fakat türevin 0 a eşit olduğu optimum noktayı bulamadık, ne zaman durmalıyız. Bunun için bir eşik değeri () belirlenir. Fonksiyonun türevi eşik değerinden küçük olduğunda ilerlemeyi durduruz ve o noktayı optimum nokta olarak kabul ederiz.

Screen Shot 2016-02-11 at 09.43.54

Gradients hesaplanması

Basit lineer regresyonda çalıştığımız fonksiyonlar 2 bilinmeyenli denklemlerdi (w0 ve w1). Çoklu değişkenler yüksek boyutta olduğundan türev yerine gradient hesaplaması yapılır. Gradient, her bir değişkenin kısmı türevinin yer aldığı vectordür. İterative olarak ilerlenilerek optimum nokta bulunur ve nokta bulunurken durulması gereken iterasyon yine bir eşik değeri ile sınırlayarak belirlenir.

Screen Shot 2016-02-11 at 09.44.36p tane değişkenli bir fonksiyondan p+1 lik bir vectör oluşur. Vectörün her bir elemanı değişkenlerin kısmı türevidir. Sonuç olarak w0 ve w1 değişkenli fonksiyonun gradient’i bulunur.

Screen Shot 2016-02-11 at 09.45.41

Gradient descent  ise optimum noktayı bulmak için her adımda azalar ilerlemektir. Yine duracağımız nokta eşik değeri ile belirlenir.

Screen Shot 2016-02-11 at 09.45.46

Least Square Doğrunun Bulunması

Veriye çizilen bir çok eğriden en uygun olanını seçmek için minimum RSS bulacağız,  bunun için RSS ‘in gradientini hesaplamamız gerekmektedir. Örnekte convex bir fonksiyon üzerinden işlemler gerçekleştirilmektedir. Bulacağımız minimum değeri eşsiz (unique) tir ve gradient descent algortiması bu değere yakınsar.

Screen Shot 2016-02-11 at 09.48.41Screen Shot 2016-02-11 at 09.48.45

Screen Shot 2016-02-11 at 09.47.10Screen Shot 2016-02-11 at 09.47.14
Screen Shot 2016-02-11 at 09.47.18

Closed Form Çözümü

Bulunan Gradient’in 0 a eşitlenerek çözülmesi.

Screen Shot 2016-02-11 at 09.49.56Screen Shot 2016-02-11 at 09.50.00

Gradient Descent Çözümü

Tek değişkenli denklemlerde ki hill descent algoritmasının çoklu değişkenli versiyonudur. Yandaki şekil gradient kuş bakışı görünümüdür ve her bir halka aynı fonkiyona aittir. Bir önceki adımdaki değerleri kullanarak bir sonraki değer elde edilir. RSS ‘in gradient hesabında tahmin yerine

Screen Shot 2016-02-11 at 09.51.08

2 Yöntemin Karşılaştırılması

Çoğunlukla tercih edilen yöntem Gradient Descent’tir fakat adım boyu, eşik değeri gibi durumları belirlemek zordur. Closed form da bu tarz belirlemeler olmadığı için daha kolaydır ama değişkenler arttıkça Gradient Descent’ti kullanmak daha verimli olur.

Örnekler:

Kaynaklar:

 

Apache Sentry ile Yetkilendirme

Merhaba arkadaşlar,

Bu yazıda Büyük Veri Güvenlik çözümlerinden Apache Sentry’den bahsetmek istiyorum. Apache Sentry kullanarak hadoop ekosisteminde rol bazlı yetkilendirme ile pekçok Büyük Veri aracı arasında güvenli iletişim sağlanabilir. Şimdi Sentry’nin hive, impala ve hdfs arasındaki çalışma şekillerine bakalım.
Yazını devamında Sentry metadatasına inceleyip, hive üzerinde yetkilendirme uyarlamaları yapıyor olacağız.

1

Hive aracı ile SQL komutları benzeri erişim yapıldığında HDFS’e gittiğimizde Sentry aracı güvenlik denetimlerini yapmakta ve izni olmayan sorguları engellemektedir. Resimde bu aşamayı görebilirsiniz.

2

Impala erişimlerinde ise Impala catalog processi yetkileri hafızasına aldığı için sorgu anında sentry metadatasını sorgulamak yerine,  kendi üzerinde yetki kontrolünü hızlıca yapabilmektedir.

3

HDFS yetkilendirmesinde Sentry’yi tecrübe etmedim ancak bildiğimiz diğer bir çözüm olan ACL ile yetkilendirme metodunun yerini alabilecek kapasitede değil. Hive tablolarının olduğu dosya ve dizinlere erişimde Sentry devreye girer ve erişim kontrolünü yapar.

4

Sentry Veritabanı Modeli:

Sentry veritabanında tablo yapıları incelediğimizde basit bir mimari görmekteyiz.

mysql> use sentry;
Database changed
mysql> show tables;
+------------------------------+
| Tables_in_sentry             |
+------------------------------+
| SENTRY_DB_PRIVILEGE          |
| SENTRY_GROUP                 |
| SENTRY_ROLE                  |
| SENTRY_ROLE_DB_PRIVILEGE_MAP |
| SENTRY_ROLE_GROUP_MAP        |
| SENTRY_VERSION               |
| SEQUENCE_TABLE               |
+------------------------------+

Bu tablolarda önemli olanları özetlersek:

SENTRY_ROLE                  -> Tanımlı roller 
SENTRY_GROUP                 -> Yetkilendirilen işletim sistemi grupları 
SENTRY_ROLE_GROUP_MAP        -> Rol x Grup bilgisi
SENTRY_DB_PRIVELEGE          -> Yetkiler
SENTRY_ROLE_DB_PRIVILEGE_MAP -> Rol x Yetki

Sentry rol bazlı bir yetkilendirme aracı olduğu için kullanıcı bazında yetkilendirme yapılamamakta ve rolleri işletim sistemi bazında gruplarla eşleştirerek, kullanıcılar yetkilendirilmiş olur.
Örnek olarak yetkiler tablosuna baktığımızda:

mysql> SELECT * FROM SENTRY_DB_PRIVILEGE  ;
+-----------------+-----------------+-------------+----------+---------------------+-------------------------------------------------------------------------------+--------+---------------+-------------------+
| DB_PRIVILEGE_ID | PRIVILEGE_SCOPE | SERVER_NAME | DB_NAME  | TABLE_NAME          | URI                                                                           | ACTION | CREATE_TIME   | WITH_GRANT_OPTION |
+-----------------+-----------------+-------------+----------+---------------------+-------------------------------------------------------------------------------+--------+---------------+-------------------+
|               1 | SERVER          | server1     | __NULL__ | __NULL__            | __NULL__                                                                      | *      | 1435230391611 | N                 |
|               6 | URI             | server1     | __NULL__ | __NULL__            | file:///opt/cloudera/parcels/CDH/lib/hive/lib/hive-contrib-1.1.0-cdh5.4.0.jar | *      | 1435758914457 | N                 |
|               7 | URI             | server1     | __NULL__ | __NULL__            | hdfs:///opt/cloudera/parcels/CDH/lib/hive/lib/hive-contrib-1.1.0-cdh5.4.0.jar | *      | 1435759061151 | N                 |
|              11 | TABLE           | server1     | default  | default             | __NULL__                                                                      | select | 1439543565668 | N                 |
|              12 | TABLE           | server1     | default  | defaul              | __NULL__                                                                      | select | 1439543578705 | N                 |
|              14 | DATABASE        | server1     | default  | __NULL__            | __NULL__                                                                      | select | 1439546951486 | N                 |
|              15 | TABLE           | server1     | default  | default             | __NULL__                                                                      | select | 1439547062374 | Y                 |
|              
+-----------------+-----------------+-------------+----------+---------------------+-------------------------------------------------------------------------------+--------+---------------+-------------------+

Gördüğümüz gibi Sentry ile bir jar dosyasına veya tablo / veritabanı için yetkilendirme yapabilmekteyiz.

Tüm gruplara verilen yetkileri raporlamak için aşağıdaki sorguyu kullanabilirsiniz.

mysql > SELECT rolelist.role_name as "ROLE NAME",
               grouplist.group_name AS "GROUP NAME",
               priv.action"ACTION",
               priv.privilege_scope "PRIV SCOPE",
               priv.db_name "DB_NAME",
               priv.table_name "TABLE_NAME",
               priv.uri "URI"
        FROM SENTRY_DB_PRIVILEGE  priv, 
             SENTRY_ROLE_DB_PRIVILEGE_MAP role_priv_map, 
             SENTRY_ROLE_GROUP_MAP role_group_map,
             SENTRY_ROLE  rolelist,SENTRY_GROUP grouplist
        WHERE role_group_map.role_id=rolelist.role_id
              and role_group_map.group_id=grouplist.group_id
              and role_priv_map.role_id=role_group_map.role_id
              and role_priv_map.db_privilege_id=priv.db_privilege_id
              order by 1 ,2 


+------------------------+-------------------------------------+--------+------------+----------+------------+-------------------------------------------------------------------------------+
| ROLE NAME              | GROUP NAME                          | ACTION | PRIV SCOPE | DB_NAME  | TABLE_NAME | URI                                                                           |
+------------------------+-------------------------------------+--------+------------+----------+------------+-------------------------------------------------------------------------------+
| admin_role             | grup1                      | *      | URI        | __NULL__ | __NULL__   | file:///opt/oracle/bigdatasql/bdcell-12.1/jlib/json-serde-1.3.1.jar           |
| admin_role             | grup2                | *      | URI        | __NULL__ | __NULL__   | file:///opt/oracle/bigdatasql/bdcell-12.1/jlib/json-serde-1.3.1.jar           |
...
| role 2              | oracle                              | *      | URI        | __NULL__ | __NULL__   | hdfs:///opt/cloudera/parcels/CDH/lib/hive/lib/hive-contrib-1.1.0-cdh5.4.0.jar |
| role 3     | grup3                      | *      | DATABASE   | db1   | __NULL__   | __NULL__                                                                      |
+------------------------+-------------------------------------+--------+------------+----------+------------+-------------------------------------------------------------------------------+

Şimdi Hive üzerinde Sentry komutlarına bakarsak:

hive> show roles;
+-----------------------------+--+
|            role             |
+-----------------------------+--+
| role1         |
| role2         |
...
...
| admin_role                  |
| deneme                      |
...
+-----------------------------+--+

Bir roldeki yetkilerin listelenmesi:

hive> show grant role admin_role;
+----------------------------------------------------------------------+--------+------------+---------+-----------------+-----------------+------------+---------------+-------------------+----------+--+
|                               database                               | table  | partition  | column  | principal_name  | principal_type  | privilege  | grant_option  |    grant_time     | grantor  |
+----------------------------------------------------------------------+--------+------------+---------+-----------------+-----------------+------------+---------------+-------------------+----------+--+
| *                                                                    |        |            |         | admin_role      | ROLE            | *          | false         | 1435230391611000  | --       |
| hdfs:///app/hive_serde/json-serde-1.3.1.jar                          |        |            |         | admin_role      | ROLE            | *          | false         | 1440163479303000  | --       |
| file:///tmp/hive-json-serde/json-serde-aws.jar                       |        |            |         | admin_role      | ROLE            | *          | false         | 1440061254959000  | --       |
| file:///tmp/hive-json-serde/json-serde-1.3.1.jar                     |        |            |         | admin_role      | ROLE            | *          | false         | 1440061245472000  | --       |
| file:///opt/oracle/bigdatasql/bdcell-12.1/jlib/json-serde-1.3.1.jar  |        |            |         | admin_role      | ROLE            | *          | false         | 1440163459313000  | --       |
| hdfs:///tmp/hive-json-serde/json-serde-1.3.1.jar                     |        |            |         | admin_role      | ROLE            | *          | false         | 1440061264598000  | --       |
| hdfs:///tmp/hive-json-serde/json-serde-aws.jar                       |        |            |         | admin_role      | ROLE            | *          | false         | 1440061271254000  | --       |
| file:///opt/oracle/bigdatasql/bdcell-12.1/jlib/json-serde-aws.jar    |        |            |         | admin_role      | ROLE            | *          | false         | 1440163475556000  | --       |
| hdfs:///app/hive_serde/json-serde-aws.jar                            |        |            |         | admin_role      | ROLE            | *          | false         | 1440163482669000  | --       |
+----------------------------------------------------------------------+--------+------------+---------+-----------------+-----------------+------------+---------------+-------------------+----------+--+

Bir işletim sistemi grubuna verilen yetkilerin listelenmesi:

hive> SHOW ROLE GRANT GROUP `OSgroup1`;
+------------------------+---------------+-------------+----------+--+
|          role          | grant_option  | grant_time  | grantor  |
+------------------------+---------------+-------------+----------+--+
| admin_role             | false         | NULL        | --       |
| role 1                 | false         | NULL        | --       |
+------------------------+---------------+-------------+----------+--+

Örnek bir Sentry yetkilenmesini şu şekilde yapabilirsiniz:

Tanımlı bir veritabanı üzerindeki yetkileri bir gruba devretmek:

hive> create role roleX;
No rows affected (0.072 seconds)
hive > Grant all on database dbX to role roleX;
No rows affected (0.062 seconds)
hive>Grant role roleX to group `OSgroupX`;
No rows affected (0.024 seconds)

Dikkat etmeniz gereken bir nokta, Sentry tanımlamalarını yapan kullanıcının Sentry konfigürasyonlarında yetkili işletim sistemi gruplarına dahil olması gerekiyor. Yoksa aşağıdaki hatayı alabilirsiniz.

hive> SHOW ROLES;
ERROR : Error processing Sentry command: Access denied to erkanul. Server Stacktrace: org.apache.sentry.provider.db.SentryAccessDeniedException: Access denied to erkanul
        at org.apache.sentry.provider.db.service.thrift.SentryPolicyStoreProcessor.list_sentry_roles_by_group(SentryPolicyStoreProcessor.java:450)
        at org.apache.sentry.provider.db.service.thrift.SentryPolicyService$Processor$list_sentry_roles_by_group.getResult(SentryPolicyService.java:953)
        at org.apache.sentry.provider.db.service.thrift.SentryPolicyService$Processor$list_sentry_roles_by_group.getResult(SentryPolicyService.java:938)
        at sentry.org.apache.thrift.ProcessFunction.process(ProcessFunction.java:39)
        at sentry.org.apache.thrift.TBaseProcessor.process(TBaseProcessor.java:39)
        at org.apache.sentry.provider.db.service.thrift.SentryProcessorWrapper.process(SentryProcessorWrapper.java:48)
        at sentry.org.apache.thrift.TMultiplexedProcessor.process(TMultiplexedProcessor.java:123)
        at sentry.org.apache.thrift.server.TThreadPoolServer$WorkerProcess.run(TThreadPoolServer.java:285)
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
        at java.lang.Thread.run(Thread.java:745)

Error: Error while processing statement: FAILED: Execution Error, return code 1 from org.apache.hadoop.hive.ql.exec.SentryGrantRevokeTask. SentryAccessDeniedException: Access denied to erkanul (state=08S01,code=1)

Evet arkadaşlar , yazımız burda sonlanıyor. Apache Sentry ile Büyük Veri dünyasında güvenlik tarafında önemli bir noktayı tamamlayabilirsiniz. Umarım faydalı bir çalışma olmuştur.
İyi çalışmalar.

Kaynak:
https://cwiki.apache.org/confluence/display/SENTRY/Sentry+Tutorial

Hive İç İçe Sorgu Kullanımı

Merhaba arkadaşlar,

Bildiğiniz gibi HIVE aracı ile SQL kurallarına benzer bir dil ile sorgulamalar yapabiliyoruz. Ancak bu noktada ticari veritabanlarının sağlamış olduğu kadar fonksiyonel geliştirme yapamadığımız bir durumda söz konusu.

Öncelikle, HIVE’ın veritabanı veya geliştirici kişiler için SQL kolaylığında sorgulama imkanı sağlamasına rağmen, Hadoop ekosisteminin büyük dosya yapıları üzerinde analiz yapma mantığı etrafında geliştiğini unutmamamız gerekiyor.

İşte, bu noktada bazı limitler ile karşılaşıyoruz, çünkü açık kaynak bir dağıtım olan HIVE, sorgularımızı file işlemleri seviyesine getirirken yaptığı dönüşümlerde, sorgu mantığını anlama işleminde, ticari veritabanları kadar etkin bir işleyişe sahip değil.

Bu yazımda bu konuya örneklemek için içiçe sorgular içeren bir işlemde aldığım hatadan ve yaptığım çalışmadan bahsedeceğim.

Aşağıdaki gibi klasik veritabanlarımızda çalışabilecek bir sorgumuzu ele alalım:

SELECT T1.SESSION_ID, T1.KEY, T1.VALUE
  FROM SCHEMA1.T1
 WHERE     session_id IN
              (SELECT SESSION_ID
                 FROM SCHEMA1.T4
                WHERE session_id IN
                         (SELECT t3.SESSION_ID
                            FROM SCHEMA1.T2 t2,
                                 SCHEMA1.T3 t3
                           WHERE     t2.VALUE IN (.........)
                                 AND t3.VALUE = '..............'
                                 AND t2.SESSION_ID = t3.SESSION_ID))
 AND T1.VALUE BETWEEN '2015-May-01 00:00:00' AND '2015-Dec-30 00:00:00’

Bu sorgumuz içiçe select cümleciklerinden oluşmakta, HIVE üzerinde çalıştırdığımda aşağıdaki hatayı almaktayım. Örnekteki HIVE sürümü 1.1.0 .

FAILED: SemanticException Line 1:190 Unsupported SubQuery Expression 'session_id' in definition of SubQuery sq_1 [
..........................
] used as sq_1 at Line 1:120: Nested SubQuery expressions are not supported

Gördüğümüz gibi kızdı, içiçe sorgularda değişkenlerin kullanımı ile ilgili bir problemden bahsediyor.

Açık kaynak araçların dökümantasyonları da gerçekten özenle hazırlanıyor. Bu hatayı arattığımda HIVE’ın dökümantasyonunda içiçe sorgular kısmında aşağıdaki bilgileri gördüm. Benim de bazılarını tecrübe ettiğim bilgiler şu şekilde. İsterseniz kendinizde test edebilirsiniz.

  • Alt sorgulara İSİM verilmesi gerekiyor.
  • Alt sorgular FROM kısmında yer almalı.
  • İçiçe sorgularda Kolon isimleri tablo isimleri ile beraber verilmeli.
  • Alt sorgu, değişkenin sağ tarafında yer almalı
  • IN , NOT IN , EXISTS ve NOT EXISTS kullanılabilir
  • IN ve NOT IN kullanımında tek bir kolon dönülmeli
  • EXISTS ve NOT EXISTS kullanımında alt sorgular en az bir kolon üzerinden eşlenmeli
  • Sorgunun üst seviyesine refereans olan kolonlar ancak WHERE kısmında kullanılabilir

Bu bilgiler ışığında sorgumuzu tekrar yazarsak ve gereksiz selectleri azaltırsak aşağıdaki gibi bir sorgu ortaya çıkıyor:

SELECT t1.SESSION_ID, t1.KEY, t1.VALUE
  FROM SCHEMA1.T1 as t1, SCHEMA1.T4 as t4
 WHERE     t1.session_id = t4.session_id
       AND t4.session_id IN
              (SELECT t3.SESSION_ID
                 FROM SCHEMA1.T2 as t2, SCHEMA1.T3 as t3
                WHERE     t2.VALUE IN
                             (..................)
                      AND t3.VALUE = '........................'
                      AND t2.SESSION_ID = t3.SESSION_ID)
      AND t1.VALUE BETWEEN '2015-May-01 00:00:00' AND '2015-Dec-30 00:00:00';

Burda gördüğünüz gibi tablo ve sorgulara İSİM verdim yani etiketledim ve alt sorgulardaki kolon isimleri açıkca tablolara bağlandı. Gereksiz select cümleleri çıkartıldı.

Sorguyu bu halde çalıştırdığımda aşağıdaki gibi başarılı bir şekilde sonlanmaktadır.

2015-12-08 01:03:28     End of local task; Time Taken: 4.188 sec.
Execution completed successfully
MapredLocal task succeeded
Launching Job 4 out of 4
...
2015-12-08 13:03:52,249 Stage-6 map = 94%,  reduce = 0%, Cumulative CPU 45.93 sec
2015-12-08 13:03:53,265 Stage-6 map = 100%,  reduce = 0%, Cumulative CPU 49.32 sec
MapReduce Total cumulative CPU time: 49 seconds 320 msec
Ended Job = job_1448973637348_0844
MapReduce Jobs Launched:
Stage-Stage-1: Map: 2098  Reduce: 1099   Cumulative CPU: 1452028.98 sec   HDFS Read: 3916425613388 HDFS Write: 105504 SUCCESS
Stage-Stage-4: Map: 1982  Reduce: 1099   Cumulative CPU: 120765.75 sec   HDFS Read: 259305477973 HDFS Write: 7688479 SUCCESS
Stage-Stage-6: Map: 16   Cumulative CPU: 49.32 sec   HDFS Read: 482421 HDFS Write: 0 SUCCESS
Total MapReduce CPU Time Spent: 18 days 4 hours 54 minutes 4 seconds 50 msec
OK
Time taken: 6884.603 seconds

Bu örnekte kullandığım tabloların büyüklükleri bu şekilde.

T1 -> Satır# 902.942.362.399 , on disk   3.5 T
T2 -> Satır#  28.861.733.076 , on disk 129.8 G
T3->  Satır#  29.576.675.998 , on disk 111.6 G
T4- > Satır#  29.577.122.203 , on disk  66.2 G

Evet arkadaşlar, çalışma burda sonlanıyor. Umarım farkındalık anlamında faydalı bir yazı olmuştur. Sorularınız olursa iletişim kurmanızdan memnuniyet duyarım.

İyi çalışmalar.

Kaynak:
https://cwiki.apache.org/confluence/display/Hive/LanguageManual+SubQueries#LanguageManualSubQueries-SubqueriesintheWHEREClause
https://issues.apache.org/jira/browse/HIVE-784

Kmeans ve Kmedoids Kümeleme

Bu yazımda sizlere Veri Madenciliği’nin Kümeleme (Clustering) alt başlığının iki üyesi olan K-means ve K-medoids’ten bahsetmeye çalışacağım.

Öğrenme Çeşitleri

Gözetimli öğrenme, sonuçları bilinen veri seti ile modelin oluşturulması ve oluşan modele sonuçları bilinmeyen veri seti verildiğinde, sonuçların tahmin edilmesidir. Örneğin, çalışmada hasta kişiler tahmin edilecekse hasta olan ve olmayan kişilerin bilgisi ile model oluşturulur. Daha sonra modele x kişisinin bilgileri verildiğin x kişisinin hasta olup olmadığı tahmin edilir.

Gözetimsiz öğrenme, sonuçları hakkında bilgi sahibi olunmayan veri setinin tahminidir. Örneğin, elimizde hasta olan ve hasta olmayan kişilere ait bilgileri var fakat kimin hasta olduğunu bilmiyoruz. Bu sefer elimizde olan bilgilere göre kişileri iki gruba ayırıyoruz.

Kümeleme

Kümeleme yöntemi, veriyi gruplara veya kümelere ayıran gözetimsiz öğrenme çeşididir. Veri, grup içindeki elemanların kendi içindeki benzerliği ve grupların birbirine benzememesi kıstası ile birbirinden ayrılır. Kümeleme de esas nokta sınıflar arasındaki benzerliğin minimum, sınıfın kendi içindeki benzerliği maksimum olmasını sağlamaktır. Bu benzerlik uzaydaki veri elemanlarının uzaklık fonksiyonlarına göre birbirlerine olan yakınlığı bazında hesaplanır. Kümeleme bu özelliği ile otomatik sınıflandırma olarak da adlandırılır.

Kümeleme, iş zekası, görüntü örüntü tanıma, web arama, biyoloji ve güvenlik alanlarında yaygın olarak kullanılır. Örneğin, görüntü tanımada el yazısı karakterlerini bulmak için veri kümelere ayrılır.

Kümeleme, bazı uygulamalarda veriyi benzerliğe göre gruplara ayırmasından dolayı aynı zamanda veri segmentasyonu(data segmentation) olarak adlandırılır. Ayrıca ayrılan gruplara benzemeyen veri elemanları ortaya çıktığı için uç değer bulma(outlier detection) uygulamalarında da kullanılır.

Veri madenciliğinde kümelemenin sağlıklı yapılabilmesi için, verinin ölçeklenebilir olmalıdır. Ayrıca kümeleme, veri tipinden bağımsız olarak çalışabilmeli, gürültülü veri ile uğraşabilmeli, girdi sayısının değişkenliğine karşı hassasiyetinin olmaması ve çok elemanlı/boyutlu veri ile çalışabilmelidir.

Kümeleme yöntemleri, bölümleme, hiyerarşik, yoğunluk tabanlı ve ızgara tabanlı olmak üzere dört şekilde uygulanır. Bölümleme metodu, K-means ve K-medoids yöntemlerinden oluşmaktadır.

K-means

Küme merkezi(centroid) tabanlı bir tekniktir. Bölümleme, D elemanı k kümeye ayırır. Oluşan kümelere C dersek,  C 1 den C k’ya k küme adet oluşur ve her küme D nin altkümesi C i ⊂ D  iken kümeler arasında (1 ≤ i, j ≤ k) benzerlik C i ∩ C j = ∅ yoktur.

Algoritma, n elemanı k tane kümeye ayırma işlemi ile başlar.  K centroid belirlendikten sonra elemanların k centroid lere olan uzaklıkları hesaplanır ve k centroid en yakın noktalar bir kümeyi oluşturur. Küme elemanlarının ortalaması alınır ve centroid ler tekrar belirlenir. Eğer  centroid değişmişse noktaların merkeze olan uzaklıklarına göre hangi centroide ait oldukları bulunur ve bu işlem küme merkezleri (centroid) stabil hale gelene kadar devam eder.

Avatajları:

  • Küme sayısı az ise büyük veri setlerinde hiyerarşik kümeleye göre daha hızlıdır.
  • Eğer veri seti özellikle küresel ise hiyerarşik kümelemeye göre daha sıkı kümeler oluşturur.

Dezavantajları:

  • Üretilen kümeler arasında kıyas yapmak zordur.
  • Sabitlenmiş küme sayısı, küme sayısının tahminini zorlaştırır.
  • Küresel olmayan veri setlerinde iyi çalışmaz.
  • Farklı başlangıç bölümlemeleri ile farklı sonuç kümeleri elde edilir.
  • Gürültülü veriye duyarlıdır.

K-medoids

Nesne temelli bir tekniktir. K belirlendikten sonra k tane centroid belirlenir. Elemanların centroide uzaklığına göre hangi centroide ait oldukları bulunur. Centroid ler stabil duruma gelene kadar noktaların centroidlere olan uzaklıkları hesaplanır ve yeni cetroidler belirlenir.

İki algoritma arasındaki temel fark merkezin (centroid) belirlenmesidir. Kmeans’te noktaların ortalaması alınırken, K-medoids’te noktaların centroide olan uzaklıkları hesaplanır.

Avantajları:

  • Daha iyi ve kararlı kümeleme sonuçları verir.
  • Verilerin işleniş sırası ve ilk atamada ki merkez seçiminin kümeleme üzerinde etkisi yoktur.
  • Merkezi elemanların kümeyi temsil etmesinden dolayı gürültülü veriye karşı duyarlı değildir.

Dejavantajları:

  • Uygun küme sayısının belirlenmesi için birden fazla deneme yapmak gerekir.

K-means ve K-medoids Kıyaslaması

K-means

  • Küme, küme merkezi ile temsil edilir.
  • Gürültülü veriye karşı duyarlıdır.
  • Büyük veride daha güvenilirdir.

K-medoids

  • Küme, kümede ki herhangi bir eleman ile temsil edilir.
  • Gürültülü veriden etkilenmez.
  • Küçük veride daha güvenilirdir.

Cluster sayısını belirlenmesi için çeşitli yöntemler

  • Deneysel yöntem: Veri setindeki nokta sayısı n ise cluster sayısı √n/2
  • Elbow Yöntemi: Cluster sayısı başlangıç olarak 1 alınır ve varyans hesaplanır. Varyans değeri sabitlenene kadar cluster sayısı artırılmaya devam edilir.
  • Silhouette Coefficient: Bu değer ile kümelerin birbirinden ne kadar farklı olduğunu bulmuş oluruz. +1 ile -1 arasında oluşan değer +1’e ne kadar yakın olursa cluster sayısının o kadar iyi olduğunu teyit ederiz. Kümelerin kendi içlerindeki ve kümelerin kendi aralarındaki ortalama uzaklık arasında oluşturulan denklem ile bu değer bulunur.

Spark ile K-means örneği: (scala dili ile)

import org.apache.spark.{SparkContext, SparkConf}
import org.apache.spark.mllib.clustering.{KMeansModel, KMeans}
import org.apache.spark.mllib.linalg.Vectors

object Kmeans {
  def main(args: Array[String]) {
    if (args.length < 4) {
      println("usage: input output numClusters maxIterations")
      System.exit(0)
    }

    val conf = new SparkConf
    conf.setAppName("Spark KMeans Example").setMaster("local")
    val context = new SparkContext(conf)

    val input = args(0)
    val output = args(1)
    val K = args(2).toInt
    val maxIteration = args(3).toInt
    val runs = calculateRuns(args)
    
    val data = context.textFile(input).map {
      line => Vectors.dense(line.split(',').map(_.toDouble))
    }.cache()

    val clusters: KMeansModel = KMeans.train(data, K, maxIteration, runs)
    println("cluster centers: " + clusters.clusterCenters.mkString(","))

    val vectorsAndClusterIdx = data.map{ point =>
      val prediction = clusters.predict(point)
      (point.toString, prediction)
    }

    vectorsAndClusterIdx.saveAsTextFile(output)

    context.stop()
  }

  def calculateRuns(args: Array[String]): Int = {
    if (args.length > 4) args(4).toInt
    else 1
  }
}

Girdi:

818.21,809.83
8.37,850.78
680.43,698.76
913.88,173.43
579.87,135.51
204.13,800.01
700.44,758.47
657.36,745.11
290.3,109.27
246.64,885.54

Çıktı:

([818.21,809.83],1)
([8.37,850.78],2)
([680.43,698.76],1)
([913.88,173.43],0)
([579.87,135.51],0)
([204.13,800.01],2)
([700.44,758.47],1)
([657.36,745.11],1)
([290.3,109.27],0)
([246.64,885.54],2)

Kaynaklar
Data Mining Concepts and Techniques Third Edition
Jiawei Han
Micheline Kamber
Jian Pei

Veri analizinde yeni alışkanlıklar

Veri işlemede kullanılan alet ve yöntemler baş döndürücü bir hızla gelişip değişiyor. Bunun sonucu olarak, eski adet ve alışkanlıklar ile devam ettirmeye çalıştığımız iş süreçlerinde çıkan sıkıntılar ve çıkmazlar sıradanlaştı. Bu yazıda, özellikle veri analizi konusunda çıkan sıkıntıları aşmak için alet kutumuza girmesi gerekli olan göreceli yeni üç aletten; data notebooks ve polyglot dillerden ve bu dünyanın getirdiği ek zorlukları aşmak için alet kutumuzda olması gereken docker container lardan bahsedeceğiz.

Çok dillilik (Polyglot)

Son zamanlarda büyük veri işleme ile ilgili isminden sıkça bahsettiğimiz birçok alet (tool), kendi dilleri ile birlikte geldi. Bunlara alana özel diller (domain specific languages – DSL) deniyor ve yazılım dilleri arasında geçiş yapılmayan tutucu eski günleri geride bıraktığımızı haber veriyorlar. Ayrıca, birçok yerde; R dili mi, Python mu tartışmaları yaşanırken, gerçek şu ki, bu iki dilin de aynı projede hatta aynı kişiler tarafından kullanılabildiği bir dönemi yaşadığımızı kabul etmemiz ve alışkanlıklarımızı buna göre değiştirmemizde fayda var. Polyglot olmanın normal olduğu bir dünyada yaşıyoruz artık.

Notebooks

Özellikle veri bilimi açısından bakıldığında, normal bir bilim insanının yaptığı gözlemleme, analiz ve sonuç çıkarma süreçlerinin, veriyi bilimsel olarak incelerken de geçerli olacağını düşünmek çok doğal olacaktır. Bu süreçte, gözlem ve analiz sonuçlarının veri ve bazı şekil ve grafiklerle zenginleştirilmiş halde olduğunu da eski örneklerinden (1) görmüşüzdür.

Alışkanlıkların değişmesi

Veri işleme, veriden sonuç çıkarma konusunda çalışan veri analisti, veri madencisi gibi ünvanlar ile çalışanlar için, bir dile bağlı olarak çalıştıkları dönemdeki alışkanlıklar ile devam etmeleri artık mümkün değil. Yeni veri bilimcileri için ise zaten doğal özelliklerden birisi.

Birbirinden bağımsız ve farklı birikimlerdeki akademik ve ticari dünyadan çok değerli insanlar teknolojinin getirdiği olanaklar sayesinde coğrafi yerden bağımsız olarak birlikte çalışıp üretebiliyorlar. Bunun sonucunda daha öncesinde hiç olmadığı kadar üretken bir yapı ortaya çıktı. Aynı problemi çözmeye odaklanmış çok sayıda grup bir araya gelip çeşitli çözümler üretiyorlar. Bu problemlerin hiç şüphesiz ki en çok ilgi çekenlerinden birisi, büyük verinin işlenmesi ve analiz edilmesidir.

Karmaşa

Değişik gruplar ve farklı birikimler, çözüme farklı yazılım dilleri ve aletleri olarak yansıyor. Bunun sonucunda pek çok alana özel dil geliştiriliyor. Bu dillerin belirli problemlerde kullanılması gerçekte daha iyi çözümler konusunda olanaklar sağlarken, çözüm ortamlarının karmaşasını da arttırıyor.

Daha önce veriyi belli dillerle işlemek alışkanlığına sahip birçok eski BT çalışanını ürküten bir durum bu. Öyle ya, RDBMS olan klasik bir ortamda çalışıyorsanız SQL biliyorsunuz, prosedürel algoritmalar için PL/SQL, T-SQL gibi dilleri öğrendiğinizde veri işlemenin birçok konusuna hakim oluyorsunuz. ETL aletlerini de kullanma beceriniz varsa, iş zekası katmanında kullanılan küp dilleri haricinde uçtan uca bir geliştirici, analist olabilirsiniz. Eğer veri madenciliğinin amiral gemisi SAS olan bir ortamda çalışıyorsanız, SQL yanında SAS programlama ve biraz da SAS Macro programlamayı bildiğinizde veriyi her türlü işleyebilirsiniz.

Bu az seslilikten çok sesliliğe geçişte, artık herkesin bildiği NoSQL veri tabanlarının neredeyse her birinin farklı bir DSL i olması eski dünya ve yenidünya sakinlerini birbirlerinden derin çizgilerle ayırıyor.

Uyum

Operasyondan sorumlu olanlar iyi bilirler, uyumluluk production sistemlerinde en büyük problemlerden birisidir. Bu nedenle bırakın farklı bir dilde çözüm üretmeyi, farklı bir versiyonda çözüm üretilmesi bile homurdanmalara yol açabilir. Bunun haklı sebepleri de var tabii ki, geliştirme ortamında çalışan bir kodun production da patladığı konusunda yaşanılan çoğu anlatılmamış kötü tecrübeler vardır.

Peki bu yeni dünyada, bir sürü belki de ismini bile duymadığımız dillerin kullanımı, operasyonel süreçleri nasıl etkiler? İşte bir sorun da buradan çıkıyor. Eski alışkanlıklar ile devam edildiğinde yenidünya çözümleri production tarafında iyiye gidişi desteklemez.

Dilemma

Peki bu paradoks gibi görünen durum nedir? Çok dillilik desteklenecek, ama aynı zamanda operasyonel işlemler de daha rahat yürüyecek. Bu noktada yenidünyanın yeni çözümü devreye giriyor. Şu anda iki farklı temsilcisi olan bu çözümün biz container tarafından bahsedeceğiz.

Containers

Uygulamaların production a kurulmadığını, geliştiricinin ortamının kontrollü olarak aynen kendi içlerinde paketlenerek çalıştırıldığını düşünelim. Teknik tabiri ile dilden bihaber (language agnostik) bir ortamdan bahsediyoruz. Her uygulama en uygun tool ve dil ne ise onunla geliştiriliyor.

Somutlaştırma

Buraya kadar genel hatları ile anlattığım süreci biraz somutlaştırmak için bir örnek üzerinde gideceğim. Veri bilimi konusunda da, kendimce çalışmalar yapan bir kişi olarak bir veri setinin alınması ve işlenmesi konusunda dilden bağımsız bir ortamda çalışma yapmak amacı ile ortaya çıkmış olan polyglot notebook lardan bazılarını inceleyip, bilinçli bir tercih yapmaya karar verdim. Mevcut seçenekler; Spark-notebook, Jupyter, Beaker-notebook, Zeppelin vb. Bunların her birini indirip makinamda kurulu olan sanal Ubuntu OS üzerinde kurup çalıştırmayı denedim. Yaklaşık iki gün boyunca indirme, kurma, ayarlamalar vb işlerle geçti. Yukarıda bahsettiğim, uyum problemi burada da çıktı. Örnek vermek gerekirse, scala 2.11 kurulu idi, ama kurduğum yazılım scala 2.10 istiyordu, Maven upgrade gerekti. Bir yerden sonra onu kur, bunu ayarla, sonuçta sadece spark-notebook u çalıştırabildim. Onda da istediğim şeyleri yapmada sıkıntı çıkınca, esas uğraşacağım işlere zaman ayıramadığımı fark ettim. Hedeften sapmıştım.

Evreka !

Bu süreçte eski dünyanın alışkanlıklarını terk etmek gerektiğine hükmettiğim yazımı ve katıldığım “Dockerize Yourself! Infinite Scalable Systems With Docker” da devveri.com yazarlarından Hüseyin Babal ın güzel uygulama+sunumunu hatırladım. Zaten Docker ile Mongo DB kullanımı ile ilgili bir yazısı da vardı sitemizde.

Değişim

Sonuçta, notebooklar ile ilgili çalışmayı docker container lar kullanarak yapmaya karar verdim. Docker ile ilgili dokümanları okumam ve ilgili yazılımları indirdikten sonra ortamı hazırlamam bir gün sürmedi. Akşamında beaker-notebook u kurup çalıştırmam birkaç dakikamı aldı. Bu işin güzel tarafı artık benzer kurulumları yapmak için baştaki eforu sarfetmem gerekmeyecek. Tabii uygulamaların network ayarlarının yapılması, uygulamalar arası veri alışverişi, port paylaşımları gibi teknik konularda uzmanlaşmak biraz daha vakit alacak ama ben yine de değişim isteyip, benim gibi nereden başlayacağını bilemeyenler için bir örnek sunmak istedim.

Örnek

Öncelikle Docker ın genel yapısından kısaca bahsedeyim. Docker container ile bir uygulamanın çalışması için gerekli olan dosya sistemi dahil her şeyi, bir pakette toplamayı sağlayan bir yapı sunuyor. Bu yapı iki türlü oluşturulabiliyor, daha önce oluşturulmuş paketlenmiş çalıştırılmaya hazır image dosyaları halinde veya installer ile. Image dosyaları ile daha önce var olan bir image de değişiklik yaparak saklayabiliyoruz. Installer ile özel bir script dili ile nelerin kurulacağını söylüyoruz. Bunun avantajı paylaşımı çok kolay oluyor ve şeffaf oluyor.

Bu oluşturulan image lar diğer insanlarla paylaşılmak istendiğinde bir repository ihtiyacı doğuyor. Bunu Docker şirketi sağlıyor. Bu repository den ücretsiz ve ücretli olmak üzere çeşitli yararlanma olanakları var.

Kurulum

Ben Windows olan bir makinaya kurulum yaptım. Kurulum detayları ile ilgili bilgilere buradan bakabilirsiniz. Docker Toolbox ile kurulum çok kolaylaştırılmış. Kurulum tamamlandıktan sonra ilk yapılan iş Docker Toolbox Terminal i tıklayıp açmak. Docker bir Linux uygulaması olduğu için Windows içinde Linux komutları yazmayı sağlayan bir emulator uygulaması. Linux ortamı olduğunu $ işareti ile anlıyorsunuz. Bu işaretin yanına tıklayıp Docker komutlarını yazabilir hale geliyoruz.

Her şeyin yolunda gittiğini anlamanız için

docker run hello-world

yazarak ilk uygulamanızı çalıştırabilirsiniz. Bu komut hello-world image ını local de arıyor, ilk seferinde bulamadığı için Docker Hub Repository ye gidip çekiyor. Dolayısı ile bu işlemin süresi, image ın büyüklüğü ile doğru orantılı oluyor. Sonrasında localde olduğu için hızla çalışıyor.

Bu hızlı girişten sonra gelelim esas amacımıza. Var olan Notebook lar içinden deneyip bakarak bir seçim yapmak istiyorduk. Bunu hızlı bir şekilde yapabilmek için bu notebookları kurulum ve ayarlamalar ile vakit kaybetmemek için Docker container ları kullanalım istiyoruz.

Burada biz bir tanesi için yapacağız, diğerlerini isteyenler kendileri yapabilirler. Ben daha önce görmediklerimden olduğu için aday olarak Beaker Notebook u seçtim. Genel olarak eski IPython notebook dan faydalanılmış nispeten yeni bir notebook ürünü. Başlama sayfasına (getting started) geldiğinizde sayfada uygulamayı kurmak için çeşitli alternatifler sunulmuş. Bu alternatiflerden Docker container ı seçtiğimizde docker hub daki açık repository e ilgili sayfaya ulaşıyoruz. Burada sayfanın sağında bulunan Docker pull commands kutusunun altında bulunan

docker pull beakernotebook/beaker

kopyalayıp, Docker Toolbox Terminal indeki $ işaretli komut satırına kopyalıyoruz. Enter a bastığımızda lokalimizde beakernotebook/beaker isimli image olmadığı için repository e bağlanıp çekmeye başlıyor. Tabii bu büyük bir imaj (4GB) olduğu için bekleme zamanı uzun oluyor.

Sonuçta her şey yolunda gittiğinde image lokalinize gelmiş olacak. Kontrol etmek için

Docker <command>

Komut ailesinden

docker image

komutunu kullanabiliriz.

Docker makinası
Docker makinası

Kısaca açıklayacak olursak, docker sanal bir makinanın özelliklerinden container bağımsız olanları ayrı bir şekilde çalıştırdığı için, birden fazla container için bir makine çalıştırarak sistem kaynaklarını ekonomik kullanmış oluyoruz. Aynı anda birden fazla makine çalıştırmak da mümkün. Bu aynı zamanda uygulamaların izalasyonunu sağlıyor. Artık containerdan istediğimiz sayıda çalıştırabiliriz.

Bu kısa açıklamalardan sonra beaker-notebook a dönersek;

$ docker run -p 8800:8800 -t beakernotebook/beaker

Komutu ile notebookumuzu çalıştırıyoruz. Çalıştırırken container ın kullandığı port ile localhost umuzun port ları arasında bir mapping yapmamız gerekiyor doğal olarak.

Connecting to https://29e59df53085:8800/

Submit this password: aKOMNCaRnIHUfnr

 

İlk çalıştırmada https üzerinden nasıl bağlanacağımız ve bağlantı sırasında sorulan şifreye verilecek rasgele atanmış şifremizi bir yere not ediyoruz. https adresi olarak yukarıdaki şekilde verdiğimiz URL i kullanmamız uygun olacak.

https://192.168.99.100:8800/

beaker notebook
beaker notebook

Bu ekran geldiği an Notebooks dünyasına girmiş oluyoruz. İlk cümleye dikkat edersek

“Click below to get started coding in Python, R, JavaScript, Julia, Scala, Java, Groovy, and Ruby.”

Bu dünya polyglot bir dünya.

Polyglot notebooks
Polyglot notebooks

Bu üçleme; Docker, uygun bir data notebook ve polyglot diller yazının başında belirttiğimiz dünyanın üç temel unsuru.

Demokratik, çoğulcu bir dünya

Bu dünyada geliştiriciler, problem çözücüler probleme en uygun dili seçip, istedikleri versiyonu kullanma özgürlüğü kazanıyor. Python dünyasının versiyon 2 ve 3 arasındaki uyumsuzluklar bu dünyada problem olmaktan çıkıyor. En güzeli de genişleyebilirlik özelliği containerlar sayesinde çoklamanın kolay olması ile problem olmaktan çıkıyor.

Sonuç

Yazının başında belittiğimiz üç alet; data notebooks ve polyglot diller ve bu dünyanın getirdiği ek zorlukları aşmak için docker container lar kullanarak verimizi analiz edebileceğimiz bir ortamı kolayca kurduk. Belirli bir örneği başka bir yazıya bırakarak daha fazla uzamadan bu yazıyı sonlandıralım.

Daha İyi Bir Veri Bilimcisi Olmanız İçin 5 İnanılmaz Yol

Bu yazı datasciencecentral.com adresindeki bir blog yazısının çevirisidir

titleÇoğu veri bilimcisi, ellerinin mümkün olduğunda çabuk bir şekilde veri ile kirlenmesini isterler ama hemen modellemeye başlamadan önce projenin detaylarına girmek önemlidir. Aklında iş fikri olan bir veri bilimcisi bu işte yoluna çıkacak güç faktörleri, sorunları başarıya ulaşmak için hesaplamalıdır. Farklı aşamalarda çeşitli bilgilere, yöntemlere ihtiyacımız olur ama ilk olarak “understanding the business” cümlesinin ilk aşamasını geçmiş olmak ve başarılı bir veri bilimcisi haline gelebilmek için detaylara hızlı ve derin bir şekilde dalmak gerekiyor.

1 – Bir Kaynak Envanterini Yönetmek

01
Bir veri bilimcisi olarak, bir veri bilimi projesinin ulaşılabilir kaynaklarının girdi ve çıktılarını bilmek önemlidir. Bu sadece analizini çalıştırmak için ne kadar bilgisayar gücüne ihtiyacının olduğunu anlamak ile ilgili değildir. Profesyonel bir veri bilimcisinin iş uzmanları, veri uzmanları, teknik destek ve diğer veri bilimcileri gibi şeyleri göz önünde bulundurması gerekiyor. Ayrıca sabit ekstreler, canlı veriye erişim, warehouse veri ve kullanıma hazır veri gibi önemli değişkenlerimiz var. Ancak, donanım ve yazılım gibi bilişim kaynaklarının da unutulmaması gerekiyor. Ciddi bir şekilde düşünmeden bir proje alan herhangi bir veri bilimcisi, mayın tarlasına yürüyor demektir ve birşeylerin ne zaman patlayacağını asla bilemez.

2 – Gereksinimleri, Varsayımları ve Kısıtlamaları Anlamak

02
Çoğu veri bilimcisi iş hedefi olarak ne seçtiyse, tahmin sonuçları noktasında ortalamadan daha yüksek olmak isterler ama başarılı veri bilimcileri bilir ki; doğru tahmin bundan daha fazlasıdır.
Örneğin tüm varsayımları dikkate alan bir veri bilimcisi projede hem iş perspektifini hemde analitik perspektifi anlamış demektir. Bu varsayımlar pek çok formda olabilir -Ancak birisi çirkin yüzünü gösterdiğinde bu genellikle veri ile ilgili olur. Bazen işe bağlı olarak, varsayımlar doğrulanabilir değildir.- ve bunlar en risklileri olabilir. Bu riskli varsayımlara mümkünse listenin en üstünde yer ve öncelik verilmelidir çünkü bunlar keşfetmeyi hedeflediğin sonucun doğrulunu etkileyebilir.

Veri bilimcileri bazı tuzaklar için dikkatli olmalıdır. Verinin biraz yada bütün olarak kaynakların erişilebilirliğini, hatta teknoloji kısıtlamalarını düşünmemiz gerekir. Bu kısıtlamalar geldiğinde olayın dışında düşünmemiz, büyük resmi görebilmemiz gerekir. Örneğin, veri boyutu modelleme için uygun mu? Bu açıkça ortadadır fakat birçok veri bilimcisi bu kritik göz önünde bulundurma kısmını kaçırıyor.

3 – Riskleri ve Olasılıkları Belirlemek

03

Daha önce hiç sırf dış gecikmeler yüzünden herşeyin parça parça olarak sona erdiği bir projeye başladınız mı? Böylesine şeyler için ön hazırlıkları planlamak akıllıca bir hareket olurdu. Çoğu veri bilimcisi burayı kısa kesiyor ve işleri sağlam temeller üzerine oturtmuyor. Böyle hazırlıklar, ihtiyacınız olduğunda gerçekten işe yarayabilir. Bu gibi durumlarda bir ya da iki yedek plan son derece yardımcı olabilir. Bilinmeyen riskler projenizde, sizi başarı rayından çıkarır. Tecrübe der ki; Her zaman başarısız olmanıza sebep olacak birşey vardır. Yani başlangıçta alternatifleri planlamak gerekir.

4 – Dökümanı Anlamak

04
‘Ne demek istiyorsun?’ sorusu iş ortamında disiplinler arası bir takımla çalışıyorsanız gerçekten cevap verilmesi gereken önemli bir sorudur. Konu kendi alanımıza gelince ortamdaki diğer insanlarla aynı dili konuşmadığımız açıktır. Herşeyden önce uygun iş terminolojisinin bir çalışma sözlüğünü hazırlamak sizi ve diğerlerini aynı rotada tutacaktır. Bir diğer iyi uygulama ise tanımlamalar ve resimlendirilmiş örnekler ile bir veri bilimi terminolojisi oluşturmaktır, ama bu direkt olarak elinizdeki işin problemleri ile ilgili olmalıdır. Tabiki bunun 700 sayfalık bir döküman olması gerekmez, en doğrusu tüm taraflar için ikna edici ve yararlı şeyler kullanmaktır. Unutmayın diğerlerinin bir veri bilimcisi olarak senden istediği; sadece en üst seviyede çalışanlar diğerlerinin derinlemesine istatistik ve kod bilmesini ister.

5 – Maliyet ve Faydayı Hesaplamak

05
Bu kısım veri bilimi projenizdeki değeri gösterebilmek için iyi bir yöntemdir. Hatırlayın, işi destekleyen bir profesyonel olarak ‘Bu veri bilimi projesini değerli kılan şey midir?’ sorusunu sormak ve cevaplamak önemlidir. Projenin birleşmiş maliyetlerin potansiyel faydalara karşı basit bir karşılaştırması ve bunun başarılı bir şekilde yapılması sizin ve işiniz için büyük bir yol katedecek olamanız demektir. Daha projenin başında bunu bilmek size ve organizasyona iş bitiminde açıkça fayda sağlayacaktır. Bana göre bu soruları sormamak ve cevap vermemek, başarılı bir Veri Bilimcisi olma yolunda kariyerinizi limitleyen bir harekettir. Bu işi kendiniz üstlenmek için sağduyuyu kullanın ve işinizde meslektaşlarınızın veya yöneticilerin bunu yapmanızı istemesini beklemeyin.

Özet

Veri bilimi iş bağlamında olgunlaştıkça bir Veri Bilimcisi durum değerlendirmesinde, bir envanter almakta, risk ve riskin gelişme ihtimalini öğrenmekte ve başarılı bir veri bilimi projesine sahip olmanın maliyet avantajlarını anlamakta daha uyanık olmalı ve farkındalığını arttırmalıdır. Her veri bilimcisi bu adımları uygulamaz, ama tekrar, her veri bilimcisi son derece başarılı değildir. İş’te sağlam bir veri bilimi metodolojisi çöldeki bir damla su gibidir. Size en çok ihtiyacı olduğu zamanda susamış organizasyonunuzu bırakmayın.

Kaynak; http://www.datasciencecentral.com/profiles/blogs/5-unbelievable-ways-you-can-be-a-better-data-scientist-in

R ile Korelasyon, Regresyon ve Zaman Serisi Analizleri

KORELASYON

Korelasyon rassal iki değişken arasındaki doğrusal ilişkinin gücünü ve yönünü ifade eder.

Bu konuda R ile bir çalışma yapalım. R’a yerleşik olarak gelen mtcars veri setini kullanarak korelasyon matrisi oluşturup bir takım uygulamalar gerçekleştirelim:

mtcars, 1973-1974 model 32 aracın yakıt tüketimi, dizayn ve performans ölçülerini içeren bir data setidir. Detay için ?mtcars yazabilirsiniz.

summary(mtcars)
head(mtcars)
# mpg: Mil/Galon
# cyl: Silindir sayısı
# disp Silindir Hacmi
# hp: Toplam Beygir Gücü
# drat: Arka Aks Oranı
# wt: Ağırlık (lb/1000)
# qsec 1/4 mil zamanı
# vs: V/S
# am: Vites Türü (0 = otomatik, 1 = Manuel)
# gear: İleri vites sayısı
# carb: Karbürator sayısı

Korelasyon matrisi nedir?

Korelasyon matrisi çoklu değişkenler arasındaki korelasyon katsayılarının tablosudur. Bu tabloda bir değişkenin diğer her değişken ile arasındaki korelasyon görülebilir.

Korelasyon matrisi oluşturalım:

korelasyon_matris <- cor(mtcars)

1.korelasyon_matris

Elde etmiş olduğumuz korelasyon katsayılarını corrplot paketi ile görselleştirerek daha yalın bir şekilde görelim:

# install.packages("corrplot")
library(corrplot)
corrplot(korelasyon_matris, method = "circle")

2.korelogram

Bu grafik ile tüm değişkenlerin birbirine bağlılık derecesini daha net bir şekilde gördük. Grafik üzerindeki koyu mavi noktalar güçlü pozitif korelasyonları, koyu kırmızı noktalar ise güçlü negatif korelasyonları göstermektedir. Diğer daireler de renklerine ve büyüklüklerine göre korelasyonun gücünü ve yönünü belirtmektedir.

Şimdi korelasyon katsayılarını ifade eden bu daireleri gruplayalım ve zayıf korelasyonları çıkaralım. Yardım için ??corplot yazıp ilgili dökümanı inceleyebilirsiniz.

cor.mtest <- function(mat, conf.level = 0.95) {
mat <- as.matrix(mat)
n <- ncol(mat)
p.mat <- lowCI.mat <- uppCI.mat <- matrix(NA, n, n)
diag(p.mat) <- 0
diag(lowCI.mat) <- diag(uppCI.mat) <- 1
for (i in 1:(n - 1)) {
for (j in (i + 1):n) {
tmp <- cor.test(mat[, i], mat[, j], conf.level = conf.level)
p.mat[i, j] <- p.mat[j, i] <- tmp$p.value
lowCI.mat[i, j] <- lowCI.mat[j, i] <- tmp$conf.int[1]
uppCI.mat[i, j] <- uppCI.mat[j, i] <- tmp$conf.int[2]
}
}
return(list(p.mat, lowCI.mat, uppCI.mat))
}

res <- cor.mtest(mtcars, 0.95)
corrplot(korelasyon_matris, method = "circle", order = "hclust", p.mat = res[[1]], sig.level = 0.05, addrect = 2, tl.col="black", tl.srt=45)

3.korelasyon_matris_grafik

Şu halde, güçlü pozitif korelasyonlar bir köşegen üzerinde, negatif korelasyonlar da diğer köşegen üzerinde toplandı. Zayıf korelasyonları ifade eden dairelerin üzeri çizildi.

Sahte Korelasyonlar

Bu gibi bir çalışmalarda pek çok sahte korelasyon çıkabilir. Sahte korelasyon, neredeyse birbiri ile hiçbir nedensellik bulunamayacak iki değişken arasında güçlü bir korelasyon çıkması durumudur.

Örneğin:

Bir ülkedeki çikolata tüketimi ile o ülkedeki insanların kazandığı toplam nobel ödülü sayısı arasında pozitif bir korelasyon var.
Internet Explorer kullanım oranı ile suç oranı arasında pozitif bir korelasyon var.
ABD’nin Maine eyaletindeki boşanma oranı ile kişi başına düşen margarin tüketimi arasında güçlü bir pozitif bir korelasyon var. (0,99)

Bunun için şu ayrıntıyı her zaman akılda tutmakta fayda var: Korelasyon nedensellik değildir.

REGRESYON

Regresyon da iki ya da daha çok değişken arasındaki ilişkiyi ölçmek için kullanılan bir analizdir. Biri bağımlı biri bağımsız olan iki değişkenin fonksiyonel ifadesidir.

Aynı şekilde R ile bir takım çalışmalar yapalım:

Yine mtcars data setini kullanalım:

# sınıfı numerik olan cyl sütununu factor sınıfına dönüştürelim.
mtcars$cyl

Şimdi bir grafiği oluşturalım:

#install.packages(“ggplot2”)
library(ggplot2)
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point(size=4, color="blue", shape=20)

4.serpilme_grafiğiBu ilişkiyi ifade eden regresyon doğrularını ekleyelim:

# Regresyon doğrusu eklemek
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point()+
geom_smooth(method=lm)

# Güven aralığı kaldırıldığında
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point()+
geom_smooth(method=lm, se=FALSE)

# Loess metodu
ggplot(mtcars, aes(x=wt, y=mpg)) +
geom_point()+
geom_smooth()

5.regresyon_grafikler

ZAMAN SERİLERİ VE TEKNİK ANALİZ

Zaman serileri bir zaman aralığı içinde ölçülen veri serisidir. Zaman seri analizleri için R oldukça faydalı bir araçtır.

Hisse senetleri ve benzeri piyasalarda analiz yapmak için çok kullanışlı bir paket olan quantmod’u inceleyelim:

Apple Inc. şirketinin 1 Ocak 2015 tarihinden bu yazının yazıldığı güne kadarki günlük fiyat değişimini görelim (01.01.2015 – 10.10.2015) :

#install.packages("quantmod")
library(quantmod)
getSymbols("AAPL") # Apple Inc. Hissesi, Yahoo Finance
apple_hisse <- AAPL["2015-01-01::2015-10-10"] # 1 Ocak 2015 tarihinden bu yazının yazıldığı güne kadar
chartSeries(apple_hisse, type="candlesticks") #Apple Inc. Hisse Senedi Grafiği

6.apple_inc_hisse_senedi

R ile Apple Inc. şirketinin hisse senedini pek çok modern platformdaki gibi inceleme imkanımız var. Şimdi bu hisse senedinin trendini gözlemlemek için bir Basit Hareketli Ortalama ekleyelim. Bu hareketli ortalama ile fiyat hareketlerini yumuşatarak trend hakkında bir fikir sahibi olabiliriz. (Aşağıdaki grafik üzerindeki kırmızı eğri).

addSMA(20) #20 günlük bir basit hareketli ortalama

7.apple_inc_hisse_senedi_ve_sma

Ve son olarak trendin gücü hakkında fikir sahibi olabileceğimiz Relative Strength Index osilatorünü ekleyelim:

addRSI(14) # Relative Strength Index

8.apple_inc_hisse_senedi_ve_rsi

Teknik Analiz konusu altında incelenen pek çok indikatör ve yöntem quandmod paketi içinde gelmektedir. R, bu ve benzeri analizler için pek çok platformda bulabileceğiniz analiz yöntemlerinden çok daha büyük imkanlar sunabilmektedir.

Finans ve araştırma konularında R ile ilgili kaynaklar için: http://www.opiyasa.com/kategori/istatistik-arastirma/

Data Driven Kavramı ve II. Faz

2015 yılı itibariyle “Data Driven” kavramı dünyamızı kökten etkilemeye ve değiştirmeye devam ediyor. Şirketler artık hizmeti müşterinin ayağına götürmenin yeterli olmadığı, müşterilerini tanımaları, ihtiyaçlarını anlamalarının hiç olmadığı kadar kendi varlık sebepleri olacağı bir döneme girmiş durumdalar. Bunları yapabilmenin yoluda exponansiyel olarak artan veri yığınları ve kaynaklarından, bunları işleyip iş süreçlerine aktarabilmekten yani bigdata analitics dediğimiz kavramdan geçiyor.

Dünyanın en büyük 500 şirketi sıralaması olan Fortune 500 listesie baktığımızda büyük değişimi görebiliyoruz. 1955’den bu yana %90 oranında listenin değişmesi ve en büyük değişiminde artarak son 20 yılda yaşanması artık ayakta kalmanın başlı başına bir başarı olduğunu ortaya koyuyor.

Tüm bu değişimin merkezinde yer alan “data driven şirketler” kavramı ise büyük veri analitik yeteneği kazanmış, algoritmaların sonuçlarını kendi iş süreçlerine entegre etmiş şirket kavramını ifade ediyor. Bu konuda kullanılan teknolojilere baktığımızda ise bu sitede de yazılarını okuduğumuz hadoop, spark, nosql, elasticsearch, R, Python gibi open-source teknolojiler yanında bu alandaki dev yazılım firmalarının sunduğu lisanslı çözümler de yer alıyor.

Büyük yazılım firmaları arasında ise Veri Analitiği konusunda halen liderliğini sürdüren SAS firması ön plana çıkıyor. 1970’lere uzanan analitik ürün geliştirme geçmişiyle SAS, analitik bakışı kendi üzerinde de uyguluyor görünüyor çünkü bu yeni çağa ayak uydurmaya çalışıyor. SAS gemisi bir yandan halen çok ihtişamlı görünüyor ancak bir yandan geminin üzerinde yol aldığı deniz artık eskisi kadar pürüzsüz ve sakin değil, bir yandan da etrafda daha ucuza yolcu taşıyan onlarca irili ufaklı gemicik belirdi. Zaman mağrurların, egoların, bana bir şey olmazların aleyhine işliyor, sen çevreye ayak uyduramazsan çevre seni yok ediyor.

Bu şartlarda SAS son yıllarda stratejisinde bazı değişimlere gitmeye başladı, zaten çok güçlü olduğu analitik alanındaki çözümlerinin, Hadoop, R gibi yeni teknolojilerle birlikte ve entegre çalışmasını sağlayan yöntemler ve entegrasyonlar sundu. In-memory çalışan, gizli patternlerin görsel keşfedilmesini sağlayan Visual Analitics ve Visual Statistics ürünlerini çıkarttı. Base SAS yada Data Step olarak isimlendirilen ve tamamen veri işleme üzerine kurgulanmış, SQL’e göre büyük avantajları olan programlama dilinin artık yeterli olmadığını anlayarak, Base SAS’ın yeni gelişmiş hali olarak Data Step 2 (DS2) yi çıkarttı. Büyük veri üzerinde analitik imkanlar sunan SAS High-Performance Analitik Server’a da yatırım yapmaya devam ediyor.

Bir diğer önemli oyuncu SPSS ise 2009 yılında IBM’in satın almasından sonra yeni gelişen dünyaya SAS’a göre daha yavaş bir reaksiyon vermiş durumda. SPSS kolay kullanımı, görsellikte ön plana çıkması, komple bir veri madenciliği paketi olarak sunulması ile ön plana çıkmıştı. Şu anda görünen SAS, R ve diğer analitik firmalara göre akademik çevrede halen bir ağırlığı olmasına rağmen SPSS’in eski popularitesi azalmış durumda.

Eski versionlarını ücretsiz veren RapidMiner, İsviçre Zurich’de üniversite kökenli bir grup tarafından geliştirilen Open source versiyonu da olan KNIME, Kaliforniya merkezli 700 den fazla musterisi olan Alterix de artık devreye girmiş durumda.

2013 sonunda SAP’ın KXEN’i, 2014 yılı mart ayında DELL’in Statsoft(Statistica)’yı satın alması, Microsoft’un ticari olarak R’ı müsterilerine sunan Revolution Analytics’i Nisan 2015’de yani sadece bir kaç ay önce bünyesine katması büyük veri analitiğinde daha yarışın yeni başladığını gösteriyor.

Bunu destekleyici tarzda Veri analizi ve analitiği konusunda yapılan bazı araştırma sonuçları ve grafikleri şimdi sizinle paylaşmak istiyorum.

Grafik 1. İlk grafikte Amerika’da 1000’den fazla kaynakta yayınlanan iş ilanlarını baz alarak araştırma sonuçları yayınlayan Indeed.com ‘un 2014/02 tarihli bir çalışması var. Grafikte halen Java, C, C++, Python gibi programlama dillerinin halen analitik yeteneklerle birlikte arandığını ortaya koyuyor. SAS’ın halen ikinci olması dikkat çekici.

1

Grafik2. Bir de analitik alanda yarışan R ile SPSS ve R ile SAS arasında karşılaştırmalı olarak geçmişten bugüne verilen iş ilanları trendlerine baktığımızda daha ilginç verilerle karşılaşıyoruz. İlk olarak SPSS ile R karşılaştırması aşağıda. Turuncu renk R, Mavi SPSS’i gösteriyor. R çoktan SPSS’i geçmiş durumda.

2

Grafik3. Aynı grafiğin SAS ile R karşılaştırması ise aşağıda. Turuncu renk R, Mavi SAS’i gösteriyor. SAS düşüş, R ise artış trendiyle devam ediyor.

3Grafik4. Son dönemlerin popüler teknolojileri, R ve Python üzerinden aynı grafiğe baktığımızda ise görüntü aşağıda. İvme yukarı yönlü devam ediyor.

4Grafik5. Bir diğer ilginç popülarite karşılaştırmasıda, Stackoverflow üzerinden geliyor. Haftalık olarak R ve SAS’la ilgili yapılan posting’lerin karşılaştırması aşağıda. 2009’dan sonra her şey değişmeye başlıyor.

5

Grafik6. Bu da Linkedin ve Quora.com verisi üzerinden alınmış bir grafik. 2013 sonu itibariyle konu bazlı açılan tartışma gruplarındaki üye sayıları dikkate alınmış durumda. Hepimizin üye olduğu Linkedin açısından ilginç bir grafik.

6

Bu grafiklere Programlama dillerinin popularitesini araştıran Tiobe Index ve Transparent Language Popularity Index sıralamalrınıda dahil edebiliriz. Bunların linkleride aşağıda ve R’ın özellikle SAS’a karşı yükselişi burada da görülüyor.

http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

http://lang-index.sourceforge.net/

Yazının sonuna geldik sanıyorum, baştaki cümleyi tekrar ediyorum, data driven kavramı her şeyi değiştiriyor ve değiştirmeye devam edecek, tüm bu grafikler, karşılaştırmalar, indeksler, trendler, araştırmalar bunu gösteriyor. Eskinin yıkılmaz, dokunulmaz denilen kaleleri dört bir yandan çevrilmiş ve bu haliyle kaldıkları sürece varlıkları sorgulanır durumda. Açık olmadıkları zaman yok olacaklarını anlamış durumdalar.

SAS gibi veri analitiğinde dev bir firmanın 30-40 yıl sonra verdiği reaksiyonlar, dev firmaların veri analitiği firmalarını bir bir satın almaları, verinin exponansiyel artışı, Hadoop-Spark, internet of things kavramları hepsi birden Data scientistlerin damga vuracağı bilgi çağında ikinci fazın başladığını gösteriyor.

Kaynaklar

http://www.dell.com/learn/us/en/vn/secure/2014-03-17-dell-acquires-statsoft-data-analytics-software

http://support.sas.com/documentation/cdl/en/ds2ref/68052/HTML/default/viewer.htm#ds2refwhatsnew94.htm

http://lang-index.sourceforge.net/

http://www.tiobe.com/index.php/content/paperinfo/tpci/index.html

http://r4stats.com/articles/popularity/

http://www.cio.com/article/2906456/data-analytics/microsoft-closes-acquisition-of-r-software-and-services-provider.html

Apache Kafka

kafka-logo-wide

Günümüzde dev veri dediğimiz şey, artık her an(real-time) oluşabilen bir veri haline geldi. Her an her yerden gelen anlık veri bile devasa boyutlara ulaştı. Bunları hızlı , sorunsuz ve ölçeklenebilir bir şekilde nasıl tutarız ve bu veriye real time a yakın bir sürede nasıl tekrar ulaşabiliriz sorusu gündemi işgal etmeye başladı. Apache Kafka’da aslında bu soruya cevap olacak nitelikte bir çözüm olarak Linkedin bünyesinde geliştirildi ve daha sonra açık kaynak kodlu olarak herkesin hizmetine sunuldu.

Apache Kafka temelde log kaydına benzer bir yapıda kayıtları tutan ve bu kayıtları diğer sistemlere mesajlaşma kuyruğu(messaging queue – MQ ) şeklinde sunan bir yapıdır. Yüksek performansı ve düşük gecikme zamanı(latency) ile gerçek zamanlı veri akışı sağlar.

Temel Kavramlar1

Şimdi Kafka’ya özgü kavramlara gelelim.

  • Kafka mesajları “topic”lerde tutar.
  • Topic”lere mesaj gönderenler “producer”lardır.
  • Topic”leri okuyanlar ise “consumer”lardır.
  • Kafka’nın çalıştığı her bir sunucu ise “broker”dır.
  • Broker”ların hepsi birlikte bir “cluster” oluşturur.

Sunucular ve istemciler arası haberleşme tamamen dil bağımsız bir TCP protokolü üzerinde olur. Bu sayede bilinen çoğu popüler dilde istemci kütüphaneleri mevcuttur.

Topic Nedir?

2

Şimdi birazda Kafka’da topic denince aslında ne kasdediliyor, bu konuyu açalım. Kafka’ya gelen mesajların tutulduğu yer bir topic ve her zaman bir ismi var. Temelde her topic bölümlendirilmiş (partitioned) bir ya da birden fazla log dosyasından oluşuyor. Her bir bölüm(partition) mevcut topicin bir kısmına sahip oluyor. Her bölüm kendi içinde bir sıra ihtiva ediyor. Bu sıraya “offset” deniyor ve her bölümde şekildende görüleceği üzere bağımsız bir offset sırası oluyor.

Topice gelen her yeni mesaj bölüm sonuna ekleniyor ve offset numarası birer birer artıyor. Bir kere bir bölüme yazılan bir mesajın offset ve partition bilgisi değişmiyor. Bütün mesajlar yapılan ayara (config) göre belirtilen süre boyunca offset bilgi değişimeden tutuluyor. Yani digger mesajlaşma sistemleri gibi okunan mesajlar artık okunamaz hale gelmiyor. (Aslında onunda bir yöntemi var, ileride anlatacağım ) Bölümlendirme sayesinde yatayda gayet rahat bir şekilde ölçeklenebilir topicler oluşturabiliyorsunuz.

Dağıtık Topic Mimarisi

Bölümlendirme sayesinde her bölüme okuma yazma işlem performansı broker sayısı ile artar hale geliyor. Çünkü Kafka’ya bağlanan her istemci, ayrı bölüme mesaj yazabiliyor ya da ayrı bölümden okuyabiliyor. Gerçek anlamda paralel okuma ve yazma işlemleri bu sayede mümkün oluyor.

Her bölüm istendiği takdirde (ayrıca tavsiye edilen) clusterdaki diğer brokerlara yedekleme amaçlı kopyalanabiliyor (replication). Her bölümün sadece bir brokerda lideri (leader) oluyor ve okuma yazma işlemleri lider bölüme yapılıyor. Diğerleri ise köle (slave) bölümler oluyorlar ve dışardan asla yazma ya da okuma işlemi yapılamıyor. Herhangi bir brokerda bir bölüm işlevsiz hale geldiğinde, o bölümün diğer kopyalardan biri o bölüm için lider olup, hizmet verir hale geliyor. Aynı topicte her bölüm için farklı makinalar lider olduğu içinde gayet dengeli bir dağılım oluyor.

Producer Kullanımı

Producer hangi mesajın ilgili topicte hangi bölüme gideceğine karar verebiliyor. Bunu ya round-robin şeklinde ya da mantıksal bölümlendirme (semantic partitioning) ile yapıyor. Bir topice mesaj gönderirken eğer bir anahtar(message key) verirseniz ve ilgili topicin mantıksal bölümlendirme fonksiyonu varsa, mesaj ona gore bir partitiona yazılır. Örneğin, gönderidğin mesajlarda anahtar olarak şehir plaka kodu gönderirseniz, aynı şehirden gelen mesajlar aynı bölümde toplanır. Kafka bu konuda garanti verir.

Consumer Kullanımı

3Kafka’da “consumer group” diye bir kavram vardır. Aslında her consumer bir “consumer group”a aittir. Bu consumer gruba eğer tek consumer group bağlı ise o zaman mesajları okuma şekli kuyruk (queue) davranışı sergiler. O consumer group için gelen mesajlar bütün bölümlerden tek tek okunur. Birden fazla consumerın bir consumer gruba bağlı olması durumda ise o zaman publish/subscribe denilen yapıda bir topic olur (Kafka’daki topic ile karıştırmayın J) Yani gelen mesajları birden fazla consumer group içindeki birden fazla proses birden fazla bölümden okur.

Her iki durum içinde aynı consumer group içindeki consumer sayısı bölüm sayısına eşit olursa, gerçekten hızlı bir şekilde paralel mesaj okumalar gerçekleşir. Consumer sayısını bölüm sayısından fazla verseniz bile Kafka en fazla bir consumer group içinde bölüm sayısı kadar consumerın okuma yapmasına izin verir.

Kafka her bölüm için yazma sırasında okuma sırası garantisi verir. Böylece bölüm bazlı sıralama korunmuş olur.

Komut Satırından Kullanım

İlk olarak Kafka’yı http://kafka.apache.org/downloads.html adresinden indiriyoruz. Ben bundan sonra, yazıyı yazdığım sırada en güncel sürüm 0.8.2.1 olan ile devam edeceğim.

$ tar -xzf kafka_2.10-0.8.2.1.tgz 
$ cd kafka_2.10-0.8.2.1

Kafka’nın dağıtık çalışması Zookeeper sayesinde oluyor. İlk olarak kendi içinde gelen Zookeeper’ı ayağa kaldırıyoruz.

$ bin/zookeeper-server-start.sh config/zookeeper.properties 
[2015-08-03 21:45:56,155] INFO Reading configuration from: config/zookeeper.properties (org.apache.zookeeper.server.quorum.QuorumPeerConfig)...

Zookeeper başarılı bir şekilde ayağa kalktıktan sonra, Kafka’yı ayağa kaldıralım

$ bin/kafka-server-start.sh config/server.properties 
[2015-08-03 21:47:04,021] INFO Verifying properties (kafka.utils.VerifiableProperties)
[2015-08-03 21:47:04,049] INFO Property broker.id is overridden to 0 (kafka.utils.VerifiableProperties)...

Kafka’da her bir “topic” birden fazla parça(partition) şeklinde tutulabilir. Ayrıca fail-over senaryoları için de yedekleri (replication) tutulabilir. Şimdi bir “topic” oluşturalım.

$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 1 --partitions 1 --topic test
Created topic "test".

Oluşturduğumuz “topic”i kontrol edelim

$ bin/kafka-topics.sh --list --zookeeper localhost:2181 
test

Artık yeni oluşturduğumuz bu “topic”e mesaj gönderebiliriz

$ bin/kafka-console-producer.sh --broker-list localhost:9092 --topic test  
[2015-08-03 21:50:37,377] WARN Property topic is not valid (kafka.utils.VerifiableProperties)
First message
Second message
Third message

Son olarakta oluşturduğumuz bu “topic”e gelen mesajları okuyalım

$ bin/kafka-console-consumer.sh --zookeeper localhost:2181 --topic test --from-beginning 
First message
Second message
Third message

Gördüğünüz gibi çok kolay bir şekilde deneme amaçlı bir topic oluşturup, bu topic e okuma yazma işlemleri yaptık. Kafka’nın asıl gücü dağıtık çalışmasında, şimdi birden fazla sunucu ayağa kaldırıp, önceden yaptığımız işlemleri bir daha yapalım.Mevcutta zaten ayakta olan bir Kafka sunucusu vardı, buna 2 tane daha sunucu ekleyelim.

İlk olarak mevcut ayar dosyasının 2 kopyasını alalım

$ cp config/server.properties config/server-1.properties  
$ cp config/server.properties config/server-2.properties

Bu dosyalarda aşağıdaki değişiklikleri yapalım

config/server-1.properties:

broker.id=1     
port=9093     
log.dir=/tmp/kafka-logs-1

config/server-2.properties:

broker.id=2     
port=9094     
log.dir=/tmp/kafka-logs-2

Diğer 2 sunucuyu da ayağa kaldıralım.

$ bin/kafka-server-start.sh config/server-1.properties & 
$ bin/kafka-server-start.sh config/server-2.properties & 

Yeni bir “topic” oluşturalım

$ bin/kafka-topics.sh --create --zookeeper localhost:2181 --replication-factor 3 --partitions 1 --topic my-replicated-topic 

Oluşturduğumuz yeni “topic” sunuculara nasıl dağılmış acaba ?

$ bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic my-replicated-topic 
Topic:my-replicated-topic	PartitionCount:1	ReplicationFactor:3	Configs: 	Topic: my-replicated-topic	Partition: 0	Leader: 1	Replicas: 1,2,0	Isr: 1,2,0 

En başta oluşturduğumuz “topic” nasılmış ?

$ bin/kafka-topics.sh --describe --zookeeper localhost:2181 --topic test Topic:test	PartitionCount:1	ReplicationFactor:1	Configs: 	Topic: test	Partition: 0	Leader: 0	Replicas: 0	Isr: 0 

Nerelerde Kullanılabilir?

• Mesajlaşma Kuyruğu
• Websitesi Aktivite Takibi
• Sistem Metrikleri Toplanması
• Log Toplanması (Log Aggregation)
• Stream işleme (processing)
• Event Sourcing
• Commit Log (MySQL binary log gibi)

Kimler Kullanıyor?

Linkedin, Yahoo, Twitter, Netflix, Spotify, Pinterest, Airbnb, PayPal, vb… Detaylarına bu adresten ulaşabilirsiniz : https://cwiki.apache.org/confluence/display/KAFKA/Powered+By

Son olarak gayet güzel bir dokümantasyonu var : http://kafka.apache.org/documentation.html

Elasticsearch İle Metin İşleme

elasticsearch

Bu yazıda, popüler doküman veri tabanlarından Elasticsearch (ES) ile metin işleme ve sorgulama konusunda bazı önemli noktaları sizlerle paylaşmak istiyorum. Java da yazılmış olan açık kaynak kodlu metin arama motoru olan Apache Lucene kullanılarak geliştirilen Elasticsearch, rakibi Apache Solr ile ciddi bir rekabet içinde.

Bu yazı Türkçe kaynaklarda fazlaca değinilmediğini düşündüğüm, Elasticsearch ile metin verisinin işlenmesinin detaylarına bir giriş niteliğinde olacak. Özellikle bu alanda yabancı çözümlerin Türkçe metinlere uygun çözümler içerip içermediği konusunda kafa yormuş ve daha önceden metin işleme konusu ile ilgili geliştirme yapmış bir kişi olarak, Elasticsearch ü bu açıdan oldukça iyi bulduğumu söyleyebilirim.

Metin işlemenin temel adımları

Metnin hangi dilde olduğundan bağımsız olarak, metin işlemede temel adımlar parantez içinde ES dokümanlarında verilen isimleri ile birlikte şu şekildedir.

  1. Dilin ve mümkünse alanın belirlenmesi, Türkçe metin, spor, edebiyat, askeriye, sosyal medya alanı gibi. Bu kullanılacak referans bir corpus (derlem) kullanılarak yapılacak sonraki adımlardaki işlemler için gereklidir.
  2. Metnin kelimelere ayrıştırılması, (tokenization).
  3. Fazlalık olan işaretlemelerin ve gereksiz kelimelerin temizlenmesi (stopwords),
  4. Kalan kelimelerin standartlaştırılması ve kökünün bulunması, (normalization, stemming)
  5. Kelimelerin benzer olanlarının tespit edilmesi, (synonyms)
  6. Hatalı kelimelerin düzeltilmesi (typoes and mispellings)
  7. Uygun şekilde saklanması (indexing)

Bu işlemler hangi dilde olursa olsun bütün metin işlemelerde geçerlidir ve hazır bir kütüphane kullanılarak metin işlemesi yapıldığında farkında olarak ya da olmadan bu adımlar gerçekleştirilmektedir. Bu açıdan bakıldığında Elasticsearch ün gayet açık ve anlaşılır bir işleme mantığı olduğunu ve kullanıcıya yapacağı metin işlemede ciddi kolaylıklar sunarak bu karmaşık işlemi başlangıç (default) değerler ile yapabilmesini sağladığı görülüyor.

Tabii burada ilk kullanıcı için ciddi avantaj olan bu durum, ileri seviyede kullanım için bu default değerlerin nasıl değiştirileceğinin öğrenilmesi gerektiği anlamına gelmektedir. Şimdi bu adımların Elasticsearch ile nasıl gerçekleştirildiğine yakından bakalım.

Dilin ve mümkünse alanın belirlenmesi

Öncelikli olarak dil ve mümkünse bir alan (domain) belirlenmelidir. Bunun nedeni metin işlenirken kullanılacak korpus un seçilmesinin buna bağlı olmasıdır. Korpus, bir dilde yazılmış eserlerde çıkabilecek her kelimenin sistematik olarak tutulduğu bir katalogdur. Bu kataloğa bakarak bir kelimenin o dilde olmadığı, yanlış yazıldığı, cümle başında veya sonunda olamayacağı tespiti yapılabilir. Dilimiz için somut bir örnek için Türkçe korpus a bakılabilir.

Dokümanın yazıldığı dilin tespitinde iki ayrı yöntem kullanılmaktadır ve Elasticsearch de bu iki yöntemi kullanıcıya sunmaktadır. Birincisi bir standart dil belirlenip konfigürasyon buna göre yapılır ve eğer bunun dışında bir dil olacaksa bir parametre ile bildirilir. Özellikle çok dilli metinlerle uğraşanlar için otomatik metin dili belirlemek bir zorunluluk haline geldiğinden, Elasticsearch ün bu tür durumlarda önerdiği açık kaynak kodlu proje chromium-compact-language-detector değişik dilleri desteklemektedir. Bunun dışında, kullanıcı ekrandan bir metin giriyorsa uygulama içinden HTTP accept-language başlık parametresi dili belirlemek için kullanılabilir. Detayları olan bir konudur. Alanın belirlenmesi metni işlerken korpusun daraltılması açısından bazı faydalar sağlamaktadır, zorunlu değildir. Özellikle sorgu performansında iyileşme sağlar.

ElasticSearch e verinin aktarımı

Metni Elasticsearch e koymak, Elasticsearch ün terminolojisinde indekslemek anlamına gelmektedir. Bunun nedeni metni kaydederken yukarıdaki ikinci adımdan yedinci adıma kadarki süreçte kelimeleri ayrıştırma, fazlalıkları atma gibi işlemler ile her bir kelimeye bir indeks karşılık getirilmesidir. Oluşturulan bu indekse inverted index denmektedir.

Basit bir şekilde şöyle açıklayabiliriz. Tabloda ilk sütuna kelimeleri yazıyoruz, her bir doküman için bir sütun ekliyoruz ve her bir kelimenin karşısına o dokümanda olup olmadığı bilgisini bir bit ile 1/0 ile belirtiyoruz.

elesticssearch indeksleme yöntemi - inverted index
elesticssearch indeksleme yöntemi – inverted index

 

Bütün bu işlemler sorgulama sırasında hızlı cevap vermek ve sorguya uygun doküman listesini kullanıcıya dönmek içindir. Bu nedenle bu noktada Elasticsearch de normalde kullanılan bilgi erişim yöntemine kısaca değinmekte fayda görüyorum. Sorgulamalarda sorguda geçen kelimeler bir bilgi erişimi metodu olan Boolean Model kullanılarak inverted index yardımı ile ilişkili dokümanları getirir. Bu model ‘ve’, ‘veya’ ve ‘değil’ gibi mantıksal operatörleri kullanmaya izin vererek basit bir şekilde indeks tablosundaki hangi dokümanların sorguya uyduğunu hızlı bir şekilde bulur.

Sorgu : (Kelime1 ve kelime3) veya kelime 5

Cevap : doc1, doc2

Doc3 ün dönmemesinin sebebi kelime1 in doc3 de bulunmamasıdır. Kelime5 doc1 de bulunmasa bile veya ile bağlandığı için cevap içinde bulunuyor.

Bu aşamada özellikle sonuçların sayısının çok olduğu durumlarda sonuçların kullanıcıya sunulacağı sıranın ne olacağı önem kazanmaktadır. Örneğin çoğumuz arama motorundan sorduğumuz soruya dönen cevaplardan ilk on veya yirmi cevaba bakarız. Bunun için Elasticsearch, Lucene ın altyapısını da kullanarak, çok karmaşık hesaplamalar yaparak _score parametresindeki [0, 1] aralığındaki değerleri üretir. İlişiklik (relevance) değerleri olarak nitelendireceğimiz bu değerlerin nasıl hesaplandığını bilmek, istenen sorgu kalitesinin nasıl arttırılacağının da cevabıdır. Şimdi bu değerin nasıl hesaplandığına bakalım.

İlişiklilik (relevance) değeri

Yapılan bir sorgu ile var olan dokümanlardan hangilerinin kullanıcıya döndürülmesi gerektiğine karar vermek hatta sıralamak için doküman veri tabanlarında kullanılan algoritmalar, bu iş için kullanılan ilişkisel veri tabanlarından benzer etkin sonuçların alınamamasının temel sebeplerinden belki de en önemlisidir. Şimdi perdenin arkasına kısa bir bakış yapalım. Her kelime için hesaplanan aşağıdaki üç değer bu konuda öne çıkmaktadır.

a)     Terim frekansı (tf)

Sorgudaki kelimelerden biri dokümanda altı kere geçiyorsa bir kere geçen dokümana göre altı kere geçen doküman daha ilişkili kabul edilir. T terim veya kelime, d doküman veya alan olmak üzere;

tf(t in d) = √frekans

b)     Ters doküman frekansı (idf)

Ters doküman frekansı (inverse document frequency – idf) kelimelerin koleksiyondaki dokümanlar içinde geçme sıklığını ifade eden bir değerdir.

Kelime ne kadar çok dokümanda geçiyorsa o kadar ayırt edici özelliği zayıftır kabulüne dayanır. Bu nedenle idf değeri ne kadar küçük ise kelimenin o kadar ağırlığı arttırılır. Ne kadar büyükse o kadar düşürülür. idf in tam değeri şu formül ile hesaplanır.

idf(t) = 1 + log ( numDocs / (docFreq + 1))

c)     Alan uzunluğu kuralı (norm)

Dokümanın veya alanın uzunluğu ne kadar fazla ise kelimenin o dokümanda bulunmasının önemi o kadar azalır. Bu açıdan, başlıkta geçen bir kelime konuda geçen bir kelimeden daha önemlidir.

norm(d) = 1 / √numTerms

Bu değerlerin hesaplanması, doküman Elasticsearch e ilk kaydedilirken indeksleme aşamasında yapılır. Bir kelime için hesaplanan bu üç değer kullanılarak bir skor üretilmesi ve hatta birçok sorguda olduğu gibi birden fazla terim içeren sorgular için de bu işlemin yapılması için Elasticsearch de şu yöntem uygulanmaktadır. Bulunan bu değerler ile oluşturulan vektörler kullanılarak, ilişiklik problemi vektör uzaylarında vektörlerin birbiri arasındaki açıyı bulma problemine dönüştürülmektedir. Bu şekilde sorgudan üretilen vektör ile her bir dokümanın vektörü çok boyutlu uzayda vektör hesaplamaları yapılarak skorlar bulunmaktadır. Bu hesaplamalar Lucene ın Pratik Skorlama fonksiyonuna girdi olmaktadır. Detay için bu linke bakabilirsiniz.

 

Sorgu performansının arttırılması

Yukarıdaki bilgiler bazıları için fazla detay gibi gelecektir ama bilmemiz gereken _score parametresinin hesaplanmasında nelerin etkin olduğu ve bunları sorgu sonuçlarının kalitesini arttırmak için nasıl kullanabileceğimizdir. Bu bilgilere dayanarak Elasticsearch de sorgu performansının arttırılması için ilk akla gelenlerden bazıları şunlardır.

  1. Eş anlamlı kelimelerin tanıtılması önemlidir. Bu şekilde terim frekansı arttırılabilir.
  2. Kelimelerin normalize edilmesi önemlidir. Dokümanların çoğunda geçmesi beklenen zamirler bu, şu, soru ekleri ‘mı’, ‘mü’, ‘mıdır’ gibi sorguda faydalı olmayacağı düşünülen kelimelerin indekslemeye sokulmaması genellikle önerilir.
  3. Alan uzunluğunun, dokümanlarda sıkça geçen ‘ve’, ‘veya’ gibi indekslemede gereksiz kelimelerin atılması ile azaltılması iyidir.

Uygulama

Esasen bu noktaya kadar anlattıklarımız metin işlemesi yapan herhangi bir çözümün yaptıkları olarak görülebilir. Bu noktada Elasticsearch ile nasıl yapıldığı konusunda somut örnekler vermek istiyoruz.

Ortam

İşlemler için kullandığımız ortamı kısaca anlatırsak, tek node üzerinde dağıtıklık özelliğine girmeden default ayarları kullanarak Ubuntu üzerinde yaptığımız bir Elasticsearch 1.7.1 kurulumu üzerinden anlatıyoruz. Elasticsearch ile etkileşimleri REST API ile gerçekleştiriyoruz. Alternatiflerimiz

  1. Bir web browser ile
  2. komut satırından curl komutu ile
  3. Marvel/Sense ile plug-in yüklenirse bir browser yardımı ile web sayfasından. Marvel/Sense i anlatan türkçe bir kaynak
  4. Herhangi bir browser ın restclient addon u, örnek; firefox restclient

 

Basit sorgular için doğrudan bir browser ile sorgulamalarımızı yapabiliriz ama kompleks sorgular için kendi sorgulama dili olan Query DSL (Domain Spesific Language) kullanılıyor. Bu dil JSON formatına bağlı kalınarak hazırlanmış yazım kuralları içeriyor. Çok karmaşık sorgular yapmaya izin veriyor.

Analyzer

Yukarıda detaylı bahsettiğimiz kelimelerin işlenmesi sürecinde Elasticsearch analyzer denen bir paket kullanır. Dilin ve yapılacak işlemin durumuna göre alternatifler mevcut olmakla birlikte default olarak standard anayzer kullanılır ve index default olarak analyzed olarak alınınır. Bunun anlamı ilgili alan yukarıdaki işlemlere tabi tutuldu ve indeksleme buna göre yapıldı demektir. Bazı durumlarda not analyzed yapılması gerekebilir. Özellikle işlenmemesi aynen alınması gereken alanlar için bu yöntem önerilir.

Öncelikle default analyzer ın ihtiyacımızı karşılayıp karşılamadığını anlamak, alternatif anlayzer seçimini yapmamızı kolaylaştıracak alet olarak Analyze API sini kullanabiliriz.

Deafult analyzer

Örnek metin ‘Bu gözümün nuru türkçenin hali ne olacak’ olsun.

curl -XGET ‘localhost:9200/_analyze?analyzer=standard‘ -d ‘Bu gözümün nuru türkçenin hali ne olacak’

Elasticsearch string bir alan tespit ettiğinde onu full text string olarak ele alır ve default olarak standard analyzer ı kullanır. Bu komut çalıştırıldığında kelimelere ayrıştırılma işlemi yapılır, metinde kelimenin nerede başlayıp nerede bittiği bilgisi ile birlikte tespit edilir ve indeksleme buna göre yapılır.

Standart analyzer ile kelimelere ayrıştırma işleminin sonuçları
Standart analyzer ile kelimelere ayrıştırma işleminin sonuçları

Burada <türkçenin> kelimesi yerine <türkçe>, <gözümün> kelimesi yerine <göz> kelimelerinin indekslenmesini isteyebiliriz. Hatta <bu> kelimesinin ayırt edici bir özelliği olmadığından tamamen kaldırılmasını isteyebiliriz. Burada ayırt edici özellik olarak metinlerin çoğunda ve yüksek frekansta geçen kelimelerin dokümanları indekslemede kullanılmamasının genellikle daha iyi sonuç ürettiğini söylemek istiyoruz.

Bu durumda farklı bir analyzer kullanmak isteyebiliriz. Bunun için built-in olanları kullanabilir veya kendimiz custom bir analyzer tanımlayabiliriz. Biz var olan turkish anayzer ı kullanalım.

Turkish analyzer

Türkçe için özel olarak geliştirilmiş built-in bir analyzer kullanalım.

curl -XGET ‘localhost:9200/_analyze?analyzer=turkish‘ -d ‘Bu gözümün nuru türkçenin hali ne olacak’

Turkish analyzer ile kelimelere ayrıştırma işleminin sonuçları
Turkish analyzer ile kelimelere ayrıştırma işleminin sonuçları

Artık <bu> ve <ne> kelimeleri indekslenmedi. <türkçenin> yerine <türkçe>, <gözümün> yerine <göz> kelimeleri indekslendi. Bu şekilde sorgu performansı da artmış oldu.

Analyzer seçiminin sorgu performansına etkisi

Bu aşamada örnek için kullandığımız metni Elasticsearch ile indeksleyip yani kaydedip sonrasında analyzer seçiminin sorgularımızın sonuçlarına nasıl yansıdığına bakalım.

Elasticsearch de yapılan sorguların hepsi, başlarında satır numaraları var.
Elasticsearch de yapılan sorguların hepsi, başlarında satır numaraları var.

36. satırdaki sorgu ile

GET /turkcedoc/denemeler/_search?q=metin1:türkçe

sorgulama yaptığımızda sorgu sonucu boş geliyor. Bu indekslenen kelimenin birebir aranmasından kaynaklanıyor. Çünkü <Türkçenin> kelimesi indekslenmişti. Bu tip durumlarda fuzzy matching kullanılabilir. Bu durumda 38. satırdaki sorgu ile cevabı alıyoruz.

GET /turkcedoc/denemeler/_search?q=metin1:türkçenin

Standart analyzer ile indekslenmiş metin1 alanının sorgu sonucu
Standart analyzer ile indekslenmiş metin1 alanının sorgu sonucu

Gelen sonuçta _score değerine bakarsak uygunluğun 0.11506981 ile değerlendiğini görüyoruz.

40.satırdaki sorguyu yapalım

GET /turkcedoc/denemeler/_search?q=metin2:türkçenin

Turkish analyzer ile indekslenmiş metin2 alanının sorgu sonucu
Turkish analyzer ile indekslenmiş metin2 alanının sorgu sonucu

Bu kez sonucun _score değerinde artış olduğunu görüyoruz. 0.13424811 Bu küçük gibi görünen artış binlerce dokümanın olduğu bir ortamda diğerlerinin önüne geçmek için yeterlidir. Hatta bu kez

GET /turkcedoc/denemeler/_search?q=metin2:türkçe

sorgusuna da cevap alıyoruz.

Yazıyı daha fazla uzatmamak için analyzer ın bize sunduğu olanaklardan birçoğuna burada yer veremiyorum. Sonuç olarak gerçekten sorgu sonuçlarını ilgilendiren indeksleme işlemlerinin arka planının anlaşılmasının ve analyzerı buna göre geliştirip değiştirmenin getirdiği faydaları anlatabildiğimi umuyorum. Belki başka bir yazıda diğer özellikleri de ele alabiliriz.

Hadoop Workshop Etkinliği

sparkİstanbul Spark Tanışmaları Grubu (İSTG) tarafından Spark ın tanıtımı ve kullanımı konulu 25 Temmuz 2015 Cumartesi günü İstanbul’da yapılan çalışma etkinliği sonrası, planlanan diğer bir diğer etkinlik olan Hadoop ile Merhaba Dünya konulu workshop, 8 Ağustos 2015 Cumartesi günü Maslak taki İTÜ Teknokent’te gerçekleştirildi. Arı 3 Çekirdek Seminer Salonu’nda gerçekleştirilen etkinliğe değişik şirket ve sektörden 25 kişi katıldı. İTÜ Çekirdek Yönetimi’nin önceki etkinlikte olduğu gibi, seminer salonlarını Workshop için kullanıma sunmaları etkinliğin güzel bir ortamda gerçekleşmesine önemli katkı sağladı.

Etkinliği düzenleyen İSTG grubunun kurucularından olan Şafak Serdar Kapçı’nın, Hadoop’u tanıtan kısa sunumundan sonra yaklaşık üç saat süren uygulama kısmına geçildi. Bu kısım, Hadoop kurulumu için daha önceden Şafak Bey tarafından hazırlanan CentOS İşletim Sistemli sanal makinanın, her bir katılımcı tarafından kendi makinasında ayağa kaldırılması, geliştirme için gerekli olan Java ve IDE ortamı olan Eclipse in yüklenmesi ve Hadoop un son sürümü Hadoop.2.7.1 kurulumu ve gerekli konfigürasyonların yapılması ile tamamlandı. Bu adımda Hadoop un üç farklı çalışma şeklinden,

  1. Basit (Standalone mode)
  2. Sanki dağıtık (Pseudodistributed mode)
  3. Tam dağıtık (Fully distributed mode)

içinden, ikincisi olan sanki dağıtık mode a göre konfigürasyonlar yapıldı. Bu modda, hadoop un temel bileşenleri tek makinada sanki bir cluster varmışçasına çalıştırıldığı için, tek bir makine üzerinde olsa da gerçeğe mümkün olduğunca yakın bir Hadoop kurulumu yapılmış oldu.

Sonrasında Java projeleri olarak hazırlanmış örnek projelerin github üzerinden alınması ve Eclipse ortamında çalıştırılması şeklinde katılımcıların her birinin kendi makinası üzerinde kurduğu Hadoop ile uygulama denemeleri yaptığı aşamaya geçildi.

Detaylar

Uygulama örneklerinde kullanılmak üzere seçilen veri setleri şunlar oldu.

TCMB.txt veri seti : TC Merkez Bankası GBP ve USD döviz kurları 1950 den günümüze efektif alış ve satış kurları verileri.

NCDC.txt veri seti : National Climatic Data Center (NCDC) ın 1901 den bu yana dünyanın birçok bölgelerinde günlük olarak kayıt edilmiş sıcaklık değerleri verileri.

CDR.txt veri seti : Arama verilerinin bulunduğu örnek veri seti.

 

Şafak Bey in hazırladığı projeler şu şekilde kurgulanmıştı.

  1. TCMB => TCMB.txt veri setinden yıl ve İngiliz Sterlini Alış (gbpA) değerlerini Map eden bir Mapper class ı, her yıl için gün bazında map edilen bu değerlerden her yıl için maksimum değerleri üreten bir reducer class ı. Sonuçta <key, value> şeklinde yıl ve o yılki maksimum gbpA değerleri üretilmektedir.
  2. NCDC => NCDC.txt veri setinden yıl ve sıcaklık değerlerini Map eden bir Mapper class ı, her yıl için gün bazında map edilen bu değerlerden her yıl için maksimum sıcaklık değerlerini üreten bir reducer class ı. Sonuçta <key, value> şeklinde yıl ve o yılki maksimum sıcaklık değerleri üretilmektedir.
  3. CallData => CDR.txt veri setinden konuşma süresi değerlerini Map eden bir Mapper class ı, map edilen bu değerlerden ortalama konuşma süresini üreten bir reducer class ı. Sonuçta <key, value> şeklinde duration ve ortalama konuşma değeri üretilmektedir.

 

Bu adımların detaylarına github daki HadoopWorkShop dan ulaşabilirsiniz.

 

Şafak Serdar Kapçı, Hadoop’u tanıtan kısa bir sunum yaptı.
Şafak Serdar Kapçı, Hadoop’u tanıtan kısa bir sunum yaptı.

 

Çalışma boyunca Şafak Bey katılımcılar ile tek tek ilgilendi.
Çalışma boyunca Şafak Bey katılımcılar ile tek tek ilgilendi.

 

Uygulamalar için Eclipse olarak bilinen ve Java dünyasında yaygın olarak kullanılan Etkileşimli Geliştirme Ortamı – IDE (Integrated Development Environment) tercih edildi. Şafak Bey’in hazırladığı kodlar kullanılarak pratikte bir Hadoop uygulamasının veri işlemede nasıl kullanıldığı uygulamalı olarak gösterildi.

IDE olarak Eclipse ortamı kullanıldı.
IDE olarak Eclipse ortamı kullanıldı.

 

Kaynak Yöneticisi WEB kullanıcı ekranı
Kaynak Yöneticisi WEB kullanıcı ekranı

 

NameNode Web kullanıcı ekranı
NameNode Web kullanıcı ekranı

 

Bitiriş

Workshop boyunca Şafak Bey in sorulara tek tek cevap veriyor olması, dağıtık veri işleme gibi zor bir konunun Hadoop ile nasıl yapılabildiğinin anlaşılması açısından katılımcılar için iyi bir fırsat sunmuş oldu. Bu başarılı etkinlikte emeği geçenleri kutluyoruz.

Spark ile Tanışma Etkinliği

sparkİstanbul Spark Tanışmaları Grubu (İSTG) tarafından Spark ın tanıtımı ve kullanımı konulu çalışma toplantısı, 25 Temmuz 2015 Cumartesi günü İstanbul Maslak taki, İTÜ Teknokent’te gerçekleştirildi. Arı 3 Çekirdek Seminer Salonu’nda gerçekleştirilen etkinliğe değişik şirket ve sektörden 23 kişi katıldı. İTÜ Çekirdek Yönetimi’nin seminer salonlarını Workshop için kullanıma sunmaları etkinliğin güzel bir ortamda gerçekleşmesine önemli katkı sağladı.

Etkinliği düzenleyen İSTG grubunun kurucusu olan Şafak Serdar Kapçı’nın, Spark’ı tanıtan kısa sunumundan sonra yaklaşık üç saat süren uygulama kısmına geçildi. Bu kısım, Spark kurulumu için sanal makinanın hazırlanması, gerekli bazı ön yüklemelerin yapılması ve sonunda da Spark’ın kurulumu ile tamamlandı. Sonrasında iki ayrı örnek veri seti üzerinde uygulamalı olarak Spark ın yetenekleri gösterildi. Bu adımların detaylarına github daki SparkWorkShop dan ulaşabilirsiniz.

Şafak Serdar Kapçı’nın, Spark’ı tanıtan kısa sunumu
Şafak Serdar Kapçı’nın, Spark’ı tanıtan kısa sunumu
Çalışmalar boyunca Şafak Bey in tek tek katılımcılar ile ilgilenmesi ve sorularını cevaplaması
Çalışmalar boyunca Şafak Bey in tek tek katılımcılar ile ilgilenmesi ve sorularını cevaplaması

Uygulamalar için REPL olarak bilinen ve popüler etkileşimli hesaplama ortamı olarak yakın zamanda Jupyter Projesi ismi ile Python a bağlı olmayan bir kimliğe bürünen IPython Notebook ortamında Şafak Bey in hazırladığı kodların üzerinden geçildi. Spark için hazırlanmış Python API paketi olan PySpark kullanılarak temel verinin SparkContext e yüklenmesi ve bu veri üzerinde transformasyon ve aksiyon kategorisindeki işlemlerin nasıl yapılacağı ile ilgili örnek verilerek devam edildi.

spark03
Spark için hazırlanmış Python API paketi olan PySpark kullanımı

Arkasından SparkSQL e bir giriş olarak, PySpark paketinin bir alt paketi olan pyspark.sql kullanılarak da benzer işlemlerin aynı veri setleri üzerinde nasıl yapıldığı konusunda bazı örneklerle oturum tamamlandı.

SparkSQL e bir giriş olarak, PySpark paketinin bir alt paketi olan pyspark.sql ın kullanımı
SparkSQL e bir giriş olarak, PySpark paketinin bir alt paketi olan pyspark.sql ın kullanımı

Çalışmalar boyunca Şafak Bey in tek tek katılımcılar ile ilgilenmesi ve sorularını cevaplaması ile genel olarak katılımcıların bir çoğunun Spark a giriş ve ısınma açısından hızlı bir başlangıç yaptıkları söylenebilir. Bu etkinlikte emeği geçen burada bahsedemediğimiz kişileri yorumlar kısmına eklerseniz seviniriz. Hadoop konusunda bir bloğa da sahip olan Şafak Bey i bu başarılı organizasyon nedeni ile tebrik ediyoruz.

MongoDB Replica Set Kullanımı

MongoDB, şüphesiz son 5 yılın en iyi NoSQL veritabanı çözümlerinden bir tanesi. Foursquare gibi büyük firmalar tarafında kullanıldığı öğrenilince, insanlar kendi sistemlerinde ciddi veri saklama çözümleri için bir heyecanla MongoDB kullanmaya çalışıyor. Evet MongoDB bir çok alanda veri saklama işinde çok yararlı olabilir, ama inanın yanlış kullanıldığı takdirde sizin bir numaralı kabusunuz da olabilir…. MongoDB Replica Set kullanımı ile ilgili internette çok fazla döküman var ama tam olarak çalıştırabileceğiniz şekilde Replica Set kurulumunu anlatan bir kaynak yok. Bu yazıda sizlere adım adım nasıl kurulacağını anlatacağım.

Yüksek hit alan sistemlerde veri saklama işini yaparken verilerin en az bir kopyasının olması(redundancy) ve yüksek erişilebilir(high availability) olması olmazsa olmazlardandır. Biz bunu MongoDB de Replica Set ile yapacağız.

Replica Set Nedir?

Aynı veri setini barındıran ve yöneten bir grup mongod servisleridir. Replica Set in öncelikli amacı datanın redundant ve high available olmasını sağlamaktır. Verilerin kopyası birden fazla sunucuda tutulduğu için, herhangi bir sunucuda donanımsal sıkıntı yaşadığınız zaman, ayni veri baska sunucudan okunabilir. Daha sonra sıkıntı giderildiğinde başka sunucudan aynı veri sorun yaşanan sunucuya otomatik olarak senkronize edilir. Ya da başka bir senaryo düşünürsek, aynı veri birden fazla sunucuda var demiştik. Okuma işlemi yaparken hep aynı sunucudan okumak yerine okuma yükü verinin kopyasının olduğu sunuculara dağıtılır. Dolayısıyla veri okuma ya da yazma hızı artırılmış olur.

Replica Set Yöntemleri

MongoDB Replica Set oluşturmak için gerekli üye sayısı tek sayı olmalıdır. Mesela aşağıdaki 3 üyeli bir Replica Set. Gördüğünüz üzere bir tane Primary üye iki tane Secondary üye var. Diyelim ki sizin bir uygulamanız var ve bu uygulama MongoDB ye bağlanıp belirli işlemler yapıyor. Siz herhangi bir yazma işlemi yaptığınızda Primary üye bu isteği alıp kendi log sistemi olan oplog a yazar. Buraya ayzmasının sebei, daha sonra Secondary üyeler tarafından okunup Secondary üyelerin kendi veritabanlarina yazması için gerekli olmasıdır.

01
Replica Set 1 (http://www.mongodb.org)

Şimdi de başa bir yönteme göz atalım. Bu senaryomuzda ise kalıcı bir Primary üye olmayacak, yeri geldiğinde Secondary üyeler Primary olabilecek. Peki neden böyle bir duruma ihtiyaç duyulsun? Diyelim ki Primary üyenin bulunduğu makine kapandı, bu durumda yazma isteklerini karşılayacak bir üye de olmayacak. Yani sistemde data kaybı olacaktır. Ama siz mimarinizi değiştirip, Primary kapandığında ya da Primary üye 10 saniyeden fazla bir süre diğer üyelerle iletişim kuramadığında, geri kalan üyeler kendi aralarında karar verip Primary üye seçerlerse sistem normal işleyişine devam edebilecektir. Bu mimariyi iki şekilde yapabilir siniz:

02
Replica Set 2 (http://www.mongodb.org)

Burada yeni bir üye tipi var: Arbiter. Bu üye hiçbir şekilde veri işlemi yapmaz sadece Primary üye seçimi yapılırken seçmen sayısının tek sayının katı olması için vardır. Yani sadece seçim işleminde rol oynar. Daha önce de demiştik, Replica Set üye sayısı tek sayı olmalıdır. Peki neden 2 tane Secondary ve tek Primary yok? Aslında onu da yapabilirsiniz ama eğer 2 tane Secondary kullanmaya gerek yok ise, Arbiter kullanmak sizin veritabanı maliyetinizi düşürecektir.

03
Üye seçimi (http://www.mongodb.org)

Bu şekilde de Primary üye bir şekilde kapanırsa eğer, geri kalanlar kendi aralarında Primary seçeceklerdir.

Son olarak, Replica Set’ten veri okuma işlemi genelde Primary üye üzerinden yapılır ama siz okuma stratejinizi değiştirip sadece Secondary üyeden okuma işlemi yap diyebilirsiniz. Bu konuyla ilgili detaylı bilgiyi buradan bulabilirsiniz.

Kurulum İçin Gereksinimler

Kurulum sırasında birden fazla sunucuya (ya da sanal makine de olabilir) ihtiyacımız olacak. Aslında aynı makine üzerinde birden fazla mongod servisini ayrı portlarda da çalıştırabiliriz, ama gerçek yaşamdaki kullanıma yakın olsun diye farklı sunucularda kurarak anlatmayı tercih ediyorum. Ama birden fazla suncuyu nerde bulacağız diyebilirsiniz. Hiç sorun değil, lokal makinenize docker kurup birden fazla linux container ayağa kaldırıp bunlara kurulum yapacağız. Docker kurulumu ile ilgili detaylara burada değinmeyeceğiim, isteyen şuradan nasıl kurulduğuna bakabilir. Kurulum esnasında kullandığım docker komutlarından kısaca bahsediyor olacağım.

Replica Set kurulumundan önce size tek bir mongod servisinin nasıl kurulduğunu göstereceğim. Bu Replica Set kurulumu yaparken işinize yarayacak.

MongoDB kurulumu

Docker kurduktuna sonra ubuntu kullanacağız ama öncelikle indirmemiz gerekiyor. docker pull ubuntu komutunu çalıştırarak indirme işlemi tamamlayın. Daha sonra docker images komutunu çalıştırınca listede ubuntu imajını görmeniz lazım. Şimdi ubuntu imajını kullanarak bir tane container ayağa kaldırıp içine MongoDB kurulumu yapabiliriz ama en az 3 tane container olacak ve herbirine tek tek MongoDB kurmak pek mantıklı olmayabilir. O yüzden gelin bunu otomasyona bağlayalım. Yani öyle birşey yapacağız ki,

  1. ubuntuyu kullansın
  2. MongoDB paketini indirsin ve belirli klasöre kopyalasın
  3. daha önceden hazırladığımız mongo.conf dosyasını container içine kopyalasın

Bu adımları bir Dockerfile içine yazıp bu direktifler doğrultusunda kendi imajımızı yaratabiliriz. Şimdi Dockerfile adında bir dosya yaratın ve içine aşağıdaki içeriği koyun.

FROM ubuntu:latest
RUN apt-get update -y && apt-get install -y wget unzip build-essential
RUN cd /opt \
        && wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.0.4.tgz \
        && tar -xvzf mongodb-linux-x86_64-3.0.4.tgz \
        && mv mongodb-linux-x86_64-3.0.4 mongodb
RUN mkdir -p /data/mongo
RUN mkdir -p /var/log/mongodb

ADD mongodb.conf /opt/mongodb/mongodb.conf
RUN chmod 644 /opt/mongodb/mongodb.conf
RUN chmod 644 /data/mongo

Basitçe, yaratacağımız imajın özelliklerini direktif halinde belirttik, şimdi bunu derleyip imaj oluşturalım. Derlemek için ise aşağıdaki komutu kullanabilirsiniz.

docker build -t mongodb:1.0 .

Bu komut sayesinde, bulunduğunuz dizindeki Dockerfile kullanılarak mongodb adında ve 1.0 versiyonunda bir imaj oluşturduk. Artık bu imajı kullanarak istediğimiz kadar container yaratabiliriz. Sanki bilgisayarınızdaki işletim sistemi ve dosyaların imajını almışsınız ve her an istediğiniz makineye kuruluabilir şeklinde düşünebilirsiniz. Container çalıştırmak için aşağıdaki komutu kullanabilirsiniz.

docker run -d --name mongodb-1 -v /dockerdata:/dockerdata mongodb:1.0 tail -f /dev/null

Bu komut ile container arka planda(-d) çalışır durumda. Adını –name opsiyonuyla verdik ve çalıştırılırken kullanılacak imaj mongodb:1.0 . -v seçeneği volume anlamına geliyor ve bu da lokaldeki bir klasörü container içindeki klasör ile eşleştirmek için kullanılıyor. Mesela ileriki bölümlerde bir anahtar üreteceğiz ve bu anahtar lokaldeki /dockerdata/ klasöründe olacak ve container içinden /dockerdata/mongokey.pem aslında lokal klasörden ulaşılmış olacak. En sondaki fonksiyon zorunlu değil ama eğer docker container içinde hiçbirşey çalışmayacak şeilde ayağa kalkarsa açar açmaz kapanacaktır. O yüzden /dev/null dosyasını tail komutuyla okudum ve bu sayede container ayakta durmuş olacaktır. Container çalışıyor ama bu container e nasıl bağlanacağız? Bağlanmadan önce docker ps diyerek o anki çalışan docker container listesine bakabiliriz. Burada container biligilerini göreceksiniz. Container’a bağlanmak için NAME alanını kullanacağız. Biz container’ı ayağa kaldırırken adını mongodb-1 vermiştik. Bağlanmak için aşağıdaki komutu kullanalım.

docker exec -i -t mongodb-1 bash

Bu komuttan sonra container a bağlanıp komut satırına düşmüş olacaksınız. Artık elinizde icinde MongoDB kurulu olan Ubuntu işletim sistemi var. MongoDB’yi başlatmak icin aşağıdaki komutu kullanabilirsiniz:

/opt/mongodb/bin/mongod --config /opt/mongodb/mongodb.conf

MongoDB’yi başlatmanın birçok yöntemi var. İsterseniz parametreleri direkt olarak komut satırından verebilirsiniz, dilerseniz bir config dosyasına koyup –config opsiyonuyla config dosyasını geçebilirsiniz. Şimdi gelelim config dosyasının içerğindeki ifadelerin ne anlama geldiğine;

dbpath: MongoDB’nin verileri yazacağı klasörün path’i

logpath: MongoDB calışırken logları yazacağı log dosyası

fork: MongoDB’nin daemon modda çalışabilmesi için gereken parametredir. Normalde MongoDB arkaplanda çalışmaz, fork: true derseniz arkaplanda çalıştırmanıza imkan sağlar.

pidfilepath: MongoDB’yi çalıştırdığınızda process id’sini yazacağı dosyadır. Aslında process id’sini ps -ef | awk ‘/mongodb/{print $2}’ | head -1 komutuyla da alabilirsiniz.

logappend: Aslında bu opsiyon analitik için çok önemli. Bu seçenek true olarak ayarlanırsa, mongod restart edildiğinde var olan logların üzerine yazmaz ve kaldığı yerden devam eder. Ama bu seçenek yoksa, restart işleminde eski loglar uçar (Eğer rotate etmediyseniz tabi) ve yeni bir log dosyası yaratıp ona yazmaya devam eder.

smallfiles: Bu seçenek true olursa, MongoDB nin oluşturduğu default veri dosya boyutları küçük olur. Bu konu performans açısından önemli ve burada çok da detaya inmek istemiyorum. Detaylı bilgi için şuraya bakabilirsiniz.

Artık MongoDB çalışır durumda, ama tahmin edeceğiniz gibi hiç bir güvenlik seviyesi yok. İsteyen bağlanıp veri yazabilir. O yüzden yönetim için hesap ekeleyelim. MongoDB servisi çalışırken aşağıdaki komutu çalıştırırsanız:

/opt/mongodb/bin/mongo

MongoDB ye bağlanacaksınız. Replica Set işlemleri, aslında bir yönetici hesabının yapması gereken işlemlerdir. O yüzden sisteme root kullanıcısı ekleyelim. İlk önce admin veritabanına use admin diyerek geçelim ve aşağıdaki komut yardımıyla root kullanıcısı ekleyelim.

db.createUser(
  {
    user: "root",
    pwd: "123456",
    roles: [ { role: "root", db: "admin" } ]
  }
)

Daha sonra şu komut yardımıyla kullanıcıya giriş yaptırabilirsiniz:

db.auth("root", "123456")

Artık kullanıcımız var, MongoDB’yi güvenlikli haliyle restart edebiliriz. Ama önce config dosyasına auth=true eklemeniz lazım. Ekledikten sonra MongoDB’yi restart edelim. Tekrardan admin database ine aşağıdaki komut ile bağlanalım.

/opt/mongodb/bin/mongo localhost:27017/admin

Bağlandıktan sonra db.getUsers() derseniz, yetkili olmadığınızı söyleyen bir mesaj belirecektir. Giriş yapalım:

db.auth("root", "123456"); 

Artık istediğimiz işlemi yapabiliriz.

Buraya kadar yaptığımız güvenlik tabakası olan bir MongoDB servisi kurmaktı. Şimdi replica set nasıl ayarlanır ona bakacağız.

Mantık çerçevesinden olaya baktığımız zaman, Replica Set üyelerinin birbirleriyle haberleşmesi şifreli olması lazım. Yani herhangi bir üye gelişi güzel Replica Set’e bağlanamamalı. Bunun için bir anahtar üreteceğiz ve bütün üyeler bu anahtarı kullanacak. Anahtarı aşağıdaki komut ile üretebiliriz.

openssl rand -base64 741 > mongokey.pem chmod 600 mongokey.pem 

mongokey.pem dosyası, Replica Set üyeleri tarafından okunabilecek bir yerde olması lazım. Bu dosyayı herbir üyenin bulunduğu container’a kopyalayabilirsiniz, ya da dockerdata ortak klasöründen okuyabilirsiniz. Bu anahtarı belirtmek için de config dosyasına bir kayıt daha koymamız lazım.

keyFile=/dockerdata/mongokey.pem

mongokey.pem dosyasını /dockerdata/ klasörüne kopyalayıp MongoDB üyelerini yeniden başlatabiliriz. Tabi yeni configi 3 üyenin config dosyasına ekelmeyi unutmayalım. Diğer üyeler aslında henüz ortada değil onları da aşağıdaki komutlarla başlatalım.

docker run -d --name mongodb-2 -v /dockerdata:/dockerdata mongodb:1.0 tail -f /dev/null
docker run -d --name mongodb-3 -v /dockerdata:/dockerdata mongodb:1.0 tail -f /dev/null

Artık 3 üyemiz var ve docker ps dediğinizde aşağıdaki gibi bir çıktı göreceksiniz.

04

Şimdi ilk container’a bağlanıp Replica Set ayarlarını yapalım.

docker exec -i -t mongodb-1 bash

ile bağlandıktan sonra

/opt/mongodb/bin/mongo localhost:27017/admin -u root -p ‘123456’

ile admin veritabanına bağlanalım ve Replica Set ayarlamaya hazırız.

Replica Set i akliftestirmek icin MongoDB konsolundayken aşağıdaki komutu kullanalım.

rs.initiate()

Bu komut aktifleştirmeyi yapıp kendisini de ilk üye olarak ekler. rs.conf() komutunu çalıştırırsanız aşağıdaki gibi bir çıktı görürsünüz.

05

Buradaki JSON objesinde members altında üyelerin bilgileri yer alır. İlk üyenin host değeri rasgele bir sayı olarak ayarlanmış. Aslında bizim mimaride üyelerin birbirleriyle bu adlarla ulaşması ilk aşamada host tanımlaması yapmadan imkansızdır. O yüzden buradaki host değerini IP ile değiştireceğiz. Peki IP yi nerden bulacağız? Burada docker inspect komutu imdadımıza yetişiyor. docker inspect <container_id> komutunu çalıştırınca ilgili container’a ait bir sürü bilgi gösterilecektir. NetworkSettings.IPAddress de ilgili container’ın IP adresi yer alır. <container_id> yi de docker ps diyerek ilgili container’ın id sini bulabilirsiniz. Aşağıdaki ekrana göre ilk mongo containerin id si 0f110ae7a9f3 tür.

06

docker inspect 0f110ae7a9f3 komutunu çalıştırdığımda IP adresini 172.17.0.29 olduğunu gördüm. Diğer container IP lerine bakmanıza gerek yok çünkü Docker ard arda açılan container ların IP lerini ardışık olarak atar. Yani diğer üyelerin IP adresleri bende 172.17.0.30 ve 172.17.0.32 dir. Şimdi gelelim ilk üyenin host değerini IP ile değiştirmeye. Basit olarak var olan Replica Set konfigürasyonunu bir değişkene atıp host değerini güncelleyeceğiz. Sonra da rs.reconfig() ile eski konfigürasyon ile değiştireceğiz.

cfg=rs.conf()
cfg.members[0].host=”172.17.0.29:27017”
rs.reconfig(cfg)

Diğer üyeleri de eklemek için aşağıdaki komutları kullanabilirsiniz.

rs.add(“172.17.0.30:27017”)
rs.add(“172.17.0.31:27017”)

Tekrar rs.conf() komutuyla diğer üyelerin de eklendiğini görebilirsiniz. rs.conf() dediğinizde her bir üyeye ait bilgileri göreceksiniz. Burda benim bahsetmek istediğim özellik priority. Priority, master seçilirken öncelikli olarak kullanılan alandır. Mesela ilk container 1.0 diğerleri 0 priority değerine sahip olursa, ilk container her zaman seçilen master olacaktır. Örnek aşağıdadır:

cfg=rs.conf()
cfg.members[0].priority = 1
cfg.members[1].priority = 0
cfg.members[2].priority = 0
rs.reconfig(cfg)

Priority hakkında daha fazla bilgiye buradan ulaşabilirsiniz

Son olarak anlatmak istediğim konu Replica Set’in durumuyla ilgili bilgi veren rs.status() komutu. Bu komutu çalıştırdığınızda aşağıdaki gibi bir çıktı alacaksınız.

07

Burada PRIMARY üyenin ne zaman seçildiğini electionTime ile, SECONDARY üyelerin nereye senkronize olduklarını syncingTo ile, SECONDARY üyenin PRIMARY üyeye ne zaman kontrol mesajı gönderdiğini lastHeartbeat, ne zaman yanıt aldığını lastHeartbeatRecv alanından anlayabilirsiniz.

Bu makalede temel olarak MongoDB Replica Set nasıl kurulduğundan bahsetmeye çalıştım. Buradaki anlatım en temel düzeyde olmasına rağmen epeyce uzun oldu. Bir sonraki makalede sizlere Replica Set mimarisinde günlük hayatta nasıl sorunlarla karşılaşılıyor ve bunların çözümleri nelerdir onlardan bahsedeceğim.