今やリレーショナルデータベース全盛の時代である。

どんなシステムもRDBなしには成り立たなくなっている。

しかし、RDBは本当に便利なのだろうか?

例えば、いまはやりのSNSを考えてみよう。

それぞれのユーザーは他のユーザーとネットワーク的につながりをもっている。

そして、そのつながりは友人関係だったり仕事仲間だったりする。

RDBではそれぞれの表の属性もあらかじめ定義される必要があり、後で属性を追加することは難しい。

しかし、SNSのような人間関係を表現するようなもので事前にデータ構造を予測することができるだろうか。

例えば最初は仕事で知り合った人間でも友人になることがあるし、恋人同士だったのが別れてしまって他人同士になってしまうこともあるだろう。

このようなダイナミックなデータ構造はRDBでは表現するのが難しいだろう。

しかし、グラフDBはこのような用途に向いたDBである。

例えば、Todoリストのデータを考えてみよう。

neo4j-011

上図の四角がノードとよばれるものでRDBでいう1レコードのデータを表す。

上の例ではタスク1ノードはタスク名、担当者名、タスク内容、期間という属性をもっていてそれぞれ値をもっている。

また、ノード間はリンクと呼ばれるもので接続される。

リンクは2ノード間の関係を表すものでどういう関係かをリンクの属性によって知ることができる。

ここではNEXTという属性によってタスクの順番を表現している。

このようにグラフDBはRDBとは根本的に違うデータ構造をもっている。

従って問い合わせもSQLではなくグラフをスキャンするAPIでデータを取り出す。

Neo4jはJavaで書かれたグラフDBライブラリである。

Neo4jを使ったプログラム例はこのようになる。

import org.neo4j.api.core.*;

public enum NeoTodoRelationTypes implements RelationshipType {
    NEXT
}
NeoService db = new EmbeddedNeo("var/base");
Node node1 = db.createNode();
node1.setProperty("name", "task1");
node1.setProperty("user", "鈴木");
node1.setProperty("content", "お仕事やってます");
node1.setProperty("due_date", "2009/6/30");
node2.setProperty("name", "task2");
node2.setProperty("user", "田中");
node2.setProperty("content", "あとは引き受けた!");
node2.setProperty("due_date", "2009/7/6");
 Relationship relation = node1.createRelationshipTo(node2,NeoTodoRelationTypes.NEXT);

import文でNeo4jライブラリをインポートしておく。

RelationshipTypeはリンクの属性を表すenumで「次へ」を表すNEXTを属性として持たせる。

EmbeddedNeoはNeo4j DBの初期化を行う。

次のcreateNodeでノードを一つ作成する。

そしてsetPropertyでノードに属性とデータを設定する。

次にノードを二つ作成しcreateRelationshipToでnode1とnode2のリンクを設定する。

これでリンクでつながった2つのノードの作成が完了する。

この要領でノード同士をつないでいけばノードのネットワークが出来上がる。

では、このネットワークからどのようにデータを取り出せばいいのだろうか

Transaction tx = db.beginTx();
try {
    Traverser tr = node1.traverse(Traverser.Order.BREADTH_FIRST,
                           StopEvaluator.END_OF_GRAPH,
                           ReturnableEvaluator.ALL,
                           NeoTodoRelationTypes.NEXT,
                           Direction.BOTH);
    Collection<node> node_list = tr.getAllNodes();
} finally {
    tx.finish();
}

Nodeクラスのtraverse APIでグラフネットワークをスキャンすることができる。

まず最初のノードのtraverseメソッドを呼ぶ。

1つ目の引数はスキャンする順番を指定するもので、BREADTH_FIRSTの意味は同じレベルにあるノードを最初にスキャンしてからより深いレベルのノードをスキャンするという意味である。

2つ目の引数はスキャンを停止する条件を指定する。

END_OF_GRAPHはグラフの最後まで来たら終了するという意味である。

3つ目の引数はどのノードの情報を返すかを指定する。

ALLなので全て返す設定になる。

4つ目はスキャンするリレーションタイプを指定する。

NEXTのリレーションタイプでつながっているノードをスキャンする。

最後はスキャンする方向を指定する

ノードからみてスキャンが他から入ってくる方向の場合はINCOMING、出て行く方向の場合はOUTGOINGとなる。

BOTHは両方の方向でのスキャンを指定する。

traverse実行後getAllNodesを呼ぶとスキャンされたノード情報がCollectionとして取得することができる。

後はイテレータで各ノードの情報をとればよい。

事前にデータ構造を決定することができてデータの整合性が重要なシステムにはRDBを使うべきだろう。

しかし、データ構造がダイナミックに変化するシステムではグラフDBを使った方が効率よく開発することができる。

これからは用途に合わせてデータベースも選ぶ時代になりつつあるのではないだろうか。

今、話題のクラウドサービスで一番有名なAmazon EC2を使ってみた。
まずはアカウントを登録する必要がある。

登録方法に関しては以下のページを参考にした。

「Amazon EC2」と「Amazon S3」を実際に使ってみたので、まずはアカウント作成まで」

「Amazon EC2」と「Amazon S3」を実際に使ってみた、今度はEC2の操作環境セットアップ

登録も済んでAccess KeyとSecret Access Keyを取得できたらEC2管理用FirefoxプラグインElastics Foxをこちらからダウンロードする。
ElasticFoxプラグインをインストールしてメニューの「ツール」-「Elasticfox」を選択すると下の画面が表示される。

elasticfox11.gif

ツールバーの下にある「Credentials」ボタンを押すと下図のようにダイアログボックスが表示される。

elasticfox2.gif

「Account Name」に登録したアカウント名、「AWS Access Key」と「AWS Secret Access Key」に取得したアクセスキーとシークレットアクセスキーを入力する。
「Add」ボタンを押してダイアログを閉じる。

「Machine Images (AMIs) 」タイトル下の一番左のRefleshボタンを押すとOSイメージの一覧が表示される。

elasticfox3.gif

次にsshでアクセスするための秘密鍵の生成を行う。
Elasticfoxの画面の「KeyPairs」タグをクリックすると秘密鍵を作成する画面が表示される。
タブ下の緑の鍵印ボタンを押すとKeypair名を入力するダイアログが出る。

elasticfox4.gif

Keypair名を入力してOKボタンを押すと秘密鍵ダウンロードのダイアログが表示される。
elasticfox5.gif

保存ボタンを押すとPCに秘密鍵ファイルがダウンロードされる。
作成したKeypairがリストに表示される。
elasticfox6.gif

次にセキュリティルールを設定する。
「Security Groups」タブをクリックする。

elasticfox9.gif

「Group  Permission」にあるGrantPermissionボタン(緑のチェック)をクリックするとプロトコルごとのセキュリティルールを設定するダイアログが表示される。

elasticfox10.gif

sshアクセスを許可するネットワークアドレスもしくはホストアドレスを設定する。
またhttpはどこからでもアクセスできるように設定する。

次にOSを起動する。「AMI and Intances」タブをクリックして好きなOSイメージを選択する。
タブ下の緑の起動ボタン(丸に縦棒のアイコン)をクリックすると以下のダイアログが表示される。
elasticfox7.gif

「Keypair」コンボボックスで先ほど作成したKeypaire(sample_key)を選択して右下の「Launch」ボタンを押す。
下のリスト「Your Instances」リストに起動したOS インスタンスが表示される。
2〜3分するとStateがpendingからrunningに変わる。
その後、sshで起動したOSにアクセスする。
「Your Instances」のOSイメージエントリーを右クリックして「Copy Public DNS to Clipboard」を選ぶとサーバーDNS名がコピーされる。

MacまたはLinuxからアクセスする場合はダウンロードした秘密鍵を sshコマンドで以下のように指定する。

# ssh -i 秘密鍵ファイルへのパス root@サーバーDNS名

ログインしたら通常のLinuxの操作を行うことができる。

login1.gif

常識なのかもしれないが、コーディングしていて改めて気がついたのでメモ。

文字列の数字表現で”1234.56″といった感じのものを読んで整数なのか小数なのかをチェックする場合、マッチさせたいパターンは詳細なものから書く。
例えば以下のように書くと

全て整数として判断される。
このような場合は正規表現のより詳細なものから先に書いておく必要がある。

こうすれば小数は小数としてマッチするようになる。
もっとスマートなやり方があればコメントしていただきたい。

Rubyでは実行時にメソッドの動きを変更することができる。

例えば次のようなクラスをperson.rbというファイルに記述する。

次にchained_person.rbというファイルに次のように記述する。

aliase_methodでperson.rbのfunc1メソッドにfunc1_without_chainedという別名をつけて、次の行でfunc_with_chainedメソッドをfunc1メソッドとするように指定する。
そしてメインの処理を記述するファイルには以下のようにする。

これで環境変数CHAINEDに値が入っている場合はchained_person.rbのメソッドが呼ばれるようになる。
これはデバッグや違う環境でメソッドを変えたい場合にその部分だけ別ファイルに分離することができるので便利だ。

参考文献

実践 Rails -強力なWebアプリケーションをすばやく構築するテクニック 実践 Rails -強力なWebアプリケーションをすばやく構築するテクニック
株式会社クイープ

オライリージャパン 2008-10-27
売り上げランキング : 3881

Amazonで詳しく見る by G-Tools

Ubuntu 7.10 Subversionインストールメモ。
以前もSubversionのインストール方法は書いたのだが、今回はWebDAVを使うパターン。

まず以下のソフトウェアをインストールする。
(Apache2は入っているものとする)

# apt-get install subversion libapache2-svn

次にWebDAVの設定ファイルを編集する。

# sudo vi /etc/apache2/mods-enabled/dav_svn.conf

dav_svn.confに以下のように記述する。

<Location /svn_repos>
DAV svn
SVNPath /home/svn/repos

AuthType Basic
AuthName “Subversion Repository”
AuthUserFile /etc/apache2/dav_svn.passwd
Require valid-user
</Location>

LocationでアクセスするURLを指定し、SVNPathでsubversionのリポジトリディレクトリがあるところを指定する。

AuthTypeでベーシック認証を設定し、パスワードファイルのパスをAuthUserFileとして設定する。

パスワードファイルはhtpasswdコマンドで以下のように作成する。

# htpasswd -c dav_svn.passwd hoge

-cオプションはファイルを作成するときだけ使用する。

Subversionのリポジトリは以下のコマンドで作成する。

# sudo mkdir /home/svn
# sudo svnadmin create /home/svn/repos

ApacheがSubversionファイルを読めるようにwww-dataユーザーにファイルオーナーを変更しておく。

sudo chown -R www-data /home/svn

変更を有効にするためにapacheを再起動する。

sudo /etc/init.d/apache2 restart

Tortoise SvnなどのSubversionクライアントでhttp://ホスト名/svn_reposというURLでアクセスして確認する。

データベース設計でER図を描くのにWindows上でDia(0.96.1)を使っているのだが思いっきりはまってしまった。

1時間ほどかけて作ったER図が保存したにもかかわらずファイルにちゃんと書かれていなかった。
セーブしたファイルを見るとサイズが0になっている。
色々試してみた結果ファイルパスに日本語が含まれているとだめみたいだ。
ちなみに図に日本語を入れるのは問題ない。

DiaはもともとGnomeのアプリケーションだから日本語ファイル名を想定して作られていないのだろう。
まだちゃんと日本語対応していないのもあると思うが。
しかし、これからのGUIアプリケーションは Linuxといえどマルチバイトのファイル名は必須ではないだろうか。
せっかく作ったER図をまた一から作らなければ。

LinuxのWebサーバー経由でWindows 2003サーバーのコマンドをRubyスクリプト起動する 方法としてSSH経由で実行することを考える。

まずはWindows 2003サーバーにCygwinをインストールしてその上でsshdを起動させる。
/etc/sshd_configはデフォルトのままにしておく。
sshdデーモンを以下のコマンドで起動しておく。

# cygrunsrv -S sshd  (停止するにはcygrunsrv -E sshd)

Linuxサーバー側のRubyスクリプトを実行する。
ソースコードはこんな感じ。

rubygemsをrequireしないとnet/sshが読み込めないというエラーが発生した。
またこのライブラリではsshの中でコマンド一発実行すると終了してしまうのでsession.loopという関数で複数コマンドを実行できるようにしている。
Windowsのバッチファイルを実行するためにはcmd .. callというコマンドで実行する必要があるようだ。
コマンドだけではcygwinからうまく実行できなかった。
バッチファイルで呼んでいるコマンドによるのかもしれない。

Ubuntu 7.04 Serverにrcovをインストールしようとしてエラーが発生。

stdlib.hが見つからないというエラーを出していた。

ネットで調べてみるとbuild-essentialを入れれば大丈夫のようだ。

apt-get install build-essentialと打つがこんなエラーが発生。

エラー http://jp.archive.ubuntu.com gutsy-updates/main linux-libc-dev 2.6.22-14.47
404 Not Found
エラー http://security.ubuntu.com gutsy-security/main linux-libc-dev 2.6.22-14.47
404 Not Found
http://security.ubuntu.com/ubuntu/pool/main/l/linux-source-2.6.22/linux-libc-dev_2.6.22-14.47_i386.deb
の取得に失敗しました 404 Not Found
E: いくつかのアーカイブが取得できません。apt-get update を実行するか –fix-missing オプションを付けて試してみてください。

色々ネットで調べてみるとapt-getのdbをアップデートすればいいみたいだ。

# sudo apt-get update

# sudo apt-get install build-essential

うまくいった。

さらにrcovをインストール。

# sudo gem install rcov

Ubuntu Feistyにsubversionをインストール、設定にはまった。

まずはバイナリーのインストールは
apt-get install subversion
ですんなり終了。

subversion用のユーザーを作成
useradd -d /home/svn -s /bin/bash svn
でsvnユーザーでログインしなおす。
su – svn

リポジトリの作成を行う。
svnadmin create /var/svn/repos

既存のソースをリポジトリにインポート
svn import -m ‘initial import’ mysrc file://var/svn/repos/mysrc

リモートからアクセスしたいのでsvnserveの設定を行う。
/var/svn/repos/mysrc/conf/svnserve.confを以下のように記述。
anon-access = none
auth-access = write
password-db = passwd
authz-db-authz
realm= My Source Repository

anon-accessは匿名ユーザーのアクセスを禁止しているのだが、noneにしておかないと許可しているユーザーのアクセスのときに変なエラーがでてアクセスが拒否されてしまった。
Googleで調べるとここをnoneにしろと書いてあったがなんかバグらしい。
とりあえずこれでアクセスできた。

同じディレクトリにpasswdファイルを作成し以下のような感じでアクセスさせたいユーザー名とパスワードを記述。

user1 = pass1
user2 = pass2

パスワードはクリアテキストで通常のパスワードファイルのようにハッシュになっていない。
(大丈夫か?)

これでsvnserveを以下のように起動。

svnserve -d -r /var/svn/repos

-dはデーモンモードで起動するオプションで、-rはリポジトリディレクトリを指定する。
-rで指定しないとリモートでアクセスできなかったので必ず指定しなければいけないのだろう。

後はクライアントから以下のコマンドでアクセスしてみる。

svn checkout svn://svnホスト名/mysrc dir1

リポジトリのファイルがクライアントのdir1というディレクトリにダウンロードされる。
これでクライアントローカルでファイルの変更が可能になる。
変更後svn statusで見ると変更されたファイルリストが表示されるはずだ。

M aaa.c
M bbb.pl

変更されたファイルをsvnサーバーのリポジトリに反映させるにはcommitコマンドを使う。

svn commit aaa.c bbb.pl

アクセス制御の設定をちゃんとしておかないとここで拒否される。
自分はここではまって何回もリポジトリを作りなおしたり、設定ファイルの変更を行った。
svnserveの起動ユーザーとリポジトリファイルのオーナーがあっていないとアクセスエラーになってしまうので注意が必要だ。
root権限でsvnserveを起動するのは危険なのでsvnユーザーのようにsubversion専用のユーザーを作成し、そのユーザーでsvnserveを動かした方がいいだろう。

今日は半日これをずっとやっていて疲れた。
次はWebDAV経由でアクセスできるように設定しないと。

Javascriptでの複合データオブジェクトはこんな感じで書くことができる。

var data= { people :
{ name : "Taro Yamada",
address: "Tokyo Japan",
sikaku : [ ]
},
{ name : "Taro Yamada",
address: "Tokyo Japan",
sikaku : [ ]
}
};

ここでsikaku配列に後からオブジェクトを追加したいと思って以下のようにやると連想配列のキーが消えてしまった。

var tuika_sikaku = "{oraclemaster : \"gold\"}";
data['people']['people].each(function(s){
s.sikaku[0] = eval(tuika_sikaku);
}

これはtuika_sikakuをevalしてオブジェクト化してから配列に入れているのだが、tuika_sikakuの記述がまちがっているためにキーが消えてしまった。
正しくは
var tuika_sikaku = “({oraclemaster : \”gold\”})”;
( )が必要である。