そこで今回は、Cassandraにphpからアクセスしてみたいと思います。
CassandraにphpからアクセスするためのAPIライブラリとして以下のようなものがあるようです。
このうち、Thriftは、Cassandra専用でもPHP専用でもなく、複数の言語間でRPC通信を可能にする汎用フレームワークで、設定コードを元に各言語用のプログラムを生成します。他のライブラリはThriftで生成されたCassandraのlow-level APIをラップしたものになります。
もともとThriftを使おうと思っていましたが、Thriftの最新版 0.8.0は、Cassandra1.1.5では出力されたコードが不十分だったため、一度断念しました。機会があれば再度試してみたいと思います。
今回はphpcassaを試してみました。
phpcassaもThriftを使用しているので、Thriftが組み込まれ、すでにコード生成もされているので、インストールも非常に簡単です。
それでは早速インストールしてみます。
$ cd /usr/local/src $ wget https://github.com/downloads/thobbs/phpcassa/phpcassa-1.0.a.5.tar.gz $ tar xzvf phpcassa-1.0.a.5.tar.gz $ cd phpcassa-1.0.a.5 $ phpize $ ./configure $ make # make install
これでインストールは完了です。
次にアプリケーション用ディレクトリを作成し、phpcassaのライブラリをコピーします。
$ mkdir -p /home/memorycraft/app $ cd /usr/local/src/phpcassa-1.0.a.5 $ cp -r lib /home/memorycraft/app/ $ cd /home/memorycraft/app/ $ touch test.php $ tree -L 2 . |-- lib | |-- autoload.php | |-- phpcassa | `-- thrift `-- test.php
これでライブラリがそろったので、これらを利用してcassandraにアクセスするコードを書いてみます。
$ vim test.php
<?php
    require(dirname(__FILE__).'/lib/autoload.php');
    use phpcassa\ColumnFamily;
    use phpcassa\ColumnSlice;
    use phpcassa\Connection\ConnectionPool;
    try{
        $servers = array('localhost:9160');
        $pool = new ConnectionPool('Hogebook', $servers);
        $user = new ColumnFamily($pool, 'User');
        //データの挿入
        $user->insert('memorycraftgirl',
            array(
                'email' => 'ng@gmail.com',
                'gender' => 'female',
            )
        );
        //データの更新
        $user->insert('memorycraftgirl', array('email'=>'memorycraft+girl@gmail.com'));
        //キーで全カラムを取得  
        $girl = $user->get('memorycraftgirl');
        echo 'girl = ' . print_r($girl, true);
        //キーでカラムを指定して取得
        $email = $user->get('memorycraftgirl', null, array('email'));
        echo 'email = ' . print_r($email, true);
        //複数キーを指定して取得
        $users = $user->multiget(array('memorycraft', 'memorycraftgirl'));
        echo 'users = ' . print_r($users, true);
        //カラムの削除
        $user->remove('memorycraftgirl', array('email'));
        echo 'girl after remove column = ' . print_r($user->get('memorycraftgirl'), true);
        //行の削除
        $user->remove('memorycraftgirl');
        echo 'girl after remove row = ' . print_r($user->get('memorycraftgirl'), true);
        $pool->close();
    }
    catch(Exception $e){
        echo 'ERROR : ' . print_r($e, true);
    }
?>
このコードでは前回作成したHogebookのUserというColumn Familyに対して、挿入/更新/取得/削除を行い、その都度結果や、Column Familyの状態を表示するようにしました。
それでは実行してみます。
$ php test.php
girl = Array
(
    [email] => memorycraft+girl@gmail.com
    [gender] => female
)
email = Array
(
    [email] => memorycraft+girl@gmail.com
)
users = Array
(
    [memorycraft] => Array
        (
            [email] => memorycraft@gmail.com
            [gender] => male
        )
    [memorycraftgirl] => Array
        (
            [email] => memorycraft+girl@gmail.com
            [gender] => female
        )
)
girl after remove column = Array
(
    [gender] => female
)
ERROR : cassandra\NotFoundException Object
(
    [message:protected] => 
    [string:Exception:private] => 
    [code:protected] => 0
    [file:protected] => /home/memorycraft/app/lib/phpcassa/ColumnFamily.php
    [line:protected] => 308
    [trace:Exception:private] => Array
        (
            [0] => Array
                (
                    [file] => /home/memorycraft/app/lib/phpcassa/ColumnFamily.php
                    [line] => 299
                    [function] => _get
                    [class] => phpcassa\ColumnFamily
                    [type] => ->
                    [args] => Array
                        (
                            [0] => memorycraftgirl
                            [1] => cassandra\ColumnParent Object
                                (
                                    [column_family] => User
                                    [super_column] => 
                                )
                            [2] => cassandra\SlicePredicate Object
                                (
                                    [column_names] => 
                                    [slice_range] => phpcassa\ColumnSlice Object
                                        (
                                            [start] => 
                                            [finish] => 
                                            [reversed] => 
                                            [count] => 100
                                        )
                                )
                            [3] => 
                        )
                )
            [1] => Array
                (
                    [file] => /home/memorycraft/app/test.php
                    [line] => 43
                    [function] => get
                    [class] => phpcassa\ColumnFamily
                    [type] => ->
                    [args] => Array
                        (
                            [0] => memorycraftgirl
                        )
                )
        )
    [previous:Exception:private] => 
)
概ね期待通りの動作になっています。
また、存在しないキーを取得しようとすると例外が返る仕様のようです。
前回少し触れましたが、Cassandraはメモリテーブルを使用するため、このテストプログラムを実行したときの感覚としてはmemcacheへアクセスしたときと同じような体感速度でした。
今回は、localhostへのアクセスでしたが、クラスタを形成した場合のパフォーマンスなど、今後さらに調査してみたいと思います。




