チーム開発のための .NET 開発環境の整備(TDDの準備1)

.NETでのチーム開発のための環境整備を社内で作成しているところですが、備忘もかねて作業記録や気が付いた点など書いていきます。


今回はTDD開発進めるにあたり準備することを記載します。

今回の概要

  1. 単体テストフレームワーク(NUnit+ChainingAsserion)
  2. Jenkinsの設定

今回の環境

  • VisualStudio 2012
  • Entity Framework 5.0
  • ASP.NET MVC4
  • Jenkins

1. 単体テストフレームワーク(NUnit+ChainingAsserion)

NUnitChaining Assertionを使ってみます。

NUnitについてはNUnitの全貌 ~ 基本から、最新バージョンの新機能まで By Codezineという記事に詳しく説明があります。

インストール

拡張機能と更新プログラム」を開いて「NUnit Test Adapter(Beta6)」をインストールします f:id:kuroyanagi_h:20130726152929p:plain

テスト用のプロジェクトを「クラスライブラリ」で作成します。 パッケージマネージャーコンソールを開いて既定のプロジェクトを今作成したテスト用プロジェクトにしてコンソール画面で「Install-Package nunit」と入力してインストールをします。 続けてコンソール画面で「Install-Package ChainingAssertion-Nunit」と入力してインストールをします。 f:id:kuroyanagi_h:20130726155229p:plain

テストの記述については、NUnitやChainingAssertionのページをご覧ください。 ChainingAssertionについてはソースで追加されているので独自の拡張も簡単にできるライブラリです。

2. Jenkins

Windows OSにJenkinsを立てたのでJenkinsを使ってNUnitのテスト自動実行させるためには、まずコンパイル環境が必要です。 コンパイルには .NETフレームワークMSBuild を用いてコンパイルしますが、 念のため今回は VisualStudio 2012 Express版もJenkinsの入っているCIサーバーにインストールしました。 また、NUnitを実行するためにCIサーバーにNUnitこちらからダウンロードして インストールします。

追加したJenkinsプラグイン

MSBuild Plugin

Jenkinsでビルドを行う時に使用するプラグインです。 設定は以下の画面で行います。

  • [Jenkinsの管理]-[システムの設定] f:id:kuroyanagi_h:20130730113313p:plain 使用するMSBuildのバージョン毎に名前を付けてそのパスを設定します。

  • プロジェクトのの設定 f:id:kuroyanagi_h:20130730113823p:plain システムの設定で登録されたMSBuildのバージョンを選んでビルド対象のプロジェクトファイルを指定します。 あとはMSBuildを実行する際のコマンドラインオプションを設定します。

NUnit Plugin

NUnitの実行結果をレポートする時に使用するプラグインです。

  • プロジェクトの設定
    • NUnitの実行 f:id:kuroyanagi_h:20130730115048p:plain プラグインがないので、「Windowsバッチコマンド実行」を使用して直接NUnit実行コマンドを設定します。 NUnit実行結果をレポートするためにXML形式で出力するように指定します。
    • NUnit実行結果の集計 f:id:kuroyanagi_h:20130730114558p:plain 「ビルド後の処理の追加」で「Publish NUnit test result report」を選択し上記のNUnit実行時に出力したXMLファイルを指定します。
Jenkins表示結果

こんな表示や f:id:kuroyanagi_h:20130730120007p:plain 「最新のテスト結果」をクリックするとこんな表示ができるようになります。 f:id:kuroyanagi_h:20130730120025p:plain

チーム開発のための .NET 開発環境の整備(ソリューションの準備)

.NETでのチーム開発のための環境整備を社内で作成しているところですが、備忘もかねて作業記録や気が付いた点など書いていきます。

今回の環境

  • VisualStudio2012
  • Git+Gitlab
  • Jenkins
1. NuGetパッケージの復元の設定

順番が前後してしまいますが、今回はVisualStudioのソリューションでの準備です。

NuGetパッケージマネージャーはインストール済、最新版に更新済みとして話を進めます。

まずは通常通りソリューション作成します。(今回は ASP.NET MVC4のソリューションです) 今後おそらく便利なNuGetパッケージを追加していくのですが、NuGetパッケージはできればソース管理の対象から外したいです。しかし共有リポジトリから取得したソリューションを他人(CIサーバ含む)がビルドする時にこのままだと参照ライブラリがないといって怒られてしまいます。

そこで必ずやっておかなければならないのが次の設定です。

f:id:kuroyanagi_h:20130724152834p:plain

対象となるソリューションを設定して、右クリックしたメニューにある「NuGetパッケージの復元の有効化」を選択します。

f:id:kuroyanagi_h:20130724153548p:plain

するとソリューションフォルダのトップに .nuget というフォルダが作成されその下に NuGet.exe NuGet.Config NuGet.targets というファイルが 作成されます。これを元に MSBuildの際には NuGetによりパッケージの取得が行われます。

試しにソリューション作成時に作成された packages フォルダを削除してビルドすると、新たにpackagesフォルダが作成されて、次のようにInstallされてビルドが行われました。

f:id:kuroyanagi_h:20130724155146p:plain

2. Gitで管理から除外するファイルの設定

拡張機能の「Visual Studio Tools for Git」でソリューションをGitで管理するようにすると良い具合に.gitignoreと.gitattributesを作成してくれますがProfessional以上でないとインストールできないので、ファイルをGistに上げておきます。 .gitignoreには上で設定したものようにpackagesフォルダをgitに含めないようにしてあります。

RhoMobile Suite 2.2のインストール

昨年の記事でRhodesのインストールについてブログ書いたのですが、それから約1年たち 新しいRhodesのバージョンでのインストール記事と目玉機能を紹介したスライド作成しましたので アップします。

インストールについては、Rubyを今まではあらかじめ準備しておかないといけなかったのですが、「RhoMobile Suite」をインストールすることで、Rubyも一緒にインストールしてくれるのでだいぶ楽になりました。 Rubyの他にもGitやRedis,NodeJSといったものもインストールされるようになっています。もちろん今まで通り、Java JDKAndroid SDK,NDKは、あらかじめインストールしておく必要があります。 Android SDK、NDKは最新版だと2013/06現在うまくRhodesでビルドができないので注意が必要です。

今回の目玉はRhoSimulatorではないかと個人的に思っています。Androidエミュレータは立ち上がるのも遅いし、ビルドしたものを転送するのも遅いんですよね、Rhodesに限らずAndroid開発のイライラの元だったのですが、今回のバージョンではRhoSimulatorという独自のエミュレータを使うことができ、あっという間に画面の確認ができるものになっているようです。立ち上がったものを見るとあくまでも画面に関してのシミュレートのようなのですがそれでも大分うれしい機能ではないでしょうか?

PaaSを使ってみる(その1 dotCloud)

とりあえず、サーバ側は動くようになったのでスマホ側からアクセスさせるための準備でどっか公開されたところにアプリアップします。

いきなり、サーバ借りるわけにもいかないのでPaaS利用してみます。
今回はRuby Rails Redisが使えるPaaSを探してみましたが色々あってよくわからないので、いくつかお試しで使ってみようと思います。

本日は 「dotCloud」です。

dotCloudでサポートされている言語は

サポートされるデータベースは

その他

このようなサービスも利用可能です。

気になる料金

今回はRubyとRedis使用するのでこのような条件で見積もって


このような価格になりました。
dotCloudではサービスの提供に、Sandbox(開発時)、Live(公開時)の2パターン(Flavorと呼んでいるようです)があります。
開発時は独自のドメインが使えず、ベストエフォートであるものの、サービスのリソース制限もなく、SSLも使えるようです。
開発者にはかなり優しいのではないでしょうか?
dotCloud - Application Flavors
こちらに詳しく制限については書いてありました。
Sandboxだと一定期間で休止状態(Hiberbnate)になるとのことなので
継続したサービスには使えなさそうですね。

まずはサインイン

dotCloud - One home for all your apps にアクセスして右上の「Sign Up」をクリックすると

メールアドレスを聞かれるので、ここにメールアドレスを入力し、ダイアログの「Sign Up」をクリックすると

入力したメールアドレスに下記のようなメールが届き、そこにあるStep1のリンクからアカウントのアクティベートを行います。

Thanks for registering for dotCloud, the easiest way to deploy and
scale your web applications.

You're 3 simple steps away from deploying your first app:

1. Activate your account by visiting: http://www.dotcloud.com/accounts/activate/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

2. Install our CLI: http://docs.dotcloud.com/firststeps/install/

3. Create a simple "hello world" sandbox app:
http://docs.dotcloud.com/firststeps/quickstart/#a-simple-example

Happy hacking!

アクティベートには、ユーザ名とパスワードを設定します。

アクティベートが終わるとダッシュボードが表示され、アプリケーションを追加することができます。

dotCloud CLIをインストール

dotCloudを操作するためにはdotCloud CLIをインストールします。このツールはpythonで動くので予めpythonのインストールが必要です。
Windowsの場合は先にcygwinのインストールが必要とのこと。

自分の環境は、ubuntuなので

$ sudo easy_install pip && sudo pip install dotcloud
sudo: easy_install: コマンドが見つかりません

まだ easy-installがインストールされていない様なので

$ sudo apt-get install python-setuptools

を実行した後再度、実行します。

Railsアプリのデプロイ

  • 普通にRailsアプリを新規で作成します。
$ rails new sample           
      create  
      create  README.rdoc
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/assets/images/rails.png
      create  app/assets/javascripts/application.js
      create  app/assets/stylesheets/application.css
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/mailers
      create  app/models
      create  app/views/layouts/application.html.erb
      .........

Rails3.1以降ではプリコンパイル済みのアセットが必要です。

$ rake assets:precompile

*1

  • dotCloud上にアプリを作成します。
$ cd sample
$ dotcloud create sample
==> Creating a sandbox application named "sample"
==> Application "sample" created.
Connect the current directory to "sample"? [Y/n]: y

これでdotCloud上にsampleと言うアプリケーションが作成されました。

  • Buldファイルの作成

dotCloudでアプリケーションを動かすために「dotcloud.yml」というファイルを用意します。
RailsMysqlを使う場合はこの様なファイルを作成します。

www:
  type: ruby
db:
  type: mysql

Redisを使用する場合は

www:
  type: ruby
data:
  type: redis

この様になります。
詳しくは、dotCloudのドキュメントのBuildFileのページ、また各サービス(言語、DB)のページにBuildファイルの記述例があります。
dotCloud - Available dotCloud Services
dotCloud - Build File

dotcloud.ymlをアプリケーションのルートに保存して
次のコマンド dotcloud push で dotcloudサーバにアプリケーションがアップされます。

$ dotcloud push
==> Pushing code with rsync from "./" to application sample
building file list ... done
./
.gitignore
.rbenv-gemsets
.rbenv-version
Gemfile
Gemfile.lock
README.rdoc
Rakefile
config.ru
dotcloud.yml
.dotcloud/
.dotcloud/config
app/
.................
sent 29.49K bytes  received 1.25K bytes  5.59K bytes/sec
total size is 46.16K  speedup is 1.50
==> Submitting a deployment request for application sample
==> Deployment of revision rsync-1355159207277 scheduled for sample
- 2012-12-11 (sample deployment, deploy_id=a1686a7b-dc80-4019-9d0e-49fc2098b9e4)
02:07:25: [www] Fetching gem metadata from https://rubygems.org/.........
02:07:27: [www] Fetching gem metadata from https://rubygems.org/..
02:07:28: [www] Installing rake (10.0.2)
02:07:28: [www] Installing i18n (0.6.1)
02:07:28: [www] Installing multi_json (1.4.0)
02:07:29: [www] Installing activesupport (3.2.9) 
02:07:46: [www] Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
02:07:46: [www] Post-install message from rdoc:
02:07:46: [www] Depending on your version of ruby, you may need to install ruby rdoc/ri data:
02:07:46: [www] 
02:07:46: [www] <= 1.8.6 : unsupported
02:07:46: [www]  = 1.8.7 : gem install rdoc-data; rdoc-data --install
02:07:46: [www]  = 1.9.1 : gem install rdoc-data; rdoc-data --install
02:07:46: [www] >= 1.9.2 : nothing to do! Yay!
02:07:46: [www] 
.................
02:07:52: [www] Build completed successfully. Compiled image size is 10MB
02:07:52: [www] Build successful for service (www)
02:07:52: --> Application (sample) build is done
02:07:52: --> Provisioning services' instances... (This may take a few minutes)
02:07:52: [www] Using default scaling for service www (1 instance(s)).
02:07:52: [www.0] Provisioning service (www) instance #0
02:08:08: --> All services' instances have been provisioned. Installing code...
02:08:09: [www.0] Installing build revision rsync-1355159207277 for service (www) instance #0
02:08:19: [www.0] Running postinstall script...
02:08:21: [www.0] Launching...
02:08:22: [www.0] Waiting for the instance to become responsive...
02:08:22: [www.0] Re-routing traffic to the new build...
02:08:24: [www.0] Successfully installed build revision rsync-1355159207277 for service (www) instance #0
02:08:24: [www.0] Installation successful for service (www) instance #0
02:08:24: --> Application (sample) fully installed
==> Application is live at http://sample-euledge.dotcloud.com

デプロイにはrsyncでサーバーにファイルがアップされるようです。
またアップが終わると自動的にBundle Installがされインスタンスの起動まで行われています。
ダッシュボードで確認してみましょう。

デプロイ時の最後、またはダッシュボードに公開されているURLが記されているので早速アクセスしてみると。

こんな感じでデプロイできています。

ダッシュボードからは、メモリ使用量、トラフィック、サーバーログ、環境変数、ドメイン名、課金状況など表示することができます。

ちなみに、ログをみるとWebサーバーはnginxが動いてるみたいです。

またSandboxからLiveへの切り替えもダッシュボードのAdminから行うようです。


あとは、ローカルでアプリコーディングして $dotCloud pushでデプロイのサイクルをしていけば良さそう。
そういえば、課金されたときの支払いはクレジットカードですが、Sandbox利用している段階ではクレジット情報の入力は不要みたいです。つまりSandbox利用中はずっと無料ってこと、これなら結構気楽に使っていけるんじゃないでしょうか?

色々なPaaS触ってみようと思ったけど、何か既にこれで十分な気がしてきた。その2があるかどうかは未定ってことで

*1:最初にデプロイしたときrailsの画像が出てなかったので変だなとは思ったのですが見て見ぬふりしてしまいました orz

簡単なパターンマッチに対応したRedis単語登録

よみの部分を簡単なパターンマッチ可能な形で辞書引きしてみます。
Redisはキーと値の組にしてに入れますが、そのままではパターンマッチできません。*1

まず、力ずくでパターン展開したすべての文字をキーにして入れてみました。
例えば「シズカ:静か」という辞書は次の様に展開します。
**カ:静か
*ズ*:静か
*ズカ:静か
シ**:静か
シ*カ:静か
シズ*:静か
シズカ:静か
この様に展開したものをRedisのSET型で登録してみます。
SET型ではキーが同じものは値が重複しない限り追加して登録できます。

SADD '**カ', '{シズカ:静か}'
SADD '**カ', '{スイカ:西瓜}'
SADD '**カ', '{トミカ:トミカ}'
SADD '**カ', '{トミカ:トミカ}'
#省略......
SADD '**ン', '{シナン:至難}'
SADD '**ン', '{シナン:指南}'


#するとこの様なイメージで登録されます
**カ => {シズカ:静か}, {スイカ:西瓜}, {トミカ:トミカ}
#省略......
シ** => {シズカ:静か}, {シナン:至難}, {シナン:指南}

#この様に保管された辞書から**カ(3文字目がカ)である単語を検索すると
SMEMBERS '**カ'

#この様に3文字めにカを持つ単語すべてを取り出せます
["{シズカ:静か}", "{スイカ:西瓜}", "{トミカ:トミカ}"]

NAISTの辞書から、記号を除いて2文字から8文字の単語のみ登録してみました。
登録キー数:  5,359,281件
登録に掛かった時間: 約35分
格納メモリ容量: 2.2GByte
全然実用的じゃないです。(そりゃそうだ)

HASH型にした方がメモリの使用率が下がるとのことだったのでそちらをつかいメモリ使用量は半分位にはなりました。
メモリが潤沢なら良いですがまだまだ実用レベルではないです。
ただし、検索に関しては文句なしに早いです。

これじゃサーバ立てたくても立てられないので、別の方法を考えました。
Redisのメモリ容量は、キーの数に大きく依存するらしいので、キーの数を減らすことを考えました。
そこで考えた方法が次の方法です。

キーをn文字目に文字Xを持つ単語の集合として定義します。

  • 1文字目がアになる単語の集合
  • 1文字目がイになる単語の集合
  • n文字目がXになる単語の集合
  • 8文字目がンになる単語の集合

こうすれば、先の例で8文字までの単語の場合8×51(実際は濁音とかあるのでもう少し増えますが)で済むはず
キーには何文字目かを分かるようにして n:X とすると

SADD '1:シ', '{シズカ:静か}'
SADD '2:ズ', '{シズカ:静か}'
SADD '3:カ', '{シズカ:静か}'
SADD '1:ス', '{スイカ:西瓜}'
SADD '2:イ', '{スイカ:西瓜}'
SADD '3:カ', '{スイカ:西瓜}'
SADD '1:ト', '{トミカ:トミカ}'
SADD '2:ミ', '{トミカ:トミカ}'
SADD '3:カ', '{トミカ:トミカ}'
SADD '1:シ', '{シナン:至難}'
SADD '2:ナ', '{シナン:至難}'
SADD '3:ン', '{シナン:至難}'
SADD '1:シ', '{シナン:指南}'
SADD '2:ナ', '{シナン:指南}'
SADD '3:ン', '{シナン:指南}'

#するとこの様なイメージで登録されます
1:シ => '{シズカ:静か}','{シナン:至難}','{シナン:指南}'
2:ズ => '{シズカ:静か}'
3:カ => '{シズカ:静か}','{スイカ:西瓜}','{トミカ:トミカ}'
1:ス => '{スイカ:西瓜}'
2:イ => '{スイカ:西瓜}'
1:ト => '{トミカ:トミカ}'
2:ミ => '{トミカ:トミカ}'
2:ナ => '{シナン:至難}','{シナン:指南}'
3:ン => '{シナン:至難}','{シナン:指南}'

これであれば「**カ」という検索に対しては 「3:カ」をキーに持つ値を抽出できます。

「シ*カ」という検索に対しては RedisのSET型は集合の演算ができます。
この場合は「1:シ」と「3:カ」の共通部分を演算させ

 SINTER('1:シ', '3:カ')

とすることで{シズカ:静か}を得ることができます。

このやり方で、一つ問題点があります。すべてが同じ文字数なら良いのですが上記の例で「シズカゴゼン:静御前」が登録されたらどうなるでしょうか?

1:シ => '{シズカ:静か}','{シナン:至難}','{シナン:指南}','{シズカゴゼン:静御前}'
2:ズ => '{シズカ:静か}','{シズカゴゼン:静御前}'
3:カ => '{シズカ:静か}','{スイカ:西瓜}','{トミカ:トミカ}','{シズカゴゼン:静御前}'
1:ス => '{スイカ:西瓜}'
2:イ => '{スイカ:西瓜}'
1:ト => '{トミカ:トミカ}'
2:ミ => '{トミカ:トミカ}'
2:ナ => '{シナン:至難}','{シナン:指南}'
3:ン => '{シナン:至難}','{シナン:指南}'
4:ゴ => '{シズカゴゼン:静御前}'
5:ゼ => '{シズカゴゼン:静御前}'
6:ン => '{シズカゴゼン:静御前}'

この時 **カを検索させるつもりで、SINTER('1:シ', '3:カ')としても
'{シズカゴゼン:静御前}'もヒットしてしまいます。

これを対処するために各単語の最後にストップ文字を加えて登録する事にします。
シズカ=>シズカ$
スイカ=>スイカ$
トミカ=>トミカ$
シナン=>シナン$
シズカゴゼン=>シズカゴゼン$

この様なデータになります。

1:シ => '{シズカ:静か}','{シナン:至難}','{シナン:指南}','{シズカゴゼン:静御前}'
2:ズ => '{シズカ:静か}','{シズカゴゼン:静御前}'
3:カ => '{シズカ:静か}','{スイカ:西瓜}','{トミカ:トミカ}','{シズカゴゼン:静御前}'
1:ス => '{スイカ:西瓜}'
2:イ => '{スイカ:西瓜}'
1:ト => '{トミカ:トミカ}'
2:ミ => '{トミカ:トミカ}'
2:ナ => '{シナン:至難}','{シナン:指南}'
3:ン => '{シナン:至難}','{シナン:指南}'
4:$ => '{シズカ:静か}','{スイカ:西瓜}','{トミカ:トミカ}','{シナン:至難}','{シナン:指南}'
4:ゴ => '{シズカゴゼン:静御前}'
5:ゼ => '{シズカゴゼン:静御前}'
6:ン => '{シズカゴゼン:静御前}'
7:$ => '{シズカゴゼン:静御前}'

シ*カを検索させる場合は、SINTER('1:シ', '3:カ', '4:$')とする事で
目的とする {シズカ:静か} だけをマッチさせることができます。

これでDB作って見ました。先ほどと同じく
NAISTの辞書から、記号を除いて2文字から8文字の単語のみ登録してみました。
登録キー数:  591件
登録に掛かった時間: 191.8s
格納メモリ容量: 176.8MByte
メモリ使用量が激減しました。これなら使えるかな?
肝心の検索スピードも 0.2s位なのでまあ大丈夫かな

ちなみにこの方法の場合、5文字の単語検索させるとき
'ア****'を検索させる場合と、'アイ*エオ'を検索させる場合は
'ア****'の方が検索に掛かるコストが少ない事になります。

*1:KEYSでパターンマッチはできますが、公式サイトの説明では管理用に使うべきで通常のコードでは使うなとあります

RubyからRedisを使ってみる

前回は、Redisをインストールして簡単な動作確認をしました。

今回はRubyからRedisにアクセスしてみます。

ライブラリのインストール

rubyからアクセスするためのライブラリ redis-rb を使います。
gem からインストールできます。

gem install redis

単語辞書データのストレージとしてRedisを使おうと思いますので、
辞書をRedisに登録するためのプログラムをまずは作成します。

登録する辞書は前々回に使用した NAIST辞書を使います。

辞書データはこの様なCSVデータが入っています。

笹野本,1365,1365,7069,名詞,固有名詞,地域,一般,*,*,笹野本,ササノホン,ササノホン,,
笹薮,1358,1358,4975,名詞,一般,*,*,*,*,笹薮,ササヤブ,ササヤブ,,
笹葉峰,1360,1360,7342,名詞,固有名詞,一般,*,*,*,笹葉峰,ササバミネ,ササバミネ,,
笹流山,1360,1360,7342,名詞,固有名詞,一般,*,*,*,笹流山,ササナガレヤマ,ササナガレヤマ,,
笹流貯水池,1360,1360,7342,名詞,固有名詞,一般,*,*,*,笹流貯水池,ササナガレチョスイチ,ササナガレチョスイチ,,
笹竜胆,1358,1358,4975,名詞,一般,*,*,*,*,笹竜胆,ササリンドウ,ササリンドー,,
笹林,1365,1365,7069,名詞,固有名詞,地域,一般,*,*,笹林,ササバヤシ,ササバヤシ,,
笹路,1365,1365,7069,名詞,固有名詞,地域,一般,*,*,笹路,ソソロ,ソソロ,,
笹和田,1365,1365,7069,名詞,固有名詞,地域,一般,*,*,笹和田,ササワダ,ササワダ,,
笹塒山,1360,1360,7342,名詞,固有名詞,一般,*,*,*,笹塒山,ササトヤヤマ,ササトヤヤマ,,

各列の意味はこの様になっています

表層形 左文脈ID 右文脈ID コスト 品詞 品詞細分類1 品詞細分類2 品詞細分類3 活用形 活用型 原形 読み 発音
笹野本 1365 1365 7069 名詞 固有名詞 地域 一般 笹野本 ササノホン ササノホン
笹竜胆 1358 1358 4975 名詞 一般 笹竜胆 ササリンドウ ササリンドー

今回は単語とその読みを登録するものとし記号以外の品詞の単語を登録します。また読みと発音が異なる場合はそれぞれ登録することにします。
で登録するためのプログラムはこの様になります。

# coding:utf-8
require 'redis'

unless ARGV.length==1 then
  p "Usage: setup_dict_redis.rb filename"
  exit 1
end

redis = Redis.new
redis.ping
redis.flushdb

filename=ARGV[0]
File.foreach(filename) do |line|
  fields = line.split(",")
  unless /記号/ =~ fields[4] then
     redis.set "#{fields[11]}","#{fields[0]}"
     redis.set "#{fields[12]}","#{fields[0]}" if fields[11] != fields[12]
  end
end

redis.save
info = redis.info
p info["db0"]
redis.quit

実行してみます。

$ wc -l naist-jdic-utf.csv 
485863 naist-jdic-utf.csv

$ time ruby setup_dict_redis.rb naist-jdic-utf.csv
"keys=250490,expires=0"
ruby setup_dict_redis.rb naist-jdic-utf.csv  31.40s user 6.52s system 97% cpu 38.836 total

元の辞書の単語数は485863語で、これから記号を除いています。
また上記のプログラムでは文字列型で登録しています。読みがキーになっているため同じ読みのものは後からの単語で上書きされます。
このためRedisに登録された単語数は 250490語になります。
この単語の登録が31.40sと言うことなのでめちゃくちゃ早いですね。

またRedisは永続化できるので先ほどのプログラムの最後でファイルに書き出しました。
データのファイルサイズがどれくらいかというと

$ ls -l /var/lib/redis/6379/
合計 7808
-rw-r--r-- 1 root root 7994150 1129 23:29 dump.rdb

約8Mといったところです。

Redisで扱うことのできるデータ型は文字列型の他にリスト型、セット型、ソート済みセット型、ハッシュ型などがあります。

Redisについての詳しい説明は、下記を参照するとよいと思います。
redisドキュメント日本語訳 — redis 2.0.3 documentation
ニコニコ生放送に見る Redis 活用ノウハウ|gihyo.jp … 技術評論社
redis、それは危険なほどのスピード|サイバーエージェント 公式エンジニアブログ

Redisを使ってみる

やりたいことなのですが、大量の単語データからの検索が必要なものです。

基本的に今回は検索のみなので、以前携わっていたお仕事の中で使っていたRedisでまずは試してみたい。
実際自分の担当の所ではあまり関係なかったのでRedisと言う言葉とぼやっとしたイメージしかなかったので
今回は復習もかねてきちんと中身を把握しようと思います。

インストール

aptにもありましたが、今回は手抜きせず自分でインストールしてみます。

最新の安定版を http://redis.io/ からダウンロードしてきます。

#ダウンロードしたファイルを解凍します。
$ tar zxf redis-2.6.5.tar.gz
$ ls redis-2.6.5
00-RELEASENOTES  CTRIBUTING  INSTALL    Makefile  deps        runtest        src    utils
BUGS             COPYING       MANIFESTO  README    redis.conf  sentinel.conf  tests
$ cd redis-2.6.5
# ビルド
$ make
....................
....................
Hint: To run 'make test' is a good idea ;)
# makeが終わるとテストしてみなって言われるので、言われるままやってみます。

$ make test
....................
....................
#ずらずらっとテストが始まり最後にはこの様な表示になります。

                   The End

Execution time of different units:
  0 seconds - unit/printver
  0 seconds - unit/quit
  1 seconds - unit/auth
  2 seconds - unit/multi
  2 seconds - unit/protocol
  3 seconds - integration/aof
  1 seconds - integration/rdb
  2 seconds - integration/convert-zipmap-hash-on-load
  8 seconds - unit/expire
  1 seconds - unit/pubsub
  9 seconds - unit/type/set
  1 seconds - unit/slowlog
  8 seconds - integration/replication-4
  1 seconds - unit/introspection
  2 seconds - unit/limits
  3 seconds - unit/scripting
  15 seconds - unit/type/list
  17 seconds - unit/type/list-2
  8 seconds - unit/dump
  21 seconds - unit/type/hash
  21 seconds - unit/aofrw
  23 seconds - unit/other
  23 seconds - integration/replication-3
  25 seconds - unit/type/zset
  13 seconds - unit/bitops
  26 seconds - unit/sort
  28 seconds - integration/replication-2
  20 seconds - unit/maxmemory
  30 seconds - unit/basic
  31 seconds - unit/type/list-3
  22 seconds - unit/obuf-limits
  32 seconds - integration/replication

\o/ All tests passed without errors!

redisサーバー動作確認

srcの中にビルドしたモジュールが入っています。

$ cd src
$ ./redis-server
[8097] 28 Nov 23:06:14.152 # Warning: no config file specified, using the default config. In order to specify a config file use ./redis-server /path/to/redis.conf
[8097] 28 Nov 23:06:14.154 # Unable to set the max number of files limit to 10032 (Operation not permitted), setting the max clients configuration to 3984.
[8097] 28 Nov 23:06:14.154 # Warning: 32 bit instance detected but no memory limit set. Setting 3 GB maxmemory limit with 'noeviction' policy now.
                _._                                                  
           _.-``__ ''-._                                             
      _.-``    `.  `_.  ''-._           Redis 2.6.5 (00000000/0) 32 bit
  .-`` .-```.  ```\/    _.,_ ''-._                                   
 (    '      ,       .-`  | `,    )     Running in stand alone mode
 |`-._`-...-` __...-.``-._|'` _.-'|     Port: 6379
 |    `-._   `._    /     _.-'    |     PID: 8097
  `-._    `-._  `-./  _.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |           http://redis.io        
  `-._    `-._`-.__.-'_.-'    _.-'                                   
 |`-._`-._    `-.__.-'    _.-'_.-'|                                  
 |    `-._`-._        _.-'_.-'    |                                  
  `-._    `-._`-.__.-'_.-'    _.-'                                   
      `-._    `-.__.-'    _.-'                                       
          `-._        _.-'                                           
              `-.__.-'                                               

[8097] 28 Nov 23:06:14.156 # Server started, Redis version 2.6.5
[8097] 28 Nov 23:06:14.156 # WARNING overcommit_memory is set to 0! Background save may fail under low memory condition. To fix this issue add 'vm.overcommit_memory = 1' to /etc/sysctl.conf and then reboot or run the command 'sysctl vm.overcommit_memory=1' for this to take effect.
[8097] 28 Nov 23:06:14.156 * The server is now ready to accept connections on port 6379

ポート番号 6379 で起動したようです。

redisクライアントで動作確認

同じくsrcフォルダにクライアントモジュールがあります。

$ ./redis-cli set test hoge
OK
$ ./redis-cli get test 
"hoge"

ちゃんとデータが入ったようです。

システムにインストール

動作確認できたのでシステムに入れます。

$ sudo make install

#utilの下にインストールスクリプトがありますのでこれを実行します。
$ cd utils
$ ls
build-static-symbols.tcl  mkrelease.sh   redis_init_script      whatisdoing.sh
generate-command-help.rb  redis-copy.rb  redis_init_script.tpl
install_server.sh         redis-sha1.rb  speed-regression.tcl

$ sudo ./install_server.sh 
Welcome to the redis service installer
This script will help you easily set up a running redis server


Please select the redis port for this instance: [6379] 
Selecting default: 6379
Please select the redis config file name [/etc/redis/6379.conf] 
Selected default - /etc/redis/6379.conf
Please select the redis log file name [/var/log/redis_6379.log] 
Selected default - /var/log/redis_6379.log
Please select the data directory for this instance [/var/lib/redis/6379] 
Selected default - /var/lib/redis/6379
Please select the redis executable path [/usr/local/bin/redis-server] 
s#^port [0-9]{4}$#port 6379#;s#^logfile .+$#logfile /var/log/redis_6379.log#;s#^dir .+$#dir /var/lib/redis/6379#;s#^pidfile .+$#pidfile /var/run/redis_6379.pid#;s#^daemonize no$#daemonize yes#;
Copied /tmp/6379.conf => /etc/init.d/redis_6379
Installing service...
update-rc.d: warning: /etc/init.d/redis_6379 missing LSB information
update-rc.d: see <http://wiki.debian.org/LSBInitScripts>
 Adding system startup for /etc/init.d/redis_6379 ...
   /etc/rc0.d/K20redis_6379 -> ../init.d/redis_6379
   /etc/rc1.d/K20redis_6379 -> ../init.d/redis_6379
   /etc/rc6.d/K20redis_6379 -> ../init.d/redis_6379
   /etc/rc2.d/S20redis_6379 -> ../init.d/redis_6379
   /etc/rc3.d/S20redis_6379 -> ../init.d/redis_6379
   /etc/rc4.d/S20redis_6379 -> ../init.d/redis_6379
   /etc/rc5.d/S20redis_6379 -> ../init.d/redis_6379
Success!
Starting Redis server...
Installation successful!