19 Ekim 2016 Çarşamba

Apache THRIFT

Apache Thrift nedir?

Farklı programlama diller arasında iletişim kurabileceğiniz, bunu ölçeklenebilir, verimli ve sorunsuz bir şekilde yapabileceğimiz bir yazılım çatısıdır (framework). Bu işlemleri yaparken RPC (remote procedure call) kullanır.

RPC, request–response protokolüne benzemektedir. Bu yapıda bir istek yapıldığında sonuç gelene kadar client (istemci) bloklanır. RPC ek olarak asenkron işlemlere müsade etmektedir. XHTTP (Ajax) gibi düşünebilirsiniz.

Binary protokolünü kullanmaktadır. Binary olması çok hızlı çalışmasını sağlamaktadır.

Siz bir arayüz tanımlıyorsunuz. Sonrasına buna göre istediğiniz dilde kod yapısını çıkarıyor. Size de boşlukları doldurmak kalıyor.

Kullanılabilir dillerden bazıları;
C++, Java, Python, PHP, Ruby, Erlang, Perl, Haskell, C#, Cocoa, JavaScript, Node.js, Smalltalk, OCaml and Delphi ...

Biz PHP ile Python'u konuşturan örnek bir uygulama yapalım;


brew install thrift --with-python --with-php
git clone https://github.com/volkan/thrift-works
cd thrift-works
thrift -r --gen php:server tutorial.thrift
thrift -r --gen php:server shared.thrift
thrift -r --gen py tutorial.thrift
thrift -r --gen py shared.thrift
Python için;

pip install thrift

Veya

cd lib/py
python setup.py install

İki ayrı pencere;

python server/PythonServer.py

php client/PhpClient.php

Böylece farklı dillerde iletişimi sağlamış olduk. Örnekler arasında "zip()" olanın içine "sleep" ile bekleme yapmasını söyledim. Ancak kod akışından bir engelleme olmadan arka planda çalışmaya devam ediyor. (Asenkron) Server tarafında "zip()" yazısı 5 saniye sonra çıkıyor.





Dikkat çekmesi için bazı görseller paylaşacağım. Kaynakları da aşağıda veriyorum. İyi incelemeler :)



Kaynaklar:
https://www.youtube.com/watch?v=e8Df_8yMGRU
http://nordicapis.com/microservice-showdown-rest-vs-soap-vs-apache-thrift-and-why-it-matters/

2 Ekim 2016 Pazar

SolrCloud yeni bir başlangıç

Daha önce hızlıca SolrCloud hakkında konuşmuştuk. Şimdi hızlı bir şekilde temel komutları gözden geçirelim.

bin/solr start -e cloud
Default ayarlarla kurulumu tamamlıyoruz. Daha sonra tekrar çalıştırmak istediğimizde aşağıdaki şekilde çalıştırabiliriz.

bin/solr start -cloud -p 8983 -s "example/cloud/node1/solr" -m 2g
bin/solr start -cloud -p 7574 -s "example/cloud/node2/solr" -z localhost:9983 -m 2g
Sistem default ayarlarla ayağa kalktıktan sonra aşağıdaki şekilde kontrol ediyoruz.

➜  solr-6.0.0 bin/solr status

Found 2 Solr nodes:

Solr process 4600 running on port 7574
{
  "solr_home":"/Users/volkan/project/solr/solr-6.0.0/example/cloud/node2/solr",
  "version":"6.0.0 48c80f91b8e5cd9b3a9b48e6184bd53e7619e7e3 - nknize - 2016-04-01 14:41:49",
  "startTime":"2016-10-01T20:15:22.133Z",
  "uptime":"0 days, 0 hours, 3 minutes, 27 seconds",
  "memory":"91.5 MB (%18.6) of 490.7 MB",
  "cloud":{
    "ZooKeeper":"localhost:9983",
    "liveNodes":"2",
    "collections":"1"}}


Solr process 4497 running on port 8983
{
  "solr_home":"/Users/volkan/project/solr/solr-6.0.0/example/cloud/node1/solr",
  "version":"6.0.0 48c80f91b8e5cd9b3a9b48e6184bd53e7619e7e3 - nknize - 2016-04-01 14:41:49",
  "startTime":"2016-10-01T20:15:15.915Z",
  "uptime":"0 days, 0 hours, 3 minutes, 34 seconds",
  "memory":"74.3 MB (%15.1) of 490.7 MB",
  "cloud":{
    "ZooKeeper":"localhost:9983",
    "liveNodes":"2",
    "collections":"1"}}

Solr kendi içinde 3 farklı config yapısıyla geliyor. Biz bunlardan "data_driven_schema_configs" olanı seçip üzerinde çalışacağız.

Bu ayar yapısında tanımlamasını yapmadığımız "field" lar otomatikmen en uygun olana çevrilir. Klasik ElasticSearch kur çalıştır yapısı gibi düşünebilirsiniz. Ama gerçek anlamda işi olan biri default ayarlarla yetinemez ;)

 server/solr/configsets/data_driven_schema_configs/conf/ dizininde işimiz bittikten sonra yapılan değişiklikleri zookeeper'a göndermemiz gerekiyor. Solr içinde zookeeper yönetmek için güzel bir script mevcut. Bununla işlerimizi rahatlıkla hâlledebiliyoruz.

➜  solr-6.0.0 ./server/scripts/cloud-scripts/zkcli.sh -zkhost localhost:9983
usage: ZkCLI
 -c,--collection    for linkconfig: name of the collection
 -cmd                    cmd to run: bootstrap, upconfig, downconfig,
                         linkconfig, makepath, put, putfile,get,getfile,
                         list, clear, updateacls
 -d,--confdir       for upconfig: a directory of configuration files
 -h,--help               bring up this help page
 -n,--confname      for upconfig, linkconfig: name of the config set
 -name              name of the cluster property to set
 -r,--runzk         run zk internally by passing the solr run port -
                         only for clusters on one machine (tests, dev)
 -s,--solrhome      for bootstrap, runzk: solrhome location
 -val               value of the cluster to set
 -z,--zkhost        ZooKeeper host address
Examples:
zkcli.sh -zkhost localhost:9983 -cmd bootstrap -solrhome /opt/solr
zkcli.sh -zkhost localhost:9983 -cmd upconfig -confdir /opt/solr/collection1/conf -confname myconf
zkcli.sh -zkhost localhost:9983 -cmd downconfig -confdir /opt/solr/collection1/conf -confname myconf
zkcli.sh -zkhost localhost:9983 -cmd linkconfig -collection collection1 -confname myconf
zkcli.sh -zkhost localhost:9983 -cmd makepath /apache/solr
zkcli.sh -zkhost localhost:9983 -cmd put /solr.conf 'conf data'
zkcli.sh -zkhost localhost:9983 -cmd putfile /solr.xml /User/myuser/solr/solr.xml
zkcli.sh -zkhost localhost:9983 -cmd get /solr.xml
zkcli.sh -zkhost localhost:9983 -cmd getfile /solr.xml solr.xml.file
zkcli.sh -zkhost localhost:9983 -cmd clear /solr
zkcli.sh -zkhost localhost:9983 -cmd list
zkcli.sh -zkhost localhost:9983 -cmd clusterprop -name urlScheme -val https
zkcli.sh -zkhost localhost:9983 -cmd updateacls /solr

Aşağıdaki şekilde yaptığımız değişiklikleri Zookeeper'a gönderiyoruz.

solr-6.0.0-> ./server/scripts/cloud-scripts/zkcli.sh -zkhost localhost:9983 -cmd upconfig -confdir server/solr/configsets/data_driven_schema_configs/conf -confname gettingstarted
Yaptığımız değişikliklerin yansıması için;

curl http://localhost:8983/solr/admin/collections?name=gettingstarted&action=RELOAD&wt=json

Bundan sonra shar sayısı ve diğer bütün ayarlar için şuraya bir göz atmak gerekiyor; https://cwiki.apache.org/confluence/display/solr/Collections+API Temel bir şeyleri yazalım.

Backup; Sunucu da öncelikle örnek bir dizin açalım. Daha sonra bu dizine "solr" kullanıcısı için yazma yetkisi verelim

mkdir -p /home/backup/solr 
sudo chown solr:solr /home/backup/solr
curl http://localhost:8983/solr/admin/collections?action=BACKUP&name=gettingstarted&collection=gettingstarted&location=/home/backup/solr&async=1000

async komutu ile arka planda bu süreç çalışmaya devam edecek. Daha sonra ürecin durumunu öğrenmek için

curl http://localhost:8983/solr/admin/collections?action=REQUESTSTATUS&requestid=1000

Süreci farklı şekilde gözden geçirmek adına, hızlıca bir collection oluşturalım;

solr-6.0.0-> bin/solr create_collection -shards 2 -replicationFactor 2 -c test -d server/solr/configsets/data_driven_schema_configs

Bu collection için 2 shard oluşturduk. replicationFactor ise 3 dedik. Şu demek; Bütün datamız ikiye bölünecek. (shard sayısı) replicationFactor ise datanın kaç katı alan kullanacağımızı belirliyor.

Datanın toplam boyutu * replicationFactor kadar yerimiz olmalı. "replicationFactor" 2 olduğunda her sunucuda birebir kopya var demek. 3 olduğunda ek olarak birer "shard"'ın daha kopyası elimizde demek. 4 desek her "shard"'ın 2 yedeği olacak demek. "shard" sayısını daha sonra artırabilirsiniz. Mevcut "shard"ları bölebilirsiniz. API linkinde bu bilgiler mevcut. Aşağıdaki örnek data basımı yaptık.

solr-6.0.0-> bin/post -c test3 example/films

solr-6.0.0-> bin/post -h

Usage: post -c  [OPTIONS] 
    or post -help

   collection name defaults to DEFAULT_SOLR_COLLECTION if not specified

OPTIONS
=======
  Solr options:
    -url  (overrides collection, host, and port)
    -host  (default: localhost)
    -p or -port  (default: 8983)
    -commit yes|no (default: yes)

  Web crawl options:
    -recursive  (default: 1)
    -delay  (default: 10)

  Directory crawl options:
    -delay  (default: 0)

  stdin/args options:
    -type  (default: application/xml)

  Other options:
    -filetypes [,,...] (default: xml,json,jsonl,csv,pdf,doc,docx,ppt,pptx,xls,xlsx,odt,odp,ods,ott,otp,ots,rtf,htm,html,txt,log)
    -params "=[&=...]" (values must be URL-encoded; these pass through to Solr update request)
    -out yes|no (default: no; yes outputs Solr response to console)
    -format solr (sends application/json content as Solr commands to /update instead of /update/json/docs)


Examples:

* JSON file: bin/post -c wizbang events.json
* XML files: bin/post -c records article*.xml
* CSV file: bin/post -c signals LATEST-signals.csv
* Directory of files: bin/post -c myfiles ~/Documents
* Web crawl: bin/post -c gettingstarted http://lucene.apache.org/solr -recursive 1 -delay 1
* Standard input (stdin): echo '{commit: {}}' | bin/post -c my_collection -type application/json -out yes -d
* Data as string: bin/post -c signals -type text/csv -out yes -d $'id,value\n1,0.47'

➜  solr-6.0.0 du -hs example/cloud/node1/solr/test3_shard1_replica1
 76K example/cloud/node1/solr/test3_shard1_replica1
➜  solr-6.0.0 du -hs example/cloud/node1/solr/test3_shard2_replica2
 64K example/cloud/node1/solr/test3_shard2_replica2
➜  solr-6.0.0 du -hs example/cloud/node1/solr/test3_shard1_replica3
 76K example/cloud/node1/solr/test3_shard1_replica3
➜  solr-6.0.0 du -hs example/cloud/node2/solr/test3_shard2_replica1
 64K example/cloud/node2/solr/test3_shard2_replica1
➜  solr-6.0.0 du -hs example/cloud/node2/solr/test3_shard1_replica2/
 76K example/cloud/node2/solr/test3_shard1_replica2/
➜  solr-6.0.0 du -hs example/cloud/node2/solr/test3_shard2_replica3
 64K example/cloud/node2/solr/test3_shard2_replica3




Umarım faydası olur :)

1 Haziran 2016 Çarşamba

Ölü XML den Diri XML çıkarmak :)

VitrinGez'de yoğun bir şekilde XML işliyoruz. Ancak firmalardan çoğu zaman düzgün çalışan XML alamıyoruz. Koskoca firmaya XML'i düzeltir misin de diyemiyorsunuz!

Biz bazı firmalardan XML alamayınca siteyi crawl ediyoruz. Bunun içinde scrapy kullanıyoruz. Scrapy kullanırken bozuk XML lerde dahi çalıştığını farkettim. O zaman kaynak kodu inceledim.

https://github.com/scrapy/scrapy/blob/master/scrapy/utils/iterators.py#L18

def xmliter(obj, nodename):
    """Return a iterator of Selector's over all nodes of a XML document,
       given the name of the node to iterate. Useful for parsing XML feeds.
    obj can be:
    - a Response object
    - a unicode string
    - a string encoded as utf-8
    """
    nodename_patt = re.escape(nodename)

    HEADER_START_RE = re.compile(r'^(.*?)<\s*%s(?:\s|>)' % nodename_patt, re.S)
    HEADER_END_RE = re.compile(r'<\s*/%s\s*>' % nodename_patt, re.S)
    text = _body_or_str(obj)

    header_start = re.search(HEADER_START_RE, text)
    header_start = header_start.group(1).strip() if header_start else ''
    header_end = re_rsearch(HEADER_END_RE, text)
    header_end = text[header_end[1]:].strip() if header_end else ''

    r = re.compile(r'<%(np)s[\s>].*?</%(np)s>' % {'np': nodename_patt}, re.DOTALL)
    for match in r.finditer(text):
        nodetext = header_start + match.group() + header_end
        yield Selector(text=nodetext, type='xml').xpath('//' + nodename)[0]
Yukarıda gördüğünüz üzere yapılan iş aslında çok basit. Önce xml'i küçük parçalara ayıyor. Sonra her birini bağımsız birer xml elemanı gibi kontrol ediyor. Mesela aşağıdaki gibi bir XML yapımız olsun. Dikkat ederseniz ID 5 olan kısımda etiketi bozuk oluşturdum. Büyük bir XML dosyamız olsa küçücük bir kısım yüzünden bütün XML çöp oluyor. Kodları gist'e koydum. Buradan inceleyebilirsiniz. https://gist.github.com/volkan/0d3af41be13a628201b1cee82246d095

$xml = '

';

echo fixXML($xml, 'product');

function fixXML($xml, $nodeName) {

        $patternTag = sprintf('/<%s[\s>].*?<\/%s>/s', $nodeName, $nodeName);
        preg_match_all($patternTag, $xml, $matches);

        $start = '';
        $end = '';
        $list = [];
        $wrongItem = [];
        $doc = new \DOMDocument();
        foreach ($matches[0] as $key => $item) {
            try {
                $tmpXML = $start . $item . $end;
                $status = @$doc->loadXML($tmpXML);
                if ($status == false) {
                 throw new \Exception;
                }
                $list[] = $item;
            } catch (\Exception $e) {
                $wrongItem[] = $item;
            }
        }

        $xml = $start . implode("\n", $list) . $end;

        return $xml;
}

29 Mayıs 2016 Pazar

SolrCloud kurulumu (ve ZooKeeper)

Solr 4 ile birlikte master-slave mevzusu devam etmekle birlikte SolrCloud olarak birden fazla solr makinenin birleştirilerek hata durumunda en az kayıpla çalışma devam etmesi ve bunlar olurken isteklerin tek bir makineye yönlendirilip arkada geri kalan işleri Solr'un hâlletmesi planlanmış. (fault tolerance and high availability).

Kendi kurulum scripti ile tomcat gibi bir web server kurmadan doğrudan kendi içinde gelen jetty isimli web server ile çalıştırabiliyorsunuz. Cloud yapısındaki datanın senkron olması için ZooKeeper isimli araç kullanılmakta. Localde test yapmak için ZooKeeper kurmanıza gerek yok. Kendi içinde gömülü geliyor. Ama prod ortam için kurmalısınız. Çünkü solr kapanırsa ZooKeeper da kapanıyor.

Düzenleme: Docker ile bütün işlemler burada: https://github.com/volkan/docker-solr-cloud

Basit olarak kurup çalıştırmak için şurada anlatılan işlemleri yapıyoruz. Özetlersek;




wget https://archive.apache.org/dist/lucene/solr/5.5.1/solr-5.5.1.tgz
tar zxvf solr-5.5.1.tgz
cd solr-5.5.1

bin/solr -e cloud
Buradan sonra gelen bütün seçenekleri enter'e basarak geçin. Sorunsuz bir şekilde kurulması gerekiyor. Aşağıdaki şekilde durumu kontrol edebilirsiniz.

bin/solr status

Bizim asıl amacımız Production ortamında bunu kurmak. Şimdi onun için başlıyoruz. Örnekler Centos 6 için anlatılacaktır.
Öncelikle varsa iptables stop edin yok yapamam diyorsanız şu kuralları kuracağınız bütün makinelere ekleyin;

vi /etc/sysconfig/iptables

-A OUTPUT -j ACCEPT
-A INPUT -p tcp --dport 2181 -j ACCEPT
-A INPUT -p tcp --dport 2182 -j ACCEPT
-A INPUT -p tcp --dport 2183 -j ACCEPT


yum install lsof -y
yum install java-1.7.0-openjdk java-1.7.0-openjdk-devel -y #java 1.7 yoksa
yum install -y system-config-services #docker için
useradd solr
cd /opt
wget https://archive.apache.org/dist/lucene/solr/5.5.1/solr-5.5.1.tgz
tar xzf solr-5.5.1.tgz && solr-5.5.1/bin/install_solr_service.sh --strip-components=2
bash solr-5.5.1/bin/install_solr_service.sh solr-5.5.1.tgz
service solr start
chown solr:solr /var/solr -R #Solr home directory /var/solr/data not found! Gibi bir sorun çıkarsa

Aşağıdaki çıktı ilk güzel haber :)

[root@9afe0af76150 opt]# service solr start
Waiting up to 30 seconds to see Solr running on port 8983 [-]
Started Solr server on port 8983 (pid=877). Happy searching!
Şimdi aynı makinede solr sayısını ikiye çıkaralım.

cd /opt
bash solr-5.5.1/bin/install_solr_service.sh solr-5.5.1.tgz -s solr2 -p 8984

Waiting up to 30 seconds to see Solr running on port 8984 [-]
Started Solr server on port 8984 (pid=1072). Happy searching!
Burada işimiz şimdilik bitti. ZooKeeper kurulumuna geçiyoruz örnek olması için tek makinede birden fazla makineye kuruyormuş gibi anlatıyorum;

cd /opt
wget http://mirror.vorboss.net/apache/zookeeper/current/zookeeper-3.4.8.tar.gz
tar xzf zookeeper-3.4.8.tar.gz
cp -R /opt/zookeeper-3.4.8/ /opt/zookeeper-3.4.8-2
cp -R /opt/zookeeper-3.4.8/ /opt/zookeeper-3.4.8-3
ln -s /opt/zookeeper-3.4.8/ /opt/zookeeper
ln -s /opt/zookeeper-3.4.8-2/ /opt/zookeeper2
ln -s /opt/zookeeper-3.4.8-3/ /opt/zookeeper3

vi /usr/local/sbin/zkrun

nano veya vi ile açtığınız dosyaya aşağıdaki kodu yerleştirin.

#!/bin/sh

# chkconfig: - 75 50
# description: Starts and stops Zookeeper

cd /opt/zookeeper
bin/zkServer.sh $1

cp /usr/local/sbin/zkrun /usr/local/sbin/zkrun2
cp /usr/local/sbin/zkrun /usr/local/sbin/zkrun3
chmod +x /usr/local/sbin/zkru*
zkrun2 ve zkrun3 için "cd /opt/zookeeper" kısmını "cd /opt/zookeeper2" ve "cd /opt/zookeeper3" olarak değiştirin.

ln -s /usr/local/sbin/zkrun /etc/init.d/zookeeper
ln -s /usr/local/sbin/zkrun2 /etc/init.d/zookeeper2
ln -s /usr/local/sbin/zkrun3 /etc/init.d/zookeeper3
chkconfig --add zookeeper
chkconfig --add zookeeper2
chkconfig --add zookeeper3
chkconfig zookeeper on
chkconfig zookeeper2 on
chkconfig zookeeper3 on

zoo.cfg leri ayarlamakta sıra; zoo.cfg dosyası oluşturup içine şunları koyuyoruz

vi /opt/zookeeper/conf/zoo.cfg

dataDir=/var/lib/zookeeperdata/1
clientPort=2181
initLimit=5
syncLimit=2
server.1=localhost:2888:3888
server.2=localhost:2889:3889
server.3=localhost:2890:3890

Burada server.1 çok önemli. Çünkü bu sayıya göre data içinde myid dosyası oluşturup değer vereceğiz. localhost yazan kısım hosts dosyasında yer alan diğer solr sunucularımız olabilirdi. Ben de bu kısım şöyle;

server.1=solr1:2888:3888
server.2=solr2:2889:3889
server.3=solr3:2890:3890
/opt/zookeeper/conf/zoo.cfg dosyasını diğer zookeeper lara kopyalıyoruz.

cp /opt/zookeeper/conf/zoo.cfg /opt/zookeeper2/conf/zoo.cfg 
cp /opt/zookeeper/conf/zoo.cfg /opt/zookeeper3/conf/zoo.cfg 
Şimdi /opt/zookeeper2/conf/zoo.cfg ve /opt/zookeeper3/conf/zoo.cfg dosyasında yer alan "dataDir" ve "clientPort" kısmında 1 yazan yerleri sırasıyla 2 ve üç yapıyoruz. portlarıda 2182,2183

mkdir -p /var/lib/zookeeperdata/1 mkdir -p /var/lib/zookeeperdata/2 mkdir -p /var/lib/zookeeperdata/3
echo 1 > /var/lib/zookeeperdata/1/myid
echo 2 > /var/lib/zookeeperdata/2/myid
echo 3 > /var/lib/zookeeperdata/3/myid

service zookeeper start && service zookeeper2 start && service zookeeper3 start
ZooKeeper da tamamlandı. Kontrol için aşağıdaki komutu yazıp ilgili çıktıyı görmeliyiz

[root@9afe0af76150 opt]# service zookeeper status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper/bin/../conf/zoo.cfg
Mode: follower
[root@9afe0af76150 opt]# service zookeeper2 status
ZooKeeper JMX enabled by default
Using config: /opt/zookeeper2/bin/../conf/zoo.cfg
Mode: leader
Şimdi Solr'a bu ZooKeeper'ları tanımlama zamanı. /etc/default/solr.in.sh ve /etc/default/solr2.in.sh dosyalarını açıp ZK_HOST alanındaki yorum kısmını kaldırıyoruz. Buraya şunu yazıyoruz;

ZK_HOST="localhost:2181,localhost:2182,localhost:2183"
Sonra solrları restart ediyoruz.

service solr restart
service solr2 restart

Hemen ilk collectionumuzu oluşturuyoruz.

[root@9afe0af76150 opt]# bash /opt/solr/bin/solr create_collection -shards 2 -replicationFactor 2 -c product2 -d /opt/solr-5.5.1/server/solr/configsets/data_driven_schema_configs

Connecting to ZooKeeper at localhost:2181,localhost:2182,localhost:2183 ...
Uploading /opt/solr-5.5.1/server/solr/configsets/data_driven_schema_configs/conf for config product2 to ZooKeeper at localhost:2181,localhost:2182,localhost:2183

Creating new collection 'product2' using command:
http://localhost:8984/solr/admin/collections?action=CREATE&name=product2&numShards=2&replicationFactor=2&maxShardsPerNode=2&collection.configName=product2

{
  "responseHeader":{
    "status":0,
    "QTime":31629},
  "success":{
    "172.17.0.2:8984_solr":{
      "responseHeader":{
        "status":0,
        "QTime":21578},
      "core":"product2_shard1_replica2"},
    "172.17.0.2:8983_solr":{
      "responseHeader":{
        "status":0,
        "QTime":21819},
      "core":"product2_shard2_replica1"}}}

Bu arada configde değişiklik yapmak için /opt/solr/server/scripts/cloud-scripts/zkcli.sh dosyasını kullanabilirsiniz. Örnek şemamız dinamik field yapısını desteklediği için direk kullanmaya başlayabilirsiniz.
PHP tarafında solarium isimli kütüphaneyi önerebilirim.

Aşağıdaki çıktıyı şu linke tıkladığınızda görürsünüz inşaallah :)
Not: Uygun vakitte Docker olarak kurulumu hazırlayıp buradan paylaşacağım.


18 Mart 2016 Cuma

Verileri Cloud Ortamlarda Aktarma

Şimdiye kadar disklerde çok veri kaybeden biri olarak uzun zamandır sanal disklerde verilerimi tutuyorum. Bu işe ilk DropBox ile başladım. Daha sonra Amazon'un 3 ay bedava sonra yıllığı $59.99 olan paketini aldım. Bütün verilerimi buraya yükledim. Biraz uzun sürdü ama sonuçta işler bitmişti. O sıralarda Android işletim sistemine sahip bir telefon kullanıyordum. Bunun Amazon Photos ve Amazon Cloud Drive uygulamaları işimi görüyordu.

Bir süre önce iphone bir telefona geçtim. Bu telefonla çektiğim 2 dakikalık videoların bile Amazon'a saatlerce gönderilemediğini farkettim. Biraz araştırınca son zamanlarda upload konularında amazonla ilgili ciddi sıkıntılar olduğunu gördüm. (Türkiye'ye özgü de olabilir.)

Amazon destek ekibiyle görüşüp çözümler aradık. Bir de üzerine Amazon Cloud Drive uygulamasının iphone da ses dosyalarını cloud'a gönderememesi beni iyice rahatsız etti.
Bu sırada alternatif olarak görebildiğim Google Drive'a aynı dosyaları upload ederek test ettim. Sonuç çok iyiydi. 100 GB limitli aylık $1.99 olan bir paket satın aldım. Aslında DropBox üzerinde 100GB seçeneği olsaydı onu tercih ederdim. Ancak bu seçenek mevcut değil.

Sonuç olarak Amazon Cloud hesabımı iptal etme kararı aldım. Amazon'a durumu yazdım. 3 ay bedava kullanım sonrasında 3 ay da ödeme ile kullandığım hâlde hiç kesinti yapmadan paranın tamamını iade edeceklerini söylediler. Müşteri memnuniyetinde çağ atlayan bir firma olan Amazon'a teşekkürlerimi sunuyorum.

Ben bütün datalarımı taşımak için DigitalOcean firmasında $10 dolarlık bir makine oluşturup rclone uygulaması ile ekstra yere ihtiyaç duymaksızın bütün datayı taşımaya başladım. Belki $5 lık bir makine de iş görecekti. Sonuç olarak şimdiye kadar ara ara hata mesajları alsamda transfer iyi gidiyor. Zaten sorun çıksada rclon sync komutu ile olmayan dosyaları senkron edebileceğimi biliyorum.

Umarım bu bilgiler işinize yarar :)

Düzenleme: DigitalOceans da açtığım makine bir gece çalıştı. Bu nedenle saat ücretlendirilmesi oldu. Çok düşük bir miktar. Ayrıca dublicate dosyaları silmek için şu kodu kullandım https://github.com/ncw/rclone/issues/329#issuecomment-196046151



22 Ocak 2016 Cuma

Algoritma verimliliği

Algoritma verimliliğini ifade etmek için kullanılan matematiksel ifade büyük O dur.
Bu konuyu iyi kavrarsak kuracağımız her mantık, yazacağımız her kod kendini bize doğrudan verimlilik açısından açmış olacak.
Bu matematiksel terimle yapılan hız hesaplaması işlemciden bağımsız olduğu için bakan herkesin aklında aynı şeyi ifade eder.

Bir algoritmanın çözüm süresi genellikle giren eleman büyüklüğü ile ilişkilidir. Biz buna N diyoruz. N büyüdükçe algoritmanın çalışma hızının değişimini ifade etmek için aşağıda gibi bazı ifadeler kullanılır.


O(1)
O(log n)
O(N)
O(N log N)
O(N^2)

Şimdi konuya gerçek hayattan bir örnekle devam edelim!


Olay;

Genişbant interneti olan bir vatandaş 300MB'lık bir dosyayı 120 KM uzaklıktaki bir yere göndermek için internet ve ayağına usb bellek bağladığı bir güvercin kullanıyor. Güvercin hedefe ulaştığında internetten gönderilen dosyanın henüz %24'ü tamamlanmış.

Bizi ilgilendiren kısmı şu, biz gönderdiğimiz dosyanın boyutunu internetten ve güvercinin ayağındaki USB bellekte artırdığımızda ne olacak?

USB de yapılan dosya boyut artırımı hız olarak hiç bir etkide bulunmayacaktır! -USB sonsuz değil abartmayalım lütfen :) -
Ancak internette gönderilen dosyada yapılan artırım dosya boyutu kadar fark yapacaktır.

İşte USB de yapılan artırım etkisi olmadığı için O(1) olarak ifade edilir. İnternette yapılan artırım ise boyuta bağlı olarak hız değişeceği için O(N) olarak ifade edilir.

Bu hesaplamalarda N ile birlikte başka değişkenler ve sabitler olabilir. Ancak en büyük değer dışındaki bütün değerler atılır. Çünkü N büyüdükçe diğer değişkenlerin büyüme hız ihmal edilebilecek kadar küçük kalmaktadır.

Biraz kod örnekleri ile baştan başlayalım;



$n = 10;
$tour = 0;
for ($i = 0; $i < $n; $i++) {
    echo $i . PHP_EOL;
    $tour++;
}

echo sprintf('Tur Sayısı: %s', $tour) . PHP_EOL;
//10
Bu algoritma O(N) sürede çalışacaktır. Tur sayısı N ile eşittir.


$n = 10;
$array = [];
$tour = 0;
for ($i = 0; $i < $n; $i++) {
    for ($j = 0; $j < $n; $j++) {
        $array[$i][$j] = $i+$j;
        $tour++;
    }
}

echo sprintf('Tur Sayısı: %s', $tour) . PHP_EOL;
//100

$n = 5;
$tour = 0;
for ($i = 0; $i < $n; $i++) {
    for ($j = 0; $j < $n; $j++) {
        $tour++;
    }
}

echo sprintf('Tur Sayısı: %s', $tour) . PHP_EOL;
//25

$n = range(0, 10);
$count = count($n);
//N*(N-1)/2
echo $count*($count-1)/2 . PHP_EOL;

$tour = 0;
for ($i = 0; $i < $count; $i++) {
    $j = 0;
    while ($n[$i] != $n[$j]) {
        $j = $j + 1;
        $tour++;
    }
}

echo sprintf('Tur Sayısı: %s', $tour) . PHP_EOL;
//55
Bu üç algoritma O(N^2) sürede çalışacaktır. Tur sayısı n sayısının karesi olacaktır. Daha önce bahsettiğimiz sabitlerin ve küçük kısımların atılması kuralı gereği O(N*(N-1)/2) yerine direk O(N^2) diyoruz.


$a = range(0, 5);
$b = range(0, 3);

$tour = 0;
for ($i = 0; $i < count($a)-1; $i++) {
    for ($j = 0; $j < count($b)-1; $j++) {
        $tour++;
    }
}

echo sprintf('Tur Sayısı: %s', $tour) . PHP_EOL;
//15
Bu algoritma O(a*b) sürede çalışacaktır.


$n = 10;
$tour = 0;
while ($n >= 1) {
    echo $n . PHP_EOL;
    $n = $n / 2;
    $tour++;
}

echo sprintf('Tur Sayısı: %s', $tour) . PHP_EOL;
//4

$n = 20;
$tour = 0;
while ($n >= 1) {
    echo $n . PHP_EOL;
    $n = $n / 2;
    $tour++;
}

echo sprintf('Tur Sayısı: %s', $tour) . PHP_EOL;
//5
Bu algoritma O(log(N)) sürede çalışacaktır.
İşlem sayısı her defasında kendini ikiye bölerek ilerliyor, katlayarak ilerlemenin tersi.
İkinci örnekte N iki katına çıkmasına rağmen tur sayısı yalnızca 1 artmıştır.
20 log 10 = 1.3, 30 log 10 = 1.47, 40 log 10 = 1.60 şeklinde ilerliyor.
N = 20 ve N = 30 arasında yalnızca 5 tur atılırken N = 40 olduğunda 6. tura geçiliyor. Tur sayısı, sayı oranına göre çok küçük bir miktarda artış meydana getiriyor.

Burada şunu sorabilirsiniz log tabanı kaç? Aslında bunun hiç bir önemi yok. Taban yazılmadığı zaman 10 kabul ediliyor. Ama bu iki veya 10 olabilir. Kurallar gereği bunlara takılmıyoruz.

Kendini çağıran fonksiyonlarda durum nasıl dersiniz? Adı üstünde kendini çağıran. Bu da kendi sayısı kadar olacaktır.

Recursive için Faktöriyel güzel bir örnek olacaktır.
Formül olarak N! = N * (N-1) * (N-2) * (N-3) ... şeklinde gidiyor.


function factorial($n, &$tour = 0) {
    $tour++;
    if ($n <= 1) {
        return 1;
    } else {
        return $n * factorial($n-1, $tour);
    }
}

$result = factorial(5, $tour);

echo sprintf('Sonuç: %s Tur Sayısı: %s', $result, $tour) . PHP_EOL;
//Tur Sayısı: 5
Bu algoritma O(N) sürede çalışacaktır. Tur sayısı N ile eşittir.

Bu kadar sözden sonra izlemenizi tavsiye edeceğim iki video var;

1. Faktöriyel
2. Big O Notations

Kaynaklar;
Güvercin ve İnternet
Büyük O gösterimi
Big O Notation (İngilizce ve daha detaylı olan)
What is the big O notation and how do I calculate it?

11 Eylül 2015 Cuma

PHP ile Thread kullanımı

Diyelim ki üç işimiz var ve her biri 1 saniye sürüyor. Normalde arka arkaya çalıştığında bu işlem 3 (üç) saniye sürer. Bir sürü işimiz olsun her biri 1 saniyelik. Tek thread lik bir süreçte bu işler arka arkaya bir birini bekleyerek çalışacağı için toplam işlem süresi iş sayısı kadar olacaktır.
Bunlara işlem sayısı kadar thread açarsak bütün işler 1 saniye sürer.

PHP ile bir örnek yapalım;
Projede Thread kullanmak için PHP de pthread isimli extension yüklemek gerekiyor.


brew install php55-pthreads

Bunu yapınca bütün PHP nin ve eklentilerinin yeniden derlenmesi gerektiğini söylemem gerekiyor.

Örnek kullanım:


result = $sleep;
        sleep($sleep);
    }

    public function getResult() {
        return $this->result;
    }
}

echo "basladi\n";
$timer = microtime(true);
$pool = new Pool(4);
$pool->submit
    (new WebWork());
$pool->submit
    (new WebWork());
$pool->submit
    (new WebWork());
$pool->submit
    (new WebWork());
$pool->shutdown();

$pool->collect(function($query){
    var_dump(
        $done = $query->getResult());
    
    return count($done);
});

printf("islem %f saniye surdu\n", microtime(true)-$timer);
echo "bitti\n";
?>

Yukarıdaki kodu isterseniz console isterseniz web üzerinden çalıştırın aynı sonucu alacaksınız. İşlemler yaklaşık olarak 1 saniye sürecek. Eğer thread sayısını 4 yerine 3 yaparsanız doğal olarak süre uzayacak.

Daha fazla örnek için https://github.com/krakjoe/pthreads/tree/master/examples

28 Ağustos 2015 Cuma

Solr Facet Pivot kullanımı


İhtiyaç: Filtrede birden fazla seçim yapıldığında bu seçimlerin hangi seçimlere bağımlı olduğunun bulunması.

Çözüm: Seçimi yapılan filtrelerin kırılımları solr facet pivot ile kolayca keşfedilebilir.

Örnek sorgu ve sonucu:
http://localhost:8983/solr/browse?wt=json&facet=true&q=*&facet.pivot.mincount=1&facet.pivot={!key%3Dsize-provider-brand-color}facet_attribute_slug_size,facet_provider_url,facet_brand_model_url,facet_color_url




{"responseHeader":{"status":0,"QTime":1},"response":{"numFound":6,"start":0,"docs":[]},"facet_counts":{"facet_queries":{},"facet_fields":{},"facet_dates":{},"facet_ranges":{},"facet_intervals":{},"facet_pivot":{"size-provider-brand-color":[{"field":"facet_attribute_slug_size","value":"m","count":1,"pivot":[{"field":"facet_provider_url","value":"nautica","count":1,"pivot":[{"field":"facet_brand_model_url","value":"nautica","count":1,"pivot":[{"field":"facet_color_url","value":"gri","count":1}]}]}]}]}}}

Bu gelen sonuçları arka tarafta işleyip istediğiniz gibi kullanabilirsiniz.

Not: Bu tür işlemler ekstra yük getirecektir. Bu nedenle solrconfig.xml dosyanızın içine benzer sorgularda Listener eklemelisiniz. Böylece "Searcher" açıldığında bu sorgu çalıştırılacak ve sorgular önceden çalıştırılmış olduğundan normalden daha hızlı çalışacaktır. Tabii cache ayarlarının da iyi olması gerekiyor.

Örnek:

     
        
             *
                /browse
                
                    sum(product(0.001,score_product_like),
                    product(0.02,score_product_hit),
                    product(0.50, score_provider_boost),
                    product(0.45,score_product_boost),
                    product(0.30, score_provider_boost_cpc),
                    product(0.30, score_provider_boost_cps),
                    product(0.50, score_category_product_boost),
                    product(0.09,score_random),
                    scale(random_1,1,5)) desc
                
                true
                facet_attribute_slug_size,facet_provider_url,facet_brand_model_url,facet_color_url
           
        
     


Kolay gelsin.