RailsからCassandraデータベースを利用してみる

前回,前々回の記事で,Amazon EC2 AMI Linux に Apache Cassandra 及び Ruby on Rails の環境をセットアップしましたが,今回は,とりあえずの目標であるRailsからCassandraを利用してみようと思います.

ここで利用するのはcassandra-rbというGemです.RubyからCassandraデータベースを利用する為のバインダになります.

cassandra-rb/cassandra · GitHub

これを利用する為に,Gemfileに次の行を追記します.

gem 'cassandra'

そして,「bundle install」
(前回「–path vendor/bundle」オプションをつけて実行しましたので,Railsアプリケーションのディレクトリ(カレントディレクトリ)配下のvendor/bundle配下にインストールされます.

$ bundle install
 :
Installing simple_uuid (0.4.0)
Installing thrift (0.8.0)
Installing thrift_client (0.8.4)
Installing cassandra (0.23.0)
 :

とりあえず,Railsコンソール(irb)で動作確認してみます.

$ bundle exec rails c

前々回作成したCassandraデータベースの「demo」キースペースに接続して,Cassandraオブジェクトを生成します.

irb> cli = Cassandra.new("demo", "127.0.0.1:9160")
=> #<Cassandra:69828286243420, @keyspace="demo", @schema={}, @servers=["
127.0.0.1:9160"]>

keyspacesメソッドによりキースペースの一覧を出力します.

irb> cli.keyspaces
=> ["system", "system_traces", "demo"]

前々回作成した「students」カラムファミリーのローキー「123450」を指定して,要素を取り出してみます.

irb> a = cli.get(:students, '123450')
=> #<OrderedHash {"e_mail"=>"taro@kago.jp", "full_name"=>"Taro Kagoshima"}
{"e_mail"=>1387164677544000, "full_name"=>1387164658381000}>

戻り値オブジェクトのa(ハッシュ)より,各カラム情報を取り出してみます.

irb> a["full_name"]
=> "Taro Kagoshima"

irb> a["e_mail"]
=> "taro@kago.jp"

今度は,データ(行)を追加してみます.

irb> cli.insert(:students, '123452', {"full_name" => "Taka Saigo", "e_mail" => "taka@kago.jp"})
=> nil

再度,getメソッドで確認してみます.

irb> cli.get(:students, '123452')
=> #<OrderedHash {"e_mail"=>"taka@kago.jp", "full_name"=>"Taka Saigo"}
{"e_mail"=>1387245372655767, "full_name"=>1387245372655767}>

Cassandraデータベースは,ActiveRecordに対応していないので,SqliteやMySQLのように,database.yml にちょろっと書いてすぐORM(Object-Relational Mapping)が利用できるわけではありません.一応,次のサイトにあるように色々なバインダがあり,ちょっと使ってみましたが,ずいぶん長い間アップデートされていなかったりで,特にこれといったものがないように思います.

Rails ORM for Cassandra – Stack Overflow

そこで,単にcassandra-rbを直接利用する形で行ってみます.

Cassandraオブジェクトを利用するために,Cassandraクラスのサブクラス(ここでは「Demo」)を定義します.そこで,そのクラスをシングルトンクラスにすると,唯一のインスタンスを自身で作成してくれます.とりあえず,試験的ですから簡単に次のように作成しておきます.modelクラスではないので,libディレクトリに作成します.

class Demo < Cassandra
  include Singleton

  def initialize
    super('demo', '127.0.0.1:9160')
  end
end

libディレクトリをパスに含めるために,application.rbに次の行を追記します.

require File.expand_path('../boot', __FILE__)
require 'rails/all'
 :
module Sample
  class Application &lt; Rails::Application
   :
    <strong>config.autoload_paths += Dir[Rails.root.join('lib').to_s]</strong>
   :
  end
end

また,irbで確認してみます.

$ bundle exec rails c

まずは,instanceメソッドで,シングルトンクラスのインスタンスを作成します.

irb> obj = Demo.instance
=> #<Cassandra:70342759918100, @keyspace="demo", @schema={}, @servers=["
127.0.0.1:9160"]>

もちろん,この結果Cassandraオブジェクトが得られるので,keyspacesメソッドやgetメソッドももちろん使えます.

irb> obj.keyspaces
=> ["system", "system_traces", "demo"]
irb> obj.get(:students, '123450')
=> #<OrderedHash {"e_mail"=>"taro@kago.jp", "full_name"=>"Taro Kagoshima"}
{"e_mail"=>1387164677544000, "full_name"=>1387164658381000}>

それでは,modelクラス(ここでは「Studentクラス」)を次のように定義して,ActiveRecordのように,find_by_***メソッドやallメソッドを実装してみます.

class Student
  @obj = Demo.instance

  def self.find_by_key(id)
    @obj.get(:students, id)
  end

  def self.all
    ret = {}
    chash = @obj.get_range(:students)
    chash.each_pair do |k, v|
      ret[k] = {}
        ret[k][:e_mail] = v["e_mail"]
        ret[k][:full_name] = v["full_name"]
      end
    ret
  end
end

もっとスマートな方法があると思うのですが,まずは使えれば良いということで....

irbで確認します.

$ bundle exec rails c
irb> Student.find_by_key('123450')
 => #<OrderedHash {"e_mail"=>"taro@kago.jp", "full_name"=>"Taro Kagoshima"}
 {"e_mail"=>1387164677544000, "full_name"=>1387164658381000}>

irb> students = Student.all
=> {"123450"=>{:e_mail=>"taro@kago.jp", :full_name=>"Taro Kagoshima"}, "123452"
=>{:e_mail=>"taka@kago.jp", :full_name=>"Taka Saigo"}, "123451"=>{:e_mail=>"han
a@satsuma.org", :full_name=>"Hanako Satsuma"}}

irb> pp students
 {"123450"=>{:e_mail=>"taro@kago.jp", :full_name=>"Taro Kagoshima"},
 "123452"=>{:e_mail=>"taka@kago.jp", :full_name=>"Taka Saigo"},
 "123451"=>{:e_mail=>"hana@satsuma.org", :full_name=>"Hanako Satsuma"}}

これで,結果をハッシュで取得可能になりましたので,controllerクラス(ここでは「StudentsControllerクラス」とview(index.html.erb)を作成して,Webブラウザで結果が表示できるようにしてみます.

次のコマンドで,必要なディレクトリやファイルを生成してくれます.

$ bundle exec rails g controller Students index
class StudentsController < ApplicationController
  def index
    @students = Student.all
  end
end
<h1>Students#index</h1>
Find me in app/views/students/index.html.erb
<table>
  <tr>
    <th>ID</th>
    <th>full_name</th>
    <th>e_mail</th>
  </tr>
<% @students.each_pair do |key, value| %>
  <tr>
    <td><%= key %></td>
    <td><%= value[:full_name] %></td>
    <td><%= value[:e_mail] %></td>
  </tr>
<% end %></table>

ルーティングは先ほどのコマンド「rails g」で自動的に設定されています.

Sample::Application.routes.draw do
  get "students/index"
 :
 end

ルーティングを確認してみます.

$ bundle exec rake routes
 Prefix Verb URI Pattern Controller#Action
 students_index GET /students/index(.:format) students#index

URL「students/index」でGETすると,studentsコントローラのindexメソッドが呼ばれ,その結果がindex.html.erbのテンプレートによって結果が画面表示されます.

Railsサーバを起動します.

$ bundle exec rails s

WebブラウザからURL「http://(ホスト名):3000/students/index」でアクセスしてみます.

ss.png

広告

One thought on “RailsからCassandraデータベースを利用してみる

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中