プログラマでありたい

おっさんになっても、プログラマでありつづけたい

RubyとCassandraの連携のサンプルプログラム

 先日インストールしたCassandraを、Rubyから使ってみようと思います。
gemで用意されているのかなと期待したら、やっぱりありました。幸せ

インストール

# gem install cassandra
 中略
Installing RDoc documentation for thrift_client-0.4.2...
Installing RDoc documentation for rake-0.8.7...
Installing RDoc documentation for simple_uuid-0.1.1...
Installing RDoc documentation for cassandra-0.8.2...

サンプルコード

require 'rubygems'
require 'cassandra'
include Cassandra::Constants

keyspace = Cassandra.new('Keyspace1')

#保存
first_name = {'first' => 'Key'}
last_name = {'last' => 'Smith'}
age = {'age' => '35'}
keyspace.insert(:Standard2, 'ksmith', first_name)
keyspace.insert(:Standard2, 'ksmith', last_name)
keyspace.insert(:Standard2, 'ksmith', age)

#取得
p keyspace.get(:Standard2, 'ksmith')


実行

# ruby cassandra_sample.rb
#"Smith", "first"=>"Key", "age"=>"35"}>

解説っぽいもの

Cassandra単体のデータ構造は、Keyspace > (Super)ColumnFamily > Columnになっています。
上記の例では、まずKeyspace1のインスタンスを作成しています。
そして、それぞれのカラムを用意して、keyspace1のStandard2というColumnFamilyにデータを入れていっています。
このColumnFamilyのキーは、'ksmith'です。(キーは任意に設定できます。)

コマンドラインインタフェースから確認

# bin/cassandra-cli --host localhost --port 9160
cassandra> get Keyspace1.Standard2['ksmith']
=> (column=last, value=Smith, timestamp=1271987442338167)
=> (column=first, value=Key, timestamp=1271987442337022)
=> (column=age, value=35, timestamp=1271987442338914)
Returned 3 results.


基本的にはCassandraはKeyValueStore型のデータベースなので、覚えることは最小限なので使いやすそうですね。
KeyspaceやColumnFamilyをどの単位でまとめるかとかがポイントになりそうです。
もうちょっと遊んでみます。楽しいですね。


関連:
Apache Cassandraのインストール
fauna's cassandra at master - GitHub
DataModel - Cassandra Wiki
Symfoware Cassandraの使いどころ(Looking to the future with Cassandraの翻訳)
up and running with cassandra:: snax

Apache Cassandraのインストール

 ちょこちょこっとCouchDBを触ってみたことがあるのですが、どうやらオープンソースの分散DBはCassandra中心で回りそうなのでそっちを使ってみることにしました。ということで、お約束のインストールメモです。

環境

Cent-OS5.4 (Amazon EC2上のrightscale-us-east/CentOS_5.4_i386_v5.2.0_Alpha.manifest.xml ami-0859bb61)
java version "1.6.0_14" (デフォルトインストール済み)
インストールしたもの
Apache Ant 1.8.0

準備

公式ページからダウンロードできます。
バージョンは、0.6.1を選びました。

ビルドから起動まで

antでビルドする以外、殆ど不要です。
環境にあわせて、confの編集をしてください。

#cd apache-cassandra-0.6.1-src
#ant
 中略
BUILD SUCCESSFUL
# chmod 755 bin/cassandra
# chmod 755 bin/cassandra-cli
# bin/cassandra -f
 INFO 00:36:08,630 Auto DiskAccessMode determined to be standard
 INFO 00:36:09,159 Saved Token not found. Using 71869193890648876842090602795170258475
 INFO 00:36:09,159 Saved ClusterName not found. Using Test Cluster
 INFO 00:36:09,166 Creating new commitlog segment /var/lib/cassandra/commitlog/CommitLog-1271910969166.log
 INFO 00:36:09,232 Starting up server gossip
 INFO 00:36:09,319 Binding thrift service to localhost/127.0.0.1:9160
 INFO 00:36:09,323 Cassandra starting up...

クライアントツールで触ってみます。

# bin/cassandra-cli --host localhost --port 9160
Connected to: "Test Cluster" on localhost/9160
Welcome to cassandra CLI.

Type 'help' or '?' for help. Type 'quit' or 'exit' to quit.
cassandra> help
List of all CLI commands:
?                                                                  Same as help.
help                                                          Display this help.
connect <hostname>/<port>                             Connect to thrift service.
describe keyspace <keyspacename>                              Describe keyspace.
exit                                                                   Exit CLI.
quit                                                                   Exit CLI.
show config file                                Display contents of config file.
show cluster name                                          Display cluster name.
show keyspaces                                           Show list of keyspaces.
show api version                                        Show server API version.
get <ksp>.<cf>['<key>']                                  Get a slice of columns.
get <ksp>.<cf>['<key>']['<super>']                   Get a slice of sub columns.
get <ksp>.<cf>['<key>']['<col>']                             Get a column value.
get <ksp>.<cf>['<key>']['<super>']['<col>']              Get a sub column value.
set <ksp>.<cf>['<key>']['<col>'] = '<value>'                       Set a column.
set <ksp>.<cf>['<key>']['<super>']['<col>'] = '<value>'        Set a sub column.
del <ksp>.<cf>['<key>']                                           Delete record.
del <ksp>.<cf>['<key>']['<col>']                                  Delete column.
del <ksp>.<cf>['<key>']['<super>']['<col>']                   Delete sub column.
count <ksp>.<cf>['<key>']                               Count columns in record.
count <ksp>.<cf>['<key>']['<super>']            Count columns in a super column.
cassandra> show keyspaces
Keyspace1
system

cassandra> set Keyspace1.Standard2['jsmith']['first'] = 'John'
Value inserted.
cassandra> get Keyspace1.Standard2['jsmith']
=> (column=first, value=John, timestamp=1271911743088000)
Returned 1 results.
cassandra> set Keyspace1.Standard2['jsmith']['last'] = 'Smith'
Value inserted.
cassandra> set Keyspace1.Standard2['jsmith']['age'] = '42'
Value inserted.
cassandra> get Keyspace1.Standard2['jsmith']
=> (column=last, value=Smith, timestamp=1271911770333000)
=> (column=first, value=John, timestamp=1271911743088000)
=> (column=age, value=42, timestamp=1271911776381000)
Returned 3 results.
cassandra> exit

 割と簡単に起動とお試しまで出来ました。
今回はrootで起動しているのですが、ユーザ権限で行う場合は/var/lib/cassandraや/var/log/cassandraを作成して権限を与えておく必要があります。
 また今回はクラスタとか組んでいないですし、Keyspaceの作成とか全然やっていないので、そのうち掘り下げて試してみようかと思います。amazon ec2でクラスタ組む場合は、インナーのアドレスとかがあるのでちょっとややこしいみたいです。


参考:
GettingStarted - Cassandra Wiki
CassandraCli - Cassandra Wiki
johanoskarsson's cassandra-ec2 at master - GitHu

週末プログラマにお薦め!!Subversion+DropBoxで似非分散型バージョン管理

※Git版も書いています。
Git+DropBoxで、プライベートリポジトリ作成。或いはGitをAmazon S3でバックアップ


 週末プログラマの悩みに、バージョン管理のリポジトリをどこに置くかというのがあります。理想を言えばどこかのサーバーにおいて、HTTP経由でどこからでもアクセス出来るのが一番良いです。でもそうすると、レンタルサーバーのコストが掛かります。またGitHub等もありますが、基本的にソースをオープンにすることが前提ですので、個人ユースで使いにくい部分もあります。で、勢い自分のローカルにしかソースがないという状況があります。
 私は以下3つの問題を改善したいなぁと思っていました。
1.ソースのバックアップをどこか違うところに持ちたい
2.ネットワークでオフラインの時でも、コミット出来るようにしたい
3.違う環境から作業しても、最新のソースを取れるようにしたい


 そこで、gitですよ。違ry
そこでSubversion+DropBoxなのですよ。数あるオンラインストレージの中でDropBoxが大きく異なっている点として、ローカルにもファイルを持つということがあります。これは状況によっては欠点にもなるのですが、今回の場合だと大変重宝します。
 つまりDropBoxの管理下のディレクトリにマスタレポジトリを作成すれば、DropBox上にバックアップが作ります。この瞬間DropBoxのサーバーに同期されるので、1のバックアップが達成できます。またSubversionのクライアントからの視線でみると、マスターリポジトリはあくまで同一のローカルファイルですから、ネットワークにつながっていない状態でもチェックイン・チェックアウト出来ます。これで2も達成できますね。最後に違う環境での同期ですが、ネットワークにつながっている状態だと瞬時に行われます。またオフラインの状態で作業していても、次につながった時に確実に同期されます。なので3についても解決します。
 実際に試してみたのですが、コミットした瞬間に別のPCでもDropBoxが変更を検知してすぐに更新されていました。思っていた以上に速かったので感動ものでした。


 さてこの方式の問題点は何でしょうか?たぶん皆さんお気づきだと思いますが、両方共オフラインした状態で作業して、オンラインになったらコンフリクトする恐れがあります。解決策は知りません。。。ただ一つ言えるのは、私は一人しかいないので複数の場所で同時に作業することもないので困りません!!一人で開発している週末プログラマの方々、どうですか?
 まだアカウントを持っていない方は、Dropboxアカウント開設へ!!





Subscribe with livedoor Reader



See Also:
Git+DropBoxで、プライベートリポジトリ作成。或いはGitをAmazon S3でバックアップ
Markdown記法+Git+md2review+ReVIEWで原稿・ドキュメント管理


継続的インテグレーション入門 開発プロセスを自動化する47の作法
ポール・M・デュバル スティーブ・M・マティアス アンドリュー・グローバー
日経BP社
売り上げランキング: 65094

PHPの警告で見る、にわかPHPプログラマの不遇

 環境の都合でちろっとPHPのプログラムを書きました。私のPHPの記述レベルは素人に毛が生えた程度なので、ググリながらやっています。で、ある値をGETで受け取って処理するというよくあるパターンの記述をしていると、下記のような警告が出ました。GETのパラメータは渡される時もあれば渡されない時もあるといったパターンです。

Notice: Undefined index: id in /foo/var/index.php on line 3

 原因はハッキリと解っていて、下記のようなソースでkeyの値が空ではなく、そもそも値が渡らない時に定義されていませんよと警告を出してくれたのです。

if ($_GET['key']) {
    //hogehoge処理
}

 配列のkeyの値がセットされているかを判定するは、definedを使うのがよいかissetが良いかイマイチよく解らなかったので、とりあえず流してみてエラー文言を見て調べようと思ったのです。そして"Notice: Undefined index"でググッたら、なんと圧倒的な数の警告の消し方が出てくるのです!!まっとうな答えは、ウノウラボ Unoh Labsさんの 「配列操作でE_NOTICE対策を簡単に行う方法」だと思います。でもそれ以上に警告の消し方が出てくるのです。
 PHP嫌いの人はこれだからPHPはダメなんだとか言うと思います。ただそれを言うだけでは短絡的です。PHPのニーズが手軽に使いたいという人が多くて問題回避的な解決をする場面が多いという事実があって、Googleなどのアルゴリズムでは良い回答か悪い解答かを判断出来ない部分があるという事実なのではないでしょうか?あまりPHPの解説サイトの状況は解りませんが、根本から詳しく解説するというより、手っ取り早く解決するサイトが望まれているのかもしれませんね。公式サイトも使い易いとは言い難いですし。もうちょっと駆け出しプログラマでも道を踏み外さない方法があったら良いんですけどね。どうしたものでしょう

位置参照情報データと郵便番号データのマッチング

 以前、郵便番号データに緯度経度を付加する手順を書きました。Google Mapsと郵便番号データを利用することで生成してたのですが、別のアプローチで作る方法がありました。ずばり位置参照情報データというのがあったので、それと郵便番号データをマッチングするという方法です。日曜大工でやってみました。
 ちなみに何故私が郵便番号データに拘るかというと、住所とのマッチングだと表記揺れの吸収が大変だからです。その点、郵便番号だと間違いなくキーとしてマッチングできます。ということで解析系のデータとして使う時に便利です。(マッチングデータに郵便番号があったとしたらですけど。)


ということで生成手順です。
位置参照情報ダウンロードサービス

 一括で解凍。unzipで一括で解凍したければ、アスタリスクをエスケープする必要があります。
nkfでUTF-8に変換したあと、ヘッダー行を削除して一つのファイルにまとめます。

$ unzip -o \*.zip
$ nkf -w --overwrite *.csv
$ sed -e "1d" *_*.csv > gaiku_infos.csv

 テーブルを作って、インポートします。
環境にもよりますが、結構な時間がかかります。
インデックスを検討した方が良いかもしれません。

DROP TABLE gaiku_infos;
CREATE TABLE gaiku_infos (
id INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
pref_kanji varchar(36),
city_kanji varchar(128),
town_kanji varchar(128),
number varchar(128),
coordinate_no char(2),
coordinate_x double,
coordinate_y double,
longitude double,
latitude double,
disp_flg char(1),
represent_flg char(1),
history_flg1 char(1),
history_flg2 char(1)
)
DEFAULT CHARSET=utf8
;
CREATE INDEX idx_pref ON gaiku_infos (
pref_kanji
);
CREATE INDEX idx_city ON gaiku_infos (
city_kanji
);
CREATE INDEX idx_town ON gaiku_infos (
town_kanji
);
CREATE INDEX idx_address ON gaiku_infos (
pref_kanji,city_kanji,town_kanji
);

load data local infile '/tmp/geo/gaiku_infos.csv'
into table gaiku_infos
fields terminated by ',' enclosed by '"'
(
pref_kanji,
city_kanji,
town_kanji,
number,
coordinate_no,
coordinate_x,
coordinate_y,
longitude,
latitude,
disp_flg,
represent_flg,
history_flg1,
history_flg2
);


 次に郵便番号データを入れます。
ダウンロード元は、こちらです。

$ lha x ken_all.lzh
$ nkf -w --overwrite ken_all.csv 
$ sed -e "s/以下に掲載がない場合//g"ken_all.csv > /tmp/geo/post_codes.csv


テーブルの作成と、データのインポートを行います。
こちらは、街区情報に比べるとすぐに終わります。

drop table post_codes;
create table post_codes(
id INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
jiscode char(5),
postcode_short varchar(5),
postcode char(7),
pref_kana varchar(200),
city_kana varchar(200),
town_kana varchar(200),
pref_kanji varchar(36),
city_kanji varchar(128),
town_kanji varchar(128),
flag1 smallint,
flag2 smallint,
flag3 smallint,
flag4 smallint,
flag5 smallint,
flag6 smallint
)
DEFAULT CHARSET=utf8
;

CREATE INDEX idx_postcode ON post_codes (
postcode
);
CREATE INDEX idx_pref ON post_codes (
pref_kanji
);
CREATE INDEX idx_city ON post_codes (
city_kanji
);
CREATE INDEX idx_town ON post_codes (
town_kanji
);
CREATE INDEX idx_address ON post_codes (
pref_kanji,city_kanji,town_kanji
);


load data local infile '/tmp/geo/post_codes.csv'
into table post_codes
fields terminated by ',' enclosed by '"'
(
jiscode,
postcode_short,
postcode,
pref_kana,
city_kana,
town_kana,
pref_kanji,
city_kanji,
town_kanji,
flag1,
flag2,
flag3,
flag4,
flag5,
flag6
);

 最後に郵便番号データと街区データの経度、緯度をマッチングさせれば完了です。
悩ましい点として、街区データなので番地ごとの経度、緯度まであります。
一方郵便番号データは、街までです。つまり一つの郵便番号に対して複数の経度、緯度が
マッチングします。ということで、ちょっと強引ですが街ごとの平均を使うことにします。
そのデータをgaiku_geocodesというテーブルに一回いれてからzip_geocodesというテーブルにインサートします。
(left outer joinで一度でやろうとすると凄まじくコストがかかるので)

CREATE TABLE gaiku_geocodes (
id INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
pref_kanji varchar(36),
city_kanji varchar(128),
town_kanji varchar(128),
longitude double,
latitude double
)
DEFAULT CHARSET=utf8
;
CREATE INDEX idx_pref ON gaiku_geocodes (
pref_kanji
);
CREATE INDEX idx_city ON gaiku_geocodes (
city_kanji
);
CREATE INDEX idx_town ON gaiku_geocodes (
town_kanji
);
CREATE INDEX idx_address ON gaiku_geocodes (
pref_kanji,city_kanji,town_kanji
);

insert into gaiku_geocodes (pref_kanji,city_kanji,town_kanji,longitude,latitude)
select
pref_kanji,city_kanji,town_kanji,avg(longitude),avg(latitude)
from gaiku_infos
group by pref_kanji,city_kanji,town_kanji
;

CREATE TABLE zip_geocodes (
id INT(10) NOT NULL AUTO_INCREMENT PRIMARY KEY,
zip_code CHAR(7),
longitude double,
latitude double
)
DEFAULT CHARSET=utf8
;
CREATE INDEX idx_zip_cd ON zip_geocodes (
zip_code
);



select
pref_kanji,city_kanji,town_kanji,avg(longitude),avg(latitude)
from gaiku_infos
group by pref_kanji,city_kanji,town_kanji
limit 5;

insert into zip_geocodes (zip_code,longitude,latitude)
select
postcode,longitude,latitude
from post_codes
left outer join gaiku_geocodes
on post_codes.pref_kanji = gaiku_geocodes.pref_kanji
and post_codes.city_kanji = gaiku_geocodes.city_kanji
and post_codes.town_kanji = gaiku_geocodes.town_kanji
where gaiku_geocodes.town_kanji is not null
;

上記でマッチングするのは、12万件中5万4千件程度。
郵便の元データの方を修正したら使い物になりそうですね。
こんなデータとか

北二条西(1〜19丁目)

TortoiseGitのインストールと日本語化

入門Git

 WindowsでGitを使いたかったのでTortoiseGitを入れてみました。
特に悩む所はないですが、メモがてらのエントリーです。

 まず最初にmsysgitのインストール。
exeをダウンロードして、起動するだけの簡単なお仕事です。
インストール完了後に、パスを通します。デフォルトだとC:\msysgit\msysgit\binです。
注意点としては、C:\msysgit\msysgit\mingw\binにもパスを通すことです。
そうしないと、gitを実行した時に「libcurl-4.dllが見つからなかったため、このアプリケーションを開始できませんでした。アプリケーションをインストールし直すとこの問題は解決される場合があります。」という全く役に立たないアドバイスを貰うことになります。

 インストール後、コマンドプロンプトでgitと叩きエラーが出なければ成功です。


 その後はToritoiseGitをダウンロードして、インストールします。
これもインストールプログラムなので、悩むことはないです。


 お好みでメニューを日本語化できます。
ダウンロード - TortoiseGit日本語言語ファイル - SourceForge.JP
日本語化ファイルをダウンロード後に、dllファイルをTortoiseGitのLanguagesフォルダにコピーします。(デフォルトだとC:\Program Files\TortoiseGit\Languages)
※日本語化したい場合は、バージョンに注意してください。
 日本語ファイルの方が古い可能性が高いです。
 その場合はTortoiseGitを日本語化サイトから古い英語版を落としておく方が確実です。


操作方法自体は、TortoiseSVNやTortoiseCVSと殆ど同じです。
分散コミットなので、そこの所の考え方はSVNやCVSと違っています。
その辺りについては、また改めて。

入門Git
入門Git
posted with amazlet at 10.03.01
濱野 純(Junio C Hamano)
秀和システム
売り上げランキング: 5182
おすすめ度の平均: 4.5
5 楽しくGitを学べる本
5 美しいワークフローのための入門書
3 内部に詳しいが故に…

CouchDBのインストールと簡単な使い方

インストール

MacPortの準備をしていれば、簡単にインストール出来ます。

sudo port selfupdate
sudo port install spidermonkey
sudo port install icu
sudo port install erlang
sudo port install couchdb +server
sudo chown -R couchdb:couchdb /opt/local/var/lib/couchdb/ /opt/local/var/log/couchdb/
sudo launchctl load -w /opt/local/Library/LaunchDaemons/org.apache.couchdb.plist

CouchDBの所は、+serverを忘れないで下さい。
全部やると数十分くらいかかると思います。気長にお待ちください。

起動済みの確認

$curl http://localhost:5984/
{"couchdb":"Welcome","version":"0.10.1"}

返事もJSON形式で返ってきます


ブラウザでも確認
http://127.0.0.1:5984/_utils/index.html

右上の方で、変なおじさんが踊っているのが見えたら成功です。
左上のCreate Databaseを押すと簡単にデータベースを作ることができます。


とりあえず今回はここまで
Enjoy!!


参考にしたサイト
Web 時代の非リレーショナルデータベース: 第 1 回 Apache CouchDB の概要とインストール
Installing_on_OSX - Couchdb Wiki
めせ太日記さくらのブログ版: Apache CouchDBをMac OS Xにインストールする