2011年3月29日火曜日

PythonからRedisに大量データをsetしてみた

前回memcachedを試しましたが、最近ではredisというKVSがあるようなのでredisで実験してみました。installについて言うと何のダウンロードしてmakeするだけで問題無く完了。Python用ドライバも何の問題も無くinstall出来ましたので割愛します。(OSはFedora13)

redisの起動は以下です。
./redis-server &

Pythonのコードは以下の通りです。いつものようにCSVファイルから大量のネタを読み込み、100万件のsetを行います。
---------------------------------------------------------
#!/usr/bin/env python
import csv
import redis
import time

if __name__ == '__main__':
    cnt=0
    start=time.time()
    r = redis.Redis()
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        r.set(str(row[0]),row[1])
    print time.time()-start
---------------------------------------------------------
実行してみると、100万件のsetに112sかかりました。

尚、mset()を使用した場合の結果は以下です。
---------------------------------------------------------
#!/usr/bin/env python
import csv
import redis
import time

if __name__ == '__main__':
    cnt=0
    d={}
    start=time.time()
    r = redis.Redis()
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        d[str(row[0])] = row[1]
        cnt = cnt+1
        if cnt % 1000 == 0:
            r.mset(d)
            d={}
    print time.time()-start
---------------------------------------------------------
これは約10sで完了しました。今までの自己ベスト!です。

redisはmemcachedと違ってクライアントツールが入っていてsqlplusとかpsqlとかに慣れてる人にはうれしい限りです。また大量のコマンドが用意されていたり、レプリケーションが出来たり、データの保存(=DISKへの同期)が簡単に出来たりと、memcachedに満足出来なかった人には使ってみる価値がありそうな気がしました。

HTTPHeaderの"Server"をいろいろ確認してみた (NYダウ編)

HTTPHeaderのServerをNYダウを構成している銘柄で確認してみました。
前回と同じく、英語の社名でgoogleで検索し、1位に表示されたものを確認してます。

アルコア   Microsoft-IIS/6.0
アメリカン・エキスプレス IBM_HTTP_Server
ボーイング SUN-ONE-Web-Server/6.1
バンク・オブ・アメリカ SUN-ONE-Web-Server/6.1
キャタピラー IBM_HTTP_Server
シスコシステムズ Apache/2.0
シェブロン     Microsoft-IIS/6.0
デュポン     Apache
ウォルト・ディズニー・カンパニー Microsoft-IIS/6.0
ゼネラル・エレクトリック  Apache/2.2.14(Unix) mod_jk/1.2.25 mod_ssl/2.2.14 openssl/0.9.8o
ホームデポ IBM_HTTP_Server/2.0.47.1-PK65782 Apache/2.0.47(Unix)
ヒューレット・パッカード Apache
アイ・ビー・エム IBM_HTTP_Server
インテル IA Web Server
ジョンソン・エンド・ジョンソン IBM_HTTP_Server
JPモルガン・チェース JPMC1.0
クラフト・フーズ Microsoft-IIS/6.0
コカ・コーラ IBM_HTTP_Server
マクドナルド Apache/2.0.54
スリーエム IBM_HTTP_Server
メルク Apache
マイクロソフト Microsoft-IIS/7.5
ファイザー  "-"
P&G Apache
エーティーアンドティー Apache
トラベーズ Microsoft-IIS/6.0
ユナイテッド・テクノロジーズ Microsoft-IIS/6.0
ベライゾン・コミュニケーションズ Microsoft-IIS/6.0
ウォルマート・ストアーズ Apache/2.2.15
エクソンモービル Microsoft-IIS/6.0

Microsoftが9社で、IBM社が7社となりました。
この数字は日本よりも多そうです。まあNYダウが30社という比較的少ない銘柄数で構成されている関係でTOPIXの構成銘柄よりもかなり大きい会社が多く、単純な比較は難しそうですが。しかし、Server名を隠しているのはファイザー社のみであり、その他の会社は全く隠していません。こうなると、私が監査で指摘されたServerは隠した方が良いというのはそもそも日本のセキュリティ監査する人だけが言ってるの?と疑問に思えてしまいます。

気になったのは以下です。
インテル・・・IA Web Server でした。確かに同社はいろんなハードベンダと親密なので特定の企業の商品を使うのはまずそうですが。。。"Apache"とかでいいんじゃないのかな。
マイクロソフト・・・Microsoft-IIS/7.5 でした。 バージョンは最新?っぽいです。同社は自社製品の最新版を自社のHPに使用しており、まるで、他社に最新バージョンにあげるように催促している?ようにさえ感じます。

繰り返しになりますが、Server名を隠している企業は1社のみでした。あまり気にしなくていいって事なんでしょうね。。

2011年3月26日土曜日

Pythonからmemcachedに大量データをsetしてみた

Pythonからmemcachedに対して大量データをsetしてみました。
OSはFedora13です。

①memcachedのinstall
yum install memcached

②memcachedの起動
memcached -d
...因みにrootユーザでは起動出来ません。

③Python用ドライバのinstall
easy_install python-memcached

これで準備完了です。

次に以下のようなコードを実行します。

--------------------------------------------------------------
#!/usr/bin/env python
import csv
import memcache
import time

if __name__ == '__main__':
    start=time.time()
    mc = memcache.Client(['localhost:11211'])
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        mc.set(str(row[0]),row[1])
    print time.time()-start
--------------------------------------------------------------

実行したところ、100万行のsetが完了するのに、130sかかりました。

期待したほどのパフォーマンスは出ませんでした。
memcachedという名の通り、DISKへのアクセスは全く発生しないはず・・・。なんですが。

因みに、、今までの実行結果を振り返ると、
Java+PostgreSQL → 130s
Java+Sqlite3 → 19s
Python + Sqlite3 → 28s

PythonとJavaを速度比較してもあまり意味は無いかも知れませんが、上記からはmemcachedとPostgreSQLの速度はほとんど変わらないという事になってしまいます。これはどういう事でしょうか?

私は、クライアントアプリとmemcachedプロセス間の通信がオーバーヘッドになっているものと考え、上記ソースを以下のように修正し、1000件分まとめてsetするようにしました。

--------------------------------------------------------------
#!/usr/bin/env python
import csv
import memcache
import time

if __name__ == '__main__':
    cnt=0
    d={}
    start=time.time()
    mc = memcache.Client(['localhost:11211'])
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        d[str(row[0])] = row[1]
        cnt = cnt+1
        if cnt % 1000 == 0:
            mc.set_multi(d)
            d={}
            cnt=0
    print time.time()-start
--------------------------------------------------------------


上記ソースの場合には100万件のsetに47s程度となり、かなり高速化されました。

自身の経験ではJavaでのバッチ更新(addbatch)とかは使った事は無いのですが、大量の更新事にはかなり高速化に寄与しそうですね。また、SQLiteやH2はプロセス間通信が無い為、大量更新事には非常に高速に動作するというのも納得です。

2011年3月17日木曜日

PythonからCouchDBに大量データをInsertしようとした

PythonからCouchDBに大量データをinsertしようとしてみました。
しようとした…としているのは結論から言うと出来なかった為です。

まず、マニュアルに沿ってCouchDBのinstallをしました。
(OSはFedora13です)

// yumで必要なパッケージをインストール
yum install erlang subversion icu libicu-devel js js-devel libcurl-devel libtool

// ソースの取得
svn checkout http://svn.apache.org/repos/asf/couchdb/trunk couchdb

// CouchDBのインストール
cd couchdb
./bootstrap
./configure
make install

// 起動
couchdb
---------------------------------------------------------------------
Apache CouchDB 1.2.0a1078467 (LogLevel=info) is starting.
Apache CouchDB has started. Time to relax.
---------------------------------------------------------------------
これで起動完了です。"Time to relax"なんて洒落てますよね。

次にCouchDBのPython用のドライバのinstallを実施しました。
easy_install couchdb

またBrowserからアクセスして新しいDBを作成します。
ここではtestdbを作成しました。

ここまでは何の問題も無く終了。

次に以下のようなソースを実行します。
基本的にはMongoDBで使ったものとほとんど一緒です。
以前もやったようにCSVネタとして100万件のneta.csvを用意しておきます。

----------------------------------------------------------------
#!/usr/bin/env python

import csv
import couchdb
import time

if __name__ == '__main__':
    start = time.time()
    server=couchdb.Server()
    db = server['testdb']
    reader = csv.reader(open("./neta.csv"))
    for row in reader:
        _id = row[0]
        value = row[1]
        t = {"_id":_id , "value":value}
        db.save(t)
    print time.time()-start
----------------------------------------------------------------

上記を実行すると我慢出来ない位遅い結果となりました。
大体ですが、100件save()するのに8〜9sかかります。
つまり100万件saveするには丸一日かかってしまいます。

尚、CouchDBはデフォルトのままで使用しており、パラメータチューニング?等は全く行っていません。なんで、こんなに遅いんでしょうか?正確には不明ですが、save()の度にcommit()に近い処理が行われてる為なのかな・・・と思い色々調査しましたが、原因が分かりませんでした。Pythonのコードの書き方が原因だと思うんですが。。。


以下は気づいた点です。


・couchdb.Server()の設定値
Pythonドライバのマニュアルではcouchdb.Serverを実行する際に
 full_commit=Truesession=None
がデフォルトとなっているようだが、上記二つの値の正確な意味が不明。このあたりの仕組みが理解出来れば何とかなるのでは・・・と思ったが分からず。

・saveをまとめてやる
save()をまとめてやれれば、パフォーマンス改善しそう…ですが、実装方法が分かりませんでした。


・delayed_commits
/usr/local/etc/couchdb/default.ini の記述をよく見ると、

delayed_commits = true ; set this to false to ensure an fsync before 201 Created is returned
という一行があり、defaultではsave()毎に実行するであろうfsync()を待たずに動作していると思われる。




尚、CouchDBにはその他DBMSやMongoDBと違ってコマンドラインからselectしたりupdateしたりするクライアントが無く、全てFutonと呼ばれるGUIからしか操作する事になります。また、単純なselectに該当するものが簡単には出来ない為、RDB慣れしてる者にとっては非常にとっつきにくい印象を受けます。


<まとめ>
・CouchDBのインストールはスムーズに完了
・Pythonのコード自体も非常にシンプルに実装可能
・データ挿入のパフォーマンスは???測定不能。Pythonのコーディングの問題??
・RDBに慣れてるものにとっては何だかとっつきにくい

全然RELAX出来ませんでした。むしろいらいらします。


慣れの問題ですかね???
個人的にはMongoDBの方を推奨ですかね。。

2011年3月14日月曜日

Youtubeの動画をFedoraに取り込んでみた

日頃からYoutubeの動画をよく見ています。しかし、
・家のネット環境だと夜間はつながりにくい
・同じ動画を何度も見る
ので、Youtube動画をローカルPC(Linux)に取り込みたいと以前から思っていました。

ふと見た日経Linuxに"clive"というソフトが紹介されていたので試してみました。

記事の内容通りに設定を進めてみます。
尚、以下はFedora13でやってみた結果です。

以下をinstall…
yum install perl-Getopt-ArgvFile
yum install perl-Class-Singleton
yum install perl-HTML-TokeParser-Simple
yum install perl-Digest-SHA
yum install perl-WWW-Curl
yum install perl-Config-Tiny
yum install perl-BerkeleyDB
yum install perl-TermReadKey
yum install perl-ExtUtils-MakeMaker

以下も必要…と書いていましたが、既に入っていた為に割愛しました。
yum install perl-version
yum install perl-URI

以下を実行。
perl Makefile.PL

すると、以下のメッセージが出力されましたが、とりあえずMakeファイルは作成されました。

Checking if your kit is complete...
Looks good
Warning: prerequisite JSON::XS 2.3 not found.
Writing Makefile for clive

あとは以下二つを実行すればどこかにcliveコマンドが作成されてできあがりです。
make
make install

しかし、cliveでいざ取り込もうとすると、エラーとなりました。
clive URL

error: specify path to quvi(1) command with --quvi at /usr/local/bin/clive line 99
    main::init() called at /usr/local/bin/clive line 43
    main::main() called at /usr/local/bin/clive line 40

quviってものが原因だろうと思い、色々とやってみましたが、断念しました。
残念。。。


clive以外のソフトを探してみると、youtube-dlというものを発見しました。
で、以下を実行すればとりあえず簡単に動画のダウンロードまでは完了しました。

yum install youtube-dl
youtube-dl URL

とすればURLに指定されたYoutube動画が.flvファイルとして保存されます。

ですが、、
今度は実際に.flvファイルをtotemというソフトで実行しようとすると以下のエラーとなりました。

(totem:3138): Totem-WARNING **: Failed to create dbus proxy for org.gnome.SettingsDaemon: Could not get owner of name 'org.gnome.SettingsDaemon': no such name
** Message: Error: Your GStreamer installation is missing a plug-in.


これは、他のblogを参考にさせてもらいましたが、以下で回避可能です。
rpm -Uvh http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm
rpm -Uvh http://download1.rpmfusion.org/nonfree/fedora/rpmfusion-nonfree-release-stable.noarch.rpm
yum install gstreamer-ffmpeg gstreamer-plugins-bad gstreamer-plugins-ugly

上記でtotemでローカルに保存した.flvファイルをtotemで見れるようになりました。



まとめ

・Fedoraにcliveを入れようとしたが、うまくインストール出来なかった。しかし、youtube-dlはインストール出来て、Youtubeの動画ダウンロードも出来た。

・ダウンロードした.flvファイルをtotemで見ようとするとそのままの状態では見れない為、追加でinstallする必要がある。

尚、私の環境で使っているとtotemがごく稀にcoredump(異常終了)します。愛嬌ってやつですね。

2011年3月5日土曜日

H2に大量データをinsertしてみた

H2 databaseというDBで大量データinsertをやってみました。
H2のホームページを見ているとDerbyよりも高機能/高速である事を売りにしています。

H2にはDerbyと同様に組込モードとサーバモードの両方が実装されていますが、以下の確認は組込モードのみで実施おり、バージョンは1.3.152です。順序は以下のとおりです。
・H2のページからダウンロード
・CLASSPATHを設定
・ java -cp h2*.jar org.h2.tools.Shell を実行する
(もしくは、 java -cp h2*.jar org.h2.tools.Server)
・コマンドラインからテーブルの作成を実施する
create table hash ( id integer PRIMARY KEY , value varchar(40));
・insert用のCSVネタを準備する
・以下のアプリを実行する
(赤字が修正した箇所です)

import java.sql.*;
import java.io.*;
import java.util.Date.*;
public class H2ins {
        public static void main (String args[]) {
                Connection db = null;
                PreparedStatement ps = null;
                String sql = "insert into hash values(?,?)";
                String url = "jdbc:h2:testdb";
                String usr = "sa";
                String pwd = "";
                BufferedReader br = null;
                int i = 0;
                try {
                        Class.forName("org.h2.Driver");
                        db = DriverManager.getConnection(url,usr,pwd);
                        db.setAutoCommit(false);
                        ps = db.prepareStatement(sql);
                } catch (Exception ex) {
                        ex.printStackTrace();
                }
                java.util.Date d1 = new java.util.Date();
                System.out.println(d1);
                try{
                        br = new BufferedReader(new InputStreamReader(new FileInputStream("neta.csv")));
                        String line;
                        while( (line = br.readLine()) != null ){
                                i++;
                                String[] col = line.split(",");
                                int id = new Integer(col[0]);
                                String value = col[1];
                                ps.setInt(1,id);
                                ps.setString(2,value);
                                ps.executeUpdate();
                                if( i % 10000 == 0) {
                                        System.out.println(i);
                                        db.commit();
                                }
                        }
                        // データベース切断
                        db.commit();
                        ps.close();
                        db.close();
                        br.close();
                } catch (Exception ex) {
                        ex.printStackTrace();
                }
                java.util.Date d2 = new java.util.Date();
                System.out.println(d2);
        }
 }

やってみると約20sで100万件のinsertが完了します。高速だと言う謳い文句は間違っていないようです。

またH2はSqliteを意識しているようで、manual上のAndroidでの実装の箇所でSqliteでは無くH2を使う理由として以下を挙げています。(抜粋)
・参照制約+チェック制約
・豊富なデータTypeとSQL
・他DBMSの互換モード
・完全なUnicodeのサポート
・ユーザ定義関数+トリガー
・全文検索機能
・複数コネクションの許容
・データベースの暗号化

Sqliteの最新では全文検索機能等は存在しているんで、あくまでAndroidでのSqlite実装が古いバージョンで行われているという事なんでしょうか。。しかし、組込モードで複数コネクションの許容とかしてもしょうがないんじゃないかなーー。

何点か補足します。

・ Derbyでも気になりましたが、DBにConnectするタイミングで若干のタイムラグを感じます。何らかの初期処理(Classのロードとか)で時間がかかっているんでしょうかね。尚、insert時間の測定は純粋にinsertの時間のみを測っている為、Connect/Disconnectの時間は含んでいません。

・java -cp h2*.jar org.h2.tools.Shellで最初にDBの接続情報を入力しますが、Useridが自動的に"sa"となります。
(ShellからUserid/Password無にする方法が分かりませんでした)
java -cp h2*.jar org.h2.tools.Server ではuserid/passwordを無として設定できました。