akishin999の日記

調べた事などを書いて行きます。

Ruby から Cassandra を使ってみる その3

Windows から Ruby で Cassandra を使うための準備
Ruby から Cassandra を使ってみる
Ruby から Cassandra を使ってみる その2


の続きです。

Twissandra

Cassandra 自体の操作にも大分慣れてきたので、そろそろ具体的なアプリケーションでも作ってみようかな、と思ったのですが、データモデルが RDBMS と異なるので、今一つ勘所が掴めません。

特に RDBMS の時は MySQL の auto increment 値や Oracle の SEQUENCE をレコードの主キーとして使用してましたが、そういった一意の値を Cassandra ではどうやって作成するのか、どうにもイメージがわきません・・・。

こういう時は具体的なアプリケーションの設計に学ぶのが一番なので、Cassandra を使ったオープンソースPythonTwitter クローン、Twissandra のスキーマ定義を見てみました。


viksit's twissandra at master - GitHub
http://github.com/viksit/twissandra


GitHub の Twissandra のページから storage-conf.xml を見てみると、Keyspace は以下のように定義されていました。
(コメントは省略しています。)

<Keyspace Name="Twissandra">
  <ColumnFamily CompareWith="UTF8Type" Name="User"/>
  <ColumnFamily CompareWith="BytesType" Name="Username"/>
  <ColumnFamily CompareWith="BytesType" Name="Friends"/>
  <ColumnFamily CompareWith="BytesType" Name="Followers"/>
  <ColumnFamily CompareWith="UTF8Type" Name="Tweet"/>
  <ColumnFamily CompareWith="LongType" Name="Timeline"/>
  <ColumnFamily CompareWith="LongType" Name="Userline"/>
  <ReplicaPlacementStrategy>org.apache.cassandra.locator.RackUnawareStrategy</ReplicaPlacementStrategy>
  <ReplicationFactor>1</ReplicationFactor>
  <EndPointSnitch>org.apache.cassandra.locator.EndPointSnitch</EndPointSnitch>
</Keyspace>


これだけでは実際のカラムがどのような構造になっているのか分かりませんが、Twissandra のページの「Schema Layout」の項目に、スキーマの詳細な説明も載っていました。

どうやら「User」カラムファミリでは一意の ID として UUID を使用し、その UUID とユーザ名を関連付けるために「Username」というカラムファミリを使っているようです。


なるほど。
これなら覚えやすいユーザ ID を使いつつ、Cassandra 上でもレコードを一意に識別する事ができますね。

Python のコードも慣れないながらなんとなく読んでみましたが、そのような実装になっているようでした。


という訳で、上記のスキーマを定義し、ユーザの登録と取得を行う以下のようなサンプルコードを書いてみました。

#!/usr/bin/ruby
require 'rubygems'
require 'cassandra'
require 'simple_uuid'

include SimpleUUID

@client = Cassandra.new('Twissandra', 'localhost:9160')

#
# ユーザ登録を行う。
#
def save_user(name, password)
  # username からまずは Username を取得
  username = @client.get(:Username, name)

  # 指定されたユーザ名が存在しなければ登録する
  if username.empty?
    id = UUID.new.to_guid.to_s
    @client.batch {
      # UUID をキーに User を登録
      @client.insert(:User, id, { 'id' => id } )
      @client.insert(:User, id, { 'username' => name } )
      @client.insert(:User, id, { 'password' => password } )
      # User に登録した username をキーに UUID(id) を登録
      @client.insert(:Username, name, { 'id' => id } )
    }
  end
end

#
# ユーザ名からユーザを取得する。
#
def get_user_by_username(name)
  # username からまずは Username を取得
  username = @client.get(:Username, name)

  @client.get(:User, username['id'])
end

name = 'akishin'
password = 'passowrd'

# ユーザ登録
save_user(name , password)

# ユーザ名からユーザを取得
user = get_user_by_username(name)

p user


実行結果は以下のようになります。

#<OrderedHash {"username"=>"akishin", "id"=>"cf83bdc8-5dec-11df-9150-ac71873ed3de", "password"=>"passowrd"}>


無事ユーザ名から User レコードが取得できました。

これで Cassandra を使ってログインが必要なシステムも作れそうですね。

参考


up and running with cassandra :: snax
http://blog.evanweaver.com/articles/2009/07/06/up-and-running-with-cassandra/


DataModel_JP - Cassandra Wiki
http://wiki.apache.org/cassandra/DataModel_JP