Hadoop Conference Japan 2011に参加した

Hadoop Conference Japan 2011 - Eventbriteに参加してきました。

場所は豊洲にあるNTT DATAの本社ビルの36階セミナールームでした。さすがの絶好の景色ですね。

詳細な内容は登壇者の方や他の方のブログにもまとまってるので、簡単に感想だけ。

Hadoop on クラウド / Amazon Elastic MapReduceの真価

スライド: Amazon Elastic MapReduceの紹介(英語)


Amazon Elastic MapReduce(Hadoopクラスター Amazon EMR) | アマゾン ウェブ サービス(AWS 日本語)の紹介です。

  • 簡単に使えそうな感じ
  • Hadoopで処理するようなジョブを回した場合、いくら位かかるのか怖いですね
  • 一度くらい試してみたい
  • Hadoop上でRを実行するRHIPEも使えるらしい

MapReduceによる大規模データを利用した機械学習

Hadoop上で機械学習を使うお話。

モバゲーの大規模データマイニング基盤におけるHadoop活用

スライド: 『モバゲーの大規模データマイニング基盤におけるHadoop活用』-Hadoop Conference Japan 2011- #hcj...


モバゲーでのデータ分析のためのHadoopプラットフォームと行動データの分析の話。

  • すでに社内でデータを活用するためのHadoopプラットフォームがしっかり整っている印象
  • ログ形式の統一等社内の他の部署でも結構データ分析への理解があるんですね
  • ユーザの感情に着目してマイニング、即座にサービスに反映させる

Enterprise Batch Processing Framework for Hadoop

基幹業務向けのHadoopフレームワークの紹介。

  • プレスリリース出てたやつですね
  • 個人的に基幹業務というやつを分かっていないので、イマイチ凄さがわからず
  • Hadoopはテストや運用がしにくいのは同意
  • 見た感じフレームワークというより、HiveやPigのような基幹業務用のDSLという感じ?
  • 「数学知らなくてもHadoop書けます!」っていうのはちょっと同意できないかな

Hiveを用いたAmebaサービスのログ解析共通基盤

AmebaでのHadoopやHiveを使ったログ解析基板の話。

  • Hiveを使ってみての紹介
  • 社内ツール的なものも結構あったようなので詳細はちょっとわからず
  • 現状を聞く限り、現在ログ解析の基板を作っている最中という感じかな?

ライトニングトーク

  • 藤川さんの「Sneak Preview of "Hapyrus" ~ Hadoopアプリ開発&共有サービス on the CLOUD」がちょっと気になった。
  • Hapyrus
  • Hadoop版のAppStoreみたいなの作ります、という話。
  • Hadoopに限らず、こういうコードを取引できる場ができるというのは面白いかも

マルチユーザーでHadoop環境を利用するためのポイント

Hadoopを複数人で使う場合のよくある問題とそれを回避する方法。

  • Hadoopクラスタに勝手に入って触られるのは困るため、基本的にはゲートウェイ経由以外入れない
  • 他の人のデータを勝手に見ることができるのも問題
  • 特定のジョブが占有してしまうのも問題

Hadoopと分析統計ソフトKNIMEを用いた効率的データ活用

Hadoopを使う人が技術者だけでなく、分析者も使うため、GUIツールと連携させた話。

  • 社内でHadoopを扱える技術者だけでなく、分析者も直にデータを見ることが出来るようにする必要がある
  • KNIME | Konstanz Information MinerというGUIツールがあるので、それとHadoopを連携させる
  • HadoopをMapReduceを知らない人や非技術者にも使えるようにしよう、という話は結構あるけど、やっぱり難しそうですよね

総括

Hadoopといっても、Hadoop上でのアルゴリズムの話から、Hadoopを使ったログ解析プラットフォームやHadoop周辺ライブラリなどの話、Hadoopチューニングの話などかなり多領域の話が聞けて、非常に面白かったですね。


ただ、Hadoopを使う上でこれだけ幅広い知識が求められるというのは、実際に活用するのは結構難しい、という印象ですね。

vimプラグインの管理をpathogen.vimにした

vimプラグインの管理を最近はやりのpathogen.vimを使う方法に変更しました。


今までは、vimanaを使ってみたりいろいろ試してはみたのですが、なかなかしっくり来る方法が見つからなかったのですが、pathogen.vimを使ってみたら、かなり使い心地が良かったため、完全に移行しました。

pathogen.vimとはなんぞや

まず、pathogen.vimvimプラグインの読み込みパスを変更するプラグインです。
従来は .vim/ 以下のpluginとかautoloadとかのディレクトリを読み込むようになっているところを、pathogen.vimをいれると .vim/bundle/<プラグイン名>/以下の各ディレクトリも .vim/ 直下と同じように読み込むようになってくれます。
これにより、bundle/ 以下にプラグインごとに別のディレクトリを切って管理をすることができるようになります。


従来のvimプラグインの管理の欠点として、すべてのプラグインを同じディレクトリに放り込まないといけなかったため、どのファイルがどのライブラリのためのものかわからなくなったり、プラグインごとにディレクトリを切らざるを得ないGitなどのレポジトリで管理されているライブラリとの相性が非常に悪かったことなどがあります。
このpathogen.vimを使うとそのあたりの欠点がすっきり解消されるため、vimプラグイン管理の見通しが非常によくなります。

pathogen.vim の導入

まずはpathogen.vimの導入です。


pathogen.vim はgithubで管理されているので、githubから落としてきます。
https://github.com/tpope/vim-pathogen


.vim/autoload/ 以下にpathogen.vimを一枚おくだけなのですが、個人的には今後のアップデートや他のプラグインとの整合性も考えて、.vim/bundle/ 以下において、.vim/autoload/ からシンボリックリンクを貼るのがいいかと思います。
また、後述しますが、.vim/ 自体もgit管理している場合は、gitのsubmoduleとして管理するのが楽かと思います。

$ mkdir .vim/bundle
$ git submodule add git://github.com/tpope/vim-pathogen.git .vim/bundle/vim-pathogen
$ ln -s .vim/bundle/vim-pathogen/autoload/pathogen.vim .vim/autoload/


あとは、.vimrcにpathogenを読み込む設定を書けばOKです。

$ vi .vimrc
call pathogen#runtime_append_all_bundles()

git管理のプラグインの移行

せっかくなので簡単にプラグインの移行方法も書いておきます。


まずは、gitレポジトリで管理されているプラグインです。
これは pathogen.vim を使うと導入が劇的に簡単になります。


gitには他のgitレポジトリをsubmoduleとして取り込む機能があります。
そのため、.vim/ 自体をgit管理している場合は、そのプラグインのgitレポジトリをsubmoduleとして取り込めばOK。

$ git submodule add git://github.com/msanders/snipmate.vim.git .vim/bundle/snipmate.vim  

vimball プラグインの移行

vimballの場合はそのまま入れると.vim/直下に解凍されてしまうので、インストールパスを変えることでとりあえず対応してます。

$ mkdir .vim/bundle/Align/
$ vi Align.vba
:let g:vimball_home = "~/.vim/bundle/Align/"
:source %

tarやzipなどで配布されているプラグインの移行

これはそのまま、ディレクトリを掘って解凍すればOKですね。

$ mkdir .vim/bundle/project
$ cd .vim/bundle/project
$ tar zxvf ~/project-1.4.1.tar.gz

単体 .vim ファイルで配布されているプラグインの移行

個人的にどうするか迷ったのがこの単体.vimファイル1枚で管理されているプラグイン。
まあ、これくらい.vim直下に入れて管理してしまっても全然問題ないと思います。


ただ、なんとなく美しくないので、他と同じようにbundle以下にディレクトリを掘って同じように管理するようにしました。

$ mkdir -p ~/.vim/bundle/yanktmp/plugin
$ mv .yanktmp ~/.vim/bundle/yanktmp/plugin/


最終的にこんな感じになりました。
https://github.com/mkataigi/dotfiles-vim

Ubuntuサーバにgit/gitosis/gitwebを入れてみる

Ubuntuサーバにgitを入れてみました。
あわせてgitosisとgitwebも入れてみました。

gitはもう言わずもがなな分散バージョン管理システムですね。
gitosisはgitのレポジトリの権限周りを管理するツールで、gitwebはgitレポジトリのウェブベースの簡易フロントエンドです。

gitを入れる

まずはgitです。
これは簡単にできます。

基本的にはaptでインストールすればOK。
普通に使う分には、特にこれといった設定も必要ありません。

server $ sudo apt-get install git-core

gitが入ったので、試しにサンプルのレポジトリを作ってみます。

server $ mkdir sample.git
server $ cd sample.git
server $ git init --bare --shared=true

local側で編集して、server側に反映させてみます。
空のレポジトリはクローンできないため、local側で編集したものを、server側にpushします。

local $ mkdir sample.git
local $ cd sample.git
local $ git init
local $ touch test.txt
local $ git remote add origin ssh://server.co.jp/git/sample.git 
local $ git add test.txt
local $ git commit -m "init"
local $ git push origin master

これでレポジトリのクローンが出来ます。

gitosisを入れる

続いてはgitosisです。
gitosisは、このgitosis自体もgitのひとつのレポジトリとして管理されていて、このレポジトリ内の設定ファイルを書き換えてコミットすることによって、git全体の設定を変える、というものです。
まあ、これだけだとよくわからないので、実際に見るのがいいですね。

aptにあるので、インストール自体はすぐです。

server $ sudo apt-get install gitosis

インストールすると、gitosisユーザとそのホームディレクトリとして/srv/gitosisができます。

gitosis-adminというレポジトリができているので、それをクローンしてきて、設定を変更します。

server $ git clone gitosis@localhost:gitosis-admin.git
server $ cd gitosis-admin.git

gitosis-adminレポジトリをクローンしてくると、keydirとgitosis.confが入っています。
レポジトリにコミットする権限を与えるには、権限を与えたい人の鍵をkeydir以下に配置して、その設定をgitosis.confに書くことで行います。
例えば、sampleレポジトリに対してlocalマシンからmkataigi権限でコミットできるようにするには以下のようにします。

server $ cp ~/local_public_key keydir/mkataigi@local.pub
server $ vi gitosis.conf
[group gitosis-admin]
writable = gitosis-admin sample
members = mkataigi@server mkataigi@local
server $ git add .
server $ git commit -m 'add configuration for mkataigi@local'
server $ git push

これで、sampleディレクトリをlocalマシンからコミットできるようになります。

local $ cd ~/sample.git
local $ git remote add origin gitosis@server:sample.git
local $ git push origin master

レポジトリの本体は /srv/gitosis/repositories 以下に作成されます。

gitwebを入れる

続いてはgitwebです。
これはwebベースのgitレポジトリの簡易フロントエンドです。
特にたいしたことが出来るわけではないのですが、ちょっと確認するには便利です。

aptの場合はこれも入っているので、インストールはすぐに終わります。

$ sudo apt-get install gitweb

gitwebの設定ファイルがあるので、レポジトリの配置にあわせて設定します。
ウェブベースなので、CSSなどの読み込みのパスを修正します。

$ sudo vi /etc/gitweb.conf
    $projectroot = "/srv/gitosis/repositories";
    $stylesheet = "/gitweb/gitweb.css";
    $logo = "/gitweb/git-logo.png";
    $favicon = "/gitweb/git-favicon.png";

あわせてapache側も設定します。

$ cd /etc/apache2/sites-available
$ sudo vi gitweb
Alias /git /usr/lib/cgi-bin
Alias /gitweb /usr/share/gitweb
<Directory /usr/lib/cgi-bin>
    Options ExecCGI
    AddHandler cgi-script .cgi
    AllowOverride None
    DirectoryIndex gitweb.cgi
    Order allow,deny
    allow from all
</Directory>
$ cd ../sites-enabled
$ sudo ln -s ../sites-available/gitweb 001-gitweb
$ sudo service apache2 restart

これで http://server/cgi-bin/gitweb.cgi で見えます。

gitosisのレポジトリについては、そのままではパーミッションがありません。
しょうがないので変更してしまいます。

$ chmod 755 /srv/git/repositories/*.git

このあたりは、いまいちなので、うまい回避策調査中です。

Ubuntu Server に Redmine をインストールしてみる

Redmineとは、Ruby on Railsで書かれたBTSです。Bugzillaとかに変わって最近人気なようなので、試しにUbuntu Serverにインストールしてみました。


基本的には公式に書いてある通りやれば、たいして難しい事でもないのですが、いくつか小ハマリがあったので、残しておきます。


Redmine.JP

Redmine の構築

まずは依存するいくつかのパッケージを apt でインストール。ベースのRubyを入れます。DBはMySQLで構築する予定なので、MySQL関連も一緒に入れます。

$ sudo apt-get install ruby rubygems mysql-server mysql-client


RedmineRuby on Rails 依存なので、その関係の gem インストール。

$ sudo gem install rails mysql


ベース部分のインストールができたら、次は本体を入れます。レポジトリから落としてきて配置するだけです。

$ svn checkout http://redmine.rubyforge.org/svn/trunk/ redmine
$ sudo mv redmine /var/lib/rails/
$ sudo chown root:root /var/lib/rails/redmine
$ cd /var/lib/rails/redmine


続いては DB の設定。

$ mysql -u root -p
SQL> GRANT ALL PRIVILEGES ON *.* TO redmine@localhost IDENTIFIED BY 'redminepassword' WITH GRANT OPTION;
SQL> create database redmine
SQL> \q


Redmine 本体側の設定もします。config/database.yml で接続する DB の設定をします。複数設定を書いて置いて、切り替えて使うような使い方もできるみたい。rake を使って DB 周りの初期化をします。

$ config/database.yml
production:
  adapter: mysql
  database: redmine
  username: redmine
  password: redminepassword
  host: localhost
  encoding: utf8
$ sudo rake config/initializers/session_store.rb
$ sudo rake db:migrate RAILS_ENV=production
$ sudo rake redmine:load_default_data RAILS_ENV=production

一応 config/email.yml で e-mail の設定も。

$ sudo vi config/email.yml
production:
  delivery_method: :smtp
  smtp_settings:
    address: localhost
    port: 25
    domain: mkataigi.com


基本的にはこれだけで大丈夫なハズ。Rails の組み込みのサーバを起動させればもう見えます。

$ sudo script/server -e production

http://localhost:3000/ でアクセスできます。

Passenger 上で動かす

公式に Passenger で動かす方法も書いてあるのでやってみます。Passenger とは、apache モジュールで Rails をデプロイするものです。


まずは Passenger を入れます。

$ sudo gem install passenger


どうやらパスも通しておかないといけないようなので、設定します。

$ vi ~/.bashrc
export APXS2=/usr/local/apache2/bin/apxs
export PATH=/usr/local/apache2/bin:$PATH


次は passenger-install-apache2-module という、インストールスクリプトを実行するようなのですが、これが見つかりません。locate で探すとちょっと予想外のところに入っていたので、フルパス指定で実行。

$ sudo /var/lib/gems/1.8/bin/passenger-install-apache2-module


実行するといくつか足りてないライブラリを指定されるので、表示されるとおりに実行してインストール。一通りインストールして、再度上記スクリプトを実行したところ、インストールできたみたい。


あとは、apache 側で設定します。

$ sudo vi /etc/apache2/mods-available/ruby_passenger.load
LoadModule passenger_module /var/lib/gems/1.8/gems/passenger-2.2.11/ext/apache2/mod_passenger.so
$ sudo vi /etc/apache2/mods-available/ruby_passenger.conf
PassengerRoot /var/lib/gems/1.8/gems/passenger-2.2.11
PassengerRuby /usr/bin/ruby1.8
$ cd /etc/apache2/mods-enabled
$ sudo ln -s ../mods-available/ruby_passenger.load .
$ sudo ln -s ../mods-available/ruby_passenger.conf .
$ sudo vi /etc/apache2/sites-available/redmine
RailsBaseURI /redmine
DocumentRoot /var/www
$ cd ../sites-enabled/
$ sudo ln -s ../sites-available/redmine 001-redmine


Redmineapache で見える場所にリンクを貼ります。

$ cd /var/www
$ sudo ln -s /var/lib/rails/redmine/public redmine

Rails って、public の部分にリンク貼ればいいんですね。


あとは apache を再起動すれば OK。

$ sudo service apache2 restart

http://localhost/redmine/ で確認します。ポート指定いらなくなった。


ちゃんと動いてる!ヨカッタヨカッタ。

グレイコード

先日某勉強会で出たグレイコードについて、一応概念的には知っていたのですが、実装とかをよく知らなかったため調査。

グレイコードについてはWikipediaに結構詳しく書いてあります。
グレイコード - Wikipedia


このグレイコード、何がいいかというと、数字的な近さがそのままグレイコード表現でも近くなることです。

普通の2進数の場合だと、例えば、

7 => 0111
8 => 1000

となって、数字上ではとなりの数字なのに、2進数では4ビットも違う表現になってしまいます。
しかし、グレイコードの場合は、

7 => 0100
8 => 1100

のようになって、数字上のとなりの数字が、グレイコード表現でも1ビット違いで表現されます。


このグレイコードの構成方法ですが、いろいろとあるのですが、ひとつの簡単な方法としては「反射2進グレイコード」というものがあります。
これは前半部分のグレイコードを反転して、先頭に0,1をつけることによってグレイコードの続きを作っていく方法です。


説明だとよくわからないので、実例で。

 0          0            00
 1   反転   1  0,1付与   01
---  ===>  ---  ======> ----
            1            11
            0            10


この数字 => グレイコード変換は単純な2進演算で実装できます。
この変換を実装するとこんな感じ。

#!/usr/bin/perl

use strict;
use warnings;

for (0 .. 15) {
    my $gray = $_ ^ ($_ >> 1);
    print sprintf("%2d => %04b\n", $_,  $gray);
}

結果

$ ./graycode.pl
 0 => 0000
 1 => 0001
 2 => 0011
 3 => 0010
 4 => 0110
 5 => 0111
 6 => 0101
 7 => 0100
 8 => 1100
 9 => 1101
10 => 1111
11 => 1110
12 => 1010
13 => 1011
14 => 1001
15 => 1000


こんな感じで数字からグレイコードへの変換は簡単にできます。
ただ、逆のグレイコードから数字への変換はちょっと難しいようです。
ここら辺は後でもうちょっと詳しく調ベる。




ハッカーのたのしみ—本物のプログラマはいかにして問題を解くか

MacPortsのソフトウェアを一括でインストールするスクリプト書いた

先日、mac portsのソフトウェアの依存関係がどうにもおかしくなってしまっていたので、一念発起してまっさらにして入れなおしました。
アンインストールする方は結構簡単にいくんですが、アンインストールした物を再度インストールしなおすのが大変。
mac portsではローカルでコンパイルしてるらしいので、一個一個が結構時間かかるんですね。


どうにも面倒になってきたので、一括でインストールするスクリプト書きました。
とりあえず一回動けばいいので、エラー処理もテストもろくにしてないです。
自分で動かしたときにはうまくいきました。


一応依存関係には配慮して、自動でインストール順を決めるようにはしています。
ただ、ガッツリmac portsの出力依存なので、バージョン変わると動かないかも。
使うときには、インストールしたいportのソフトをvariant付きでひとつのファイルにズラズラ書き出して、それを引数に与えてスクリプトを実行すればOK。

$ port version
Version: 1.8.2
$ cat install_list.txt
gcc43
perl5 +perl5_10
#sqlite3
$ sudo ./port_install.pl install_list.txt

なかでport installを回しているだけなので、相当時間がかかるので、夜中に実行して、朝起きたら終わってる、位の感覚で実行するといいかも。


以下スクリプト本体。

#!/usr/bin/perl

use strict;
use warnings;
use IO::File;


if (scalar(@ARGV) < 1) {
    exit(1);
}

my $filename = $ARGV[0];

my $file = IO::File->new($filename, 'r');
my @not_install = ();
my %variants = ();
while (my $line = $file->getline) {
    chomp $line;
    if ($line ne "" and $line !~ /^\s*#/) {
        my ($cmd, @variant) = split(/\s+/, $line);
        $variants{$cmd} = \@variant;
        push @not_install, $cmd;
    }
}

my %dependencies = ();
for my $cmd (@not_install) {
    my ($name, @deps);
    my $out = `port deps $cmd @{$variants{$cmd}}`;
    for my $l (split(/\n/, $out)) {
        if ($l =~ /Full Name:\s([^ ]*)\s/) {
            $name = $1;
        } elsif ($l =~ /has no Build Dependencies/) {
        } elsif ($l =~ /Build Dependencies:\s+(.*)$/) {
            foreach my $dline (split(/,\s/, $1)) {
                if ($dline ne "" and $dline ne ",") {
                    chomp $dline;
                    push @deps, $dline;
                }
            }
       } elsif ($l =~ /Library Dependencies:\s+(.*)$/) {
            foreach my $dline (split(/,\s/, $1)) {
                chomp $dline;
                if ($dline ne "" and $dline ne ",") {
                    push @deps, $dline;
                }
            }
        }
    }
    $dependencies{$name} = \@deps;
}

my @installed = ();
while (scalar @not_install) {
    my $cmd = shift @not_install;
    my $dep_flag = 0;
    for my $dep (@{$dependencies{$cmd}}) {
        for my $not_install_cmd (@not_install) {
            if ($dep eq $not_install_cmd) {
                $dep_flag= 1;
                last;
            }
        }
        last if $dep_flag;
    }
    if ($dep_flag) {
        push @not_install, $cmd;
    } else {
        push @installed, $cmd;
    }
}

my @install_ok = ();
my @install_ng = ();
for my $cmd (@installed) {
    eval {
        system("port",  "install",  $cmd, @{$variants{$cmd}});
    };
    if ($@) {
        push @install_ng, "$cmd @{$variants{$cmd}}";
        eval {
            system("port",  "clean",  $cmd);
        };
    } else {
        push @install_ok, "$cmd @{$variants{$cmd}}";
    }
}

print "install OK\n" . join("\n", @install_ok) . "\n\n";
print "install NG\n" . join("\n", @install_ng) . "\n\n";