2010年06月29日

cassandra(悲劇の預言者)をPHP5で使ってみる。

cassandraのPHP用のソースはPHP4用らしく、実行時に以下のようなエラーが出ることがあります。

Object of class cassandra_ColumnOrSuperColumn could not be converted to string in ~~~

これはPHP4では自動で呼び出されていた__toString()メソッドがPHP5ではエラーとして扱われるようになったことから起こるエラーです。

なので、該当クラス(この場合はcassandra_ColumnOrSuperColumn)に__toString()メソッドを追記してあげればいいようです。

私は暫定的に以下のようなコードを追記しました。


//追加
public function __toString(){
if ($this->column->name != null){
return $this->column->name;
}
if ($this->super_column->name != null){
return $this->super_column->name;
}
}

CentOSでThriftインストール時のエラー

 CentOSでWikiの手順どおりするThriftをインストールするとエラーがでます。
 
configure.ac:50: error: possibly undefined macro: AC_PROG_MKDIR_P
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
configure.ac:147: error: possibly undefined macro: AC_TYPE_INT16_T
configure.ac:148: error: possibly undefined macro: AC_TYPE_INT32_T
 
 
 ここを参考に解決しました!
 http://d.hatena.ne.jp/lion_and_perican/


$ ./configure
$ make
$ make install

$ thrift -version
Thrift version 0.2.0-exported

 Wikiの手順から./bootstrap.shを実行しないようにしています。
 もし一回実行していたら、ソースディレクトリを削除の上、解凍からやり直してみてください。

2010年06月25日

cassandra(悲劇の預言者)に過去データを覚えてもらう。


 さて、1300万レコードを覚えてもらうわけですが、その前に。
 この大量のレコードは情報の極ごく一部です。これはテスト用に貰った5日分データであり、本番は365日×事業者数のデータ量になります。
 なので、この時点で指数乗的に検索時間が増えて行くRDBでは無理になってしまったのです。
 それがcassandraなら比例的な検索時間の増加で済む(らしい)です。

 でもcassandraは「LIKE検索」とか「WHERE検索」とか出来ません(たぶん)
 飽く迄Keyと列で指定された行のValueを取得するだけです。

 じゃあ、どうすればいいのか?というところですが、以下のページがそこそこ分かりやすく説明してくれています。
 
Cassandraで登録しているカラムデータの検索方法(Cassandra:inverted indexの翻訳)

 私がざっくり説明すると「自分で検索用インデックスを作ってね」ということです。
 
 なんということでしょう!
 
 データベースの一部の機能を自前で用意する必要があるのです。
 これはデータベースマニアには堪らないですね。
 でも、残念ながら私はデータベースマニアではないので、あまりうれしくありません。

 それでもここを考えないと進みませんので仕方ないですが、考えます。
 
■1レコードの情報
・オブジェクトID
・時刻
・月
・日
・時
・曜日
・休日フラグ
・天気
・ステータス(%)

 時刻とその他の情報が重複しておりますが、この辺はあとで検索に使いたいので必要になります。
 例えば、「あるオブジェクトIDの日曜日の14時~18時のステータスの平均」とかそういう指定で集計する必要があるのですね。

 まずはインデックス以外のデータ部分を考えます。
 Keyとして登録する必要があるのは「オブジェクトID+時刻」となります。
 データ部分は「月~ステータス」まで普通に登録しましょう。

 次にインデックスをどの情報で持つかを考えます。

■検索するためのインデックス条件
・オブジェクトID
・月
・日
・時
・曜日
・休日フラグ
・天気

 これらに1つずつ登録してもいいのですが、これだと「AND検索」したときにアプリケーション側ですることが多すぎます。
 それに月だけ指定して取得した場合、確実に1300万レコードとか拾ってきそうです。
 仮にどんなに良いマシンを使っても処理が終わる気がしません。

■登録するインデックス
・月→12通り
・日→31通り
・時→24通り
・曜日→7通り
・休日フラグ→2通り
・天気→晴れ、曇り、雨、雪の4通り

 となり、これらの検索条件としてKeyに「Month=7」と指定したレコードを別途作るわけですね。
 で、カラムに「day=12」としたものを作り、valueに「オブジェクトID+時刻」でデータを登録しておき、データ全体を呼び出せるようにしておくわけですね。
 これならば2通りまでの組み合わせなら対処できそうです。
 あとは事前にcassandraの設定が必要になりますが、ColumnFamilyを設定すれば更に3通りの組み合わせに対処できます。
 
 いずれの場合もほぼ自動でインデックス作成ルーチンを組むことが可能です。
 
 Keyspace1.ColumnFamily1.SuperColumn1['key']['column']

 となっているので、実際には、以下のような指定で値をセットしたり、取得したりします。
 
 Keyspace1.Month=04.Day=15['ObjectID=ID0001']['Kindofday=Mon']=【IDリスト】
 
 うーむ、Column名に「=」が使えるのか。
 また取得範囲が広い場合は、絞り込むことも可能だそうです。そこは実際にデータを入れてから取得するときに考えたいと思います。

2010年06月24日

cassandra(悲劇の預言者)をPHPで使ってみる。


 さて、さっきのページはJavaから使う前提で書かれていましたので、私のホームグラウンドであるPHPで使う方法を調べます。
 なぜPHPで作る必要があるかというと生産性が段違いだからです!
 I/FはWEBブラウザになる予定なので、HTMLタグを使いやすくするためです。
 また集計作業は複雑なものではないので、PHPの関数だけで十分です。Javaとかバイナリファイルを使わない限りあまり必要はありません。
 
 PHPで使うにはまずはthriftというフレームワークをインストールする必要がありそうです。
 
cassandraに挑戦 その8 thriftのインストール

 でも、ここに書いてあるのも他のページに書いてあるのもLinuxが前提です。
 Windowsでthriftをインストールできないものか……。
 Cygwinでビルドとか嫌です。そもそもWindows用にビルドしなおすとか文化があいません(キリ
 で、探していたらコンパイル済みのバイナリを見つけましたw

WindowsでThriftコマンドを使用する

 次はPHP-APCをインストールする必要があります。
 PHPのアクセラレータの1つらしいですね。これもLinuxなら簡単なのですが、Windowsでは安定的な方法がなかなかない。
 いくつかのページを調べてみると、以下のようなバイナリファイルと設定が見つかりました。

PHP APC for Windows Download


①上記のページのファイルをダウンロードし、php_apc_3_0_19.dllをphp5/extフォルダへコピー
②php.iniに以下の設定を書き加えます。

[apc]
extension=php_apc_3_0_19.dll
apc.enabled=1
apc.shm_segments=1
apc.shm_size=48
apc.ttl=7200
apc.user_ttl=7200
apc.num_files_hint=1024
apc.mmap_file_mask=NULL
apc.enable_cli=1


 が!しかし。xamppにはすでにAPCがインストールされていたことが判明。
 php.iniのextension=php_apc.dllを有効にします。

 さて、これで準備は整いましたのでPHPからcassandraを使ってみたいと思います。
 まずはcassandraのサーバーを起動。

cassandraに挑戦 その10 PHP Clientを動かしてみる

 の中にあるテスト用のコードをダウンロードします。
 そして、一番最初にある
 
$GLOBALS['THRIFT_ROOT'] = '/usr/share/php/Thrift';

 をWindows用に書き換えます。

$GLOBALS['THRIFT_ROOT'] = 'C:/Thrift';

 あ、でもその下にある「Thrift.php」がそのフォルダにないな……。
 調べてみるとThrift自体のソースコードに含まれている模様。
 
 http://ftp.riken.jp/net/apache/incubator/thrift/0.2.0-incubating/thrift-0.2.0-incubating.tar.gz
 
 からダウンロードしました。
 
 ~~Downloads\thrift-0.2.0\lib\php\srcフォルダの中身をC:\Thriftフォルダへコピーします。
 まだ足りないww
 package/cassandra/Cassandra.phpもありません。
 
Using Cassandra with PHP

 の「4.Build the PHP Thrift interface for Cassandra:」をすればできそうです。
 
 C:\Thrift>Thrift -gen php C:\cassandra/interface/cassandra.thrift
 
 Windows用になおして実行!
 C:\Thrift\gen-php\cassandraフォルダが出来たのでこれをC:\Thrift\packagesフォルダへコピーします。
 
 これで「整いました~」
 
 C:\xampp\php>php cassandra_test.php
 
 CLIでエラー……。
 なぜでしょうか?
 
 http://localhost/cassandra_test.php

 を実行してみたら普通に通りました。動きましたよ!
 これでよしにしておきましょうw

cassandra(悲劇の預言者)をWindowsで使ってみる。

 あれです。
 現在テストで1300万を超えるレコードを一括処理する必要が出てきています。
 集計作業をするにしてもデータベースに入れようものならデータベースから1分経っても反応が返ってこなくなります……。
 できればこれをリアルタイムで集計したいのです。使える環境は4年前現役だったノートパソコン1台。これがお金を取る仕事だったら断っていますが、空いた時間にやる投資的なお仕事なので、超時間を掛けてやってみようと思います。

 まずはMySQLの1テーブルに突っ込んでみました。
 ……phpMyAdminが応答がなくなり、最終的にはタイムアウトエラーを吐く様になりました。
 タイムアウトしないようにすればいいのですが、1分以上待つような処理も嫌だなと考え、その案は保留にいたします。
 
 次はMySQLに1万テーブルぐらいに分けて登録してみました。
 テーブル名を表示する時点でタイムアウトエラーを吐くようになりました。もっと酷くなったw

 ここまででRDBでは無理な問題だと気がつきます。
 というか、別段RDBである必要はどこにもありません。1レコードに登録された列ごとの関係を集計できればいいだけなので、SQLも極単純な集計しかしません。
 JOINなんか一切必要ないです。

 これが1ヶ月ほど前のことです。
 で、調べていくうちにGoogleのBigTableというのに行き当たり、その技術や思考に感心しながら「これならできるんじゃね?」的な感触を受けました。
 でも、BigTableは一般のヒトは使えない。GAEを使えばいいのですが、Giga級のデータを転送することを考えると費用が嵩みそうです。
 
 自前で作ろうかどうか考えていると、オープンソースのBigTableがすでに使える状態にあることがわかりました!
 それがApacheのトップレベルプロジェクト【cassandra】だったわけですね!
 
 
 さて、環境はWindowsなので、それで設定する方法を探しました。
 先人がすでにやってくれてましたので、参考にします。
 
Windows で Cassandra を動かしてみる
 
 この手順のうち、

「コマンドプロンプトより Cassandra を展開したディレクトリに移動し、「bin/cassandra.bat」を実行します。」

 ではやくもエラー。

「JAVA_HOME environment variable must be set!」

 設定しないとダメだそうです。

JAVA_HOMEの設定

 を見て設定しました。

 再度「bin/cassandra.bat」を起動すると動きました!
 同様にしてクライアントも起動すると動作しているようです。
 
 コマンドも無事通りました。
 cassandraの設定は完了のようです。
 設定で色々苦労すると思っていただけにこのセットアップの簡単さはいいですね。流石トップレベルプロジェクトです。plaggerもこれぐらいに便利になればいいのに!