<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
   <channel>
      <title>blog.katsuma.tv</title>
      <link>http://blog.katsuma.tv/</link>
      <description>適当に直感で思ったことを何も考えず発信</description>
      <language>ja</language>
      <copyright>Copyright 2010</copyright>
      <lastBuildDate>Sun, 11 Jul 2010 04:37:18 +0900</lastBuildDate>
      <generator>http://www.sixapart.com/movabletype/?v=3.33-ja</generator>
      <docs>http://blogs.law.harvard.edu/tech/rss</docs> 

            <item>
         <title>Google Codeで管理していたコードをgithubへ移行する</title>
         <description><![CDATA[<p>最近は仕事でgitを使うケースがSubversionと比べて圧倒的に多いので、個人的にGoogle Codeでホスティングしていたコードもgithubに移すことにしました。</p>

<h3>git-svn</h3>
<p>移行作業にはgit-svnが必要になります。MacOSXでgit-svnを使うには、git-coreをmacportsで入れるときに、<strong>+svn</strong>のvariantsをつけてインストールしてあげるとOK。ぼくはすでにgit-coreをインストールしていたので、次のようにしてインストールしなおしました。</p>

<p><pre>
sudo port deactivate git-core
sudo port install git-core +svn
</pre></p>

<h3>作業用ディレクトリの作成</h3>
<p>作業用の適当なディレクトリを作ります。</p>
<p><pre>
mkdir ~/Desktop/git
cd ~/Desktop/git
</pre></p>

<h3>authors.txtの作成</h3>
<p>次のような内容のauthors.txtを作成。(no author)はGoogle Codeの初期設定で、名無しさんがtrunk, branches, tagsを作成しているようなので、この２行が必要になります。左辺はGoogleアカウント名、右辺はgithubに登録した名前とメールアドレスです。</p>
<p><pre>
ryo katsuma = ryo katsuma &lt;katsuma@gmail.com&gt;
(no author) = ryo katsuma &lt;katsuma@gmail.com&gt;
</pre></p>

<h3>移行用レポジトリを作成</h3>
<p>githubで移行用のレポジトリを作成します。作成は<a href="http://github.com/repositories/new">ここ</a>から。</p>

<h3>移行</h3>
<p>ここまでくるとあとは簡単。</p>
<p><pre>
git svn clone -s -A ./authors.txt http://svn_repo.googlecode.com/svn repo
cd repo/
git remote add origin git@github.com:katsuma/new_repo.git
git push origin master
</pre></p>

<h3>まとめ</h3>
<p>Google Codeからgithubの移行は、実作業はauthors.txtを用意するくらいで、全体としてそんなに複雑なものではなかったと思います。
ちなみに今回の作業を通して<a href="http://www.tokyo-jogging.com/">Tokyo-Jogging</a>のコードを全部<a href="http://github.com/katsuma/tokyo-jogging">github</a>に移しました。
コード管理はもちろん、サイト全体の操作性なんかもGoogle Codeと比べてgithubの方が優れていると思うので、移行して正解だったかなーと感じています。
</p>]]></description>
         <link>http://blog.katsuma.tv/2010/07/from_googlecode_to_github.html</link>
         <guid>http://blog.katsuma.tv/2010/07/from_googlecode_to_github.html</guid>
         <category>develop</category>
         <pubDate>Sun, 11 Jul 2010 04:37:18 +0900</pubDate>
      </item>
            <item>
         <title>「よくわかるAmazonEC2/S3入門」を献本いただきました</title>
         <description><![CDATA[<p>株式会社学びingの<a href="http://twitter.com/igarashi">五十嵐学</a>様より「<a href="http://www.amazon.co.jp/gp/product/4774142840?ie=UTF8&tag=katsumatv-22&linkCode=as2&camp=247&creative=7399&creativeASIN=4774142840">よくわかるAmazonEC2/S3入門</a>」を献本いただきました。</p>

<p>本書は、EC2, S3を中心とするAWSの導入、運用方がをボリュームよくまとまったかなりの良本です。</p>

<h3>目次</h3>
<p>
<ul style="list-style-type: none">
<li>■第1章　クラウドコンピューティングへの招待 
<ul>
<li>1-1 クラウドコンピューティングの隆盛</li>
<li>1-2 クラウドコンピューティングとは何か</li>
<li>1-3 サービス提供側から見るクラウドコンピューティング</li>
<li>1-4 クラウドコンピューティングの3つの分類</li>
<li>1-5 クラウドコンピューティングの主要プレイヤー</li>
</ul>
</li>

<li>■第2章　Amazon EC2/S3で何をするのか
<ul>
<li>2-1 Amazon EC2</li>
<li>2-2 Amazon EC2</li>
<li>2-3 Amazon S3</li>
<li>2-4 料金体系</li>
</ul>
</li>

<li>■第3章　Amazon EC2/S3導入手順詳細
<ul>
<li>3-1 Amazon EC2/S3を使うまでの準備</li>
<li>3-2 GUIツールからの操作（AWS Management Console） </li>
<li>3-3 コマンドラインからの操作</li>
<li>3-4 Amazon S3を利用する</li>
</ul>
</li>

<li>■第4章　Amazon EC2使用方法
<ul>
<li>4-1 Amazon EC2でLinuxを使う</li>
<li>4-2 Amazon EC2でWindowsを使う</li>
</ul>
</li>

<li>■第5章　Amazon EC2/S3の応用例
<ul>
<li>5-1 Amazon EC2のオプション</li>
<li>5-2 Amazon S3のオプション</li>
<li>5-3 その他のオプション</li>
<li>5-4 Amazon EC2/S3　ツール集</li>
</ul>
</li>

<li>■第6章　AWSにおける運用管理
<ul>
<li>6-1 運用上における物理サーバとAmazon EC2の違いとは</li>
<li>6-2 サーバ種類別の考察</li>
<li>6-3 AMIをゼロから作る</li>
</ul>
</li>

<li>■第7章　Amazon EC2/S3ができること，できないこと
<ul>
<li>7-1 相性が良い想定利用シーン</li>
<li>7-2 相性が悪い想定利用シーン</li>
<li>7-3 当社で起きた特殊な事件</li>
<li>7-4 その他注意点</li>
<li>7-5 Amazon EC2/S3は使えるのか？</li>
</ul>
</li>

<li>■Appendix　コマンドリファレンス</li>
</ul>
</p>

<h3>AWS導入検討時は何よりまず読むべき</h3>
<p>一通り読んでみて感じたことは、「僕がAWSを初めてまともに使った１年前にこの本があれば。。。」と、いうこと。導入にあたってのアカウントの作成方法、料金計算方法、Webインターフェースとコマンドツールの細かな説明から運用上の諸注意まで全部一通り掲載されてあって、AWS日本語公式サイトがまだ存在しない今だと、へたに検索して１つ１つ調べるよりよっぽど有益な情報を効率よく収集できます。</p>

<p>個人的に一番よかったのは、６章「AWSにおける運用管理」と７-3「当社でおきた特殊な事件」。AWSの実運用事例はまだまだ国内では少ないので、このあたりの実際に使ってみてはじめて分かる、目の当たりにする困難な点は情報として絶対量もまだまだ多くありません。その点で、これらの章は使った人にとっては「あるある！！」と思える点ばかりで、AWSユーザ視点での生の声が集まったかなり貴重な章と言えると思います。あと、Auto ScalingやElastic Load Balancingなんかは、まだ使ったことがなかったので、そのあたりの情報は普通にかなり参考になりました。</p>

<p>と、いうわけでAWSの導入を検討している人は当然のこと、AWSのサービスを断片的には使っているもののサービス間の連携についての知識が不十分だと思える人にとって、本書は必須な本だと思います。かなりオススメ！</p>

<p>
<iframe src="http://rcm-jp.amazon.co.jp/e/cm?lt1=_blank&bc1=000000&IS2=1&bg1=FFFFFF&fc1=000000&lc1=0000FF&t=katsumatv-22&o=9&p=8&l=as1&m=amazon&f=ifr&md=1X69VDGQCMF7Z30FM082&asins=4774142840" style="width:120px;height:240px;" scrolling="no" marginwidth="0" marginheight="0" frameborder="0"></iframe>
</p>]]></description>
         <link>http://blog.katsuma.tv/2010/07/amazon_ec2_s3_introduction_book.html</link>
         <guid>http://blog.katsuma.tv/2010/07/amazon_ec2_s3_introduction_book.html</guid>
         <category>aws</category>
         <pubDate>Mon, 05 Jul 2010 02:55:29 +0900</pubDate>
      </item>
            <item>
         <title>memcached vs TokyoCabinet vs TokyoTyrant vs Redis</title>
         <description><![CDATA[<p>NoSQLの話題が周りで盛り上がっているので、有名どころのライブラリのset/getのベンチマークを取ってみることにしました。対象はmemcached, TokyoCabinet, TokyoTyrant, Redisの４種類。gemで入れたruby用のバインディングを利用して1000件のデータをset, getしています。結果はこんなかんじ。</p>

<table>
<thead>
<th>&nbsp;</th>
<th>user</th>
<th>system</th>
<th>total</th>
<th>real</th>
</tr>
</thead>

<tbody>
<tr><td>memcached:set</td><td>0.120000</td><td>0.030000</td><td>0.150000</td><td>(  0.213069)</td></tr>
<tr><td>memcached:get</td><td>0.150000</td><td>0.030000</td><td>0.180000</td><td>(  0.238989)</td></tr>
<tr><td>TokyoCabinet:set</td><td>0.000000</td><td>0.000000</td><td>0.000000</td><td>(  0.002802)</td></tr>
<tr><td>TokyoCabinet:get</td><td>0.000000</td><td>0.000000</td><td>0.000000</td><td>(  0.001759)</td></tr>
<tr><td>TokyoTyrant:set</td><td>0.010000</td><td>0.000000</td><td>0.010000</td><td>(  0.005384)</td></tr>
<tr><td>TokyoTyrant:get</td><td>0.030000</td><td>0.000000</td><td>0.030000</td><td>(  0.038285)</td></tr>
<tr><td>Redis:set</td><td>0.040000</td><td>0.030000</td><td>0.070000</td><td>(  0.147060)</td></tr>
<tr><td>Redis:get</td><td>0.040000</td><td>0.020000</td><td>0.060000</td><td>(  0.151168)</td></tr>
</tbody>
</table>

<p>当然のごとくmemcachedが最速だろう。。。と思いきや、そうでもない結果に。むしろ一番遅い結果に。なんだこれーーーと思って調べ続けていたのですが、バインディングのgemのコードを追いかけるかぎり、どうもこれはmemcache-clientの実装が原因のよう。</p>

<p>これは、memcache-clientの実装はpure-rubyで実装されているのに対して、TokyoCabinet/TokyoTyrantのバインディングの実装はnativeコードで実装されてあるのが原因のようです。事実、TokyoTyrantはmemcacheプロトコルを実装しているので、memcache-clientを利用してTokyoTyrantにアクセスすると両者はこんな結果になりました。</p>

<table>
<thead>
<th>&nbsp;</th>
<th>user</th>
<th>system</th>
<th>total</th>
<th>real</th>
</thead>
<tbody>
<tr><td>memcache:set</td><td>0.120000</td><td>0.040000</td><td>0.160000</td><td>(  0.189803)</td></tr>
<tr><td>memcache:get</td><td>0.150000</td><td>0.030000</td><td>0.180000</td><td>(  0.240141)</td></tr>
<tr><td>TokyoTyrant:set</td><td>0.130000</td><td>0.030000</td><td>0.160000</td><td>(  0.238009)</td></tr>
<tr><td>TokyoTyrant:get</td><td>0.130000</td><td>0.020000</td><td>0.150000</td><td>(  0.271598)</td></tr>
</tbody></table>

<p>TokyoTyrantのアクセス速度は一気に遅くなりました。やっぱりRuby実装に引きづられているみたいですね。。</p>

<p>ちなみに、Redisもsetに限るとmemcacheプロトコルと同じプロトコルを利用できるので、そのベンチをとってみると</p>

<table>
<thead>
<th>&nbsp;</th>
<th>user</th>
<th>system</th>
<th>total</th>
<th>real</th>
</tr>
</thead>
<tbody>
<tr><td>Redis:set</td><td>0.040000</td><td>0.010000</td><td>0.050000</td><td>(  0.091300)</td></tr></tbody></table>

<p>と、なってmemcacheクライアントを利用したときのmemcached, TokyoTyrantと比較しても圧倒的に高速だということがわかりました（おもしろい！）</p>

<h3>まとめ</h3>
<ul>
<li>オンメモリだからmemcachedが高速、とは限らない</li>
<li>memcache-clientは遅いので注意</li>
<li>各ライブラリのオリジナルのバインディングを利用した場合、高速順に並び替えるとTokyoCabinet, TokyoTyrant, Redis, memcachedになる</li>
</ul>


<p>と、いうわけで、memcachedが高速なことを確認するためにベンチマーク取ってみたのですが、実装によってはまったく異なる結果になることが分かって、なかなかおもしろかったです。なお、今回利用したコードは<a href="http://gist.github.com/436046">gist</a>に掲載しています。</p>]]></description>
         <link>http://blog.katsuma.tv/2010/06/memcached_vs_tokyocabinet_vs_tolyo_tyrant_vs_redis.html</link>
         <guid>http://blog.katsuma.tv/2010/06/memcached_vs_tokyocabinet_vs_tolyo_tyrant_vs_redis.html</guid>
         <category>kvs</category>
         <pubDate>Sun, 13 Jun 2010 02:39:01 +0900</pubDate>
      </item>
            <item>
         <title>ClouderaベースのAMIのHiveのバージョンを上げる方法</title>
         <description><![CDATA[<p>Clouderaの提供しているAMIはバージョン１(CDH1)から３(CDH3)まであるのですが、それぞれ梱包されてあるHadoopとその上モノのHive, Pigのバージョンは異なります。</p>

<div>
<table border="1">
<thead>
<tr>
<th>CDH Release</th>
<th>Hadoop 0.18</th>
<th>Hadoop 0.20</th>
<th>Hive</th>
<th>Pig</th>
</tr>
</thead>

<tbody>
<tr>
<td>CDH1</td>
<td>hadoop_0.18.3-6cloudera0.3.0</td>
<td>N/A</td>
<td>hive_0.3.0-0cloudera0.3.0</td>
<td>pig_0.2.0-0cloudera0.3.0</td>
</tr>

<tr>
<td>CDH2</td>
<td>hadoop-0.18.3+76.2</td>
<td>hadoop-0.20.1+169.56</td>
<td>hive-0.4.1+14.4</td>
<td>pig-0.5.0+11.1</td>
</tr>

<tr>
<td>CDH3</td>
<td>N/A</td>
<td>hadoop-0.20.2+228</td>
<td>hive-0.5.0+20</td>
<td>pig-0.5.0+30</td>
</tr>

</tbody>
</table>

<p> via <a href="http://archive.cloudera.com/docs/_choosing_a_version.html">1.2.1. Choosing a Version</a></p>
</div>

<p>CDHは常にupdateしていて、現在の最新リリースであるCDH3も2010年5月5日現在ではテスト版扱いですが、これもじきにStable版としてリリースされることになるかと思います。</p>

<p>さて、そうるとClouderaのAMIを使っていて、特定のバージョンに上げたい、というのは結構自然な流れかと思います。このとき、バージョンを上げる流れとしては次のような流れになります。</p>

<p><ol>
<li>Hadoopとその上モノであるHive, Pigなどをパッケージ管理ツールを利用して全てアンインストール。</li>
<li>パッケージ管理ツールのレポジトリを追加</li>
<li>パッケージ管理ツールを利用してHadoopをインストールし直し</li>
<li>パッケージ管理ツールを利用してHive, Pigなどをンストールし直し</li>
</ol></p>

<p>要するに、全ソフトウェアのバージョンをまとめて上げるのではなく、Hadoopかまたはそれ以外の特定のソフトウェアについて、パッケージ管理ツールを利用してバージョンを上げる、ということが可能になります。このとき、Hadoopについては新たに設定項目がかなり多かったり、AMIを作りなおさないと試すことができなかったりと面倒なことが多いのですが、逆にHiveやPigなどHadoopの上モノについては、AMIを作り直すこともなく、その場でバージョンを上げることも結構簡単にできます。</p>

<p>たとえば、HiveのバージョンをCDH1→CDH2に上げる場合は次のような手順で可能です。</p>

<p>まず、既存にインストールされてあるHiveをアンインストールします。たとえばFedoraベースの　AMIの場合は、パッケージ管理ツールとしてはyumを利用することが可能です。</p>

<p><pre>
yum remove hadoop-hive
</pre></p>

<p>次に、CDH2用のyumのレポジトリを追加します。あとえばCDH2用のレポジトリを追加するときは、こんなかんじ。CDH3用のレポジトリを追加したい場合は、URLの最後をcloudera-cdh3.repoに変更ください。</p>

<p><pre>
cd /etc/yum.repos.d/
wget http://archive.cloudera.com/redhat/cdh/cloudera-cdh2.repo
</pre></p>

<p>これで、最新のパッケージを扱える状態になりました。ここでHiveだけCDH2仕様のver0.40系にしてみましょう。</p>

<p><pre>
yum -y install hadoop-hive
</pre></p>

<p>これで、0.40.xのHiveがインストールされました。また、設定ファイル(/etc/hive/conf/hive-site.xml)は、オリジナルのものに戻ってしまっているので、適宜直しておきましょう。ぼくは以下の箇所を変更、追加しました。</p>

<p><ul>
<li>javax.jdo.option.ConnectionURL</li>
<li>javax.jdo.option.ConnectionDriverName</li>
<li>javax.jdo.option.ConnectionUserName</li>
<li>javax.jdo.option.ConnectionUserPassword</li>
</ul</p>

<p>いかがでしたでしょうか？Hiveについては、アップグレードは非常に簡単だったかと思います。同じように、PigについてもHadoopの上モノなので同様の手順でアッグレード可能になります。これなら割と気軽にバージョン上げたりパッチ当てたりなんかもできそうですね。</p>

<p>また、Hadoop本体のアップグレードについても、次回は挑戦してみたいと思います。</p>]]></description>
         <link>http://blog.katsuma.tv/2010/05/hive_version_up_on_cloudera_based_ami.html</link>
         <guid>http://blog.katsuma.tv/2010/05/hive_version_up_on_cloudera_based_ami.html</guid>
         <category>aws</category>
         <pubDate>Thu, 06 May 2010 03:00:00 +0900</pubDate>
      </item>
            <item>
         <title>京都でクラウドの取り組みについて発表してきました</title>
         <description><![CDATA[<p>4月16, 17日に京都で「アグレッシブなクラウドの使い方」というタイトルで、会社でのクラウドの取り組みについて話してきました。</p>

<div style="width:425px" id="__ss_3827098">
<object id="__sse3827098" width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=engineer-event-100417-kyoto-100423034302-phpapp02&stripped_title=engineer-event-in-kyoto-100417" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed name="__sse3827098" src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=engineer-event-100417-kyoto-100423034302-phpapp02&stripped_title=engineer-event-in-kyoto-100417" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object></div>


<p>話の中身としては、僕と<a href="http://blog.livedoor.jp/sasata299">sasata299</a>さんがいろんなところで話してきたクラウド系の話の総集編みたいなものになっています。あと、RDSとかPigについて話したのは今回が初になります。</p>

<p>発表の後のTwitterでのTLを追いかけてると、「内容がちょっと分かりづらかった」という声もちらほらあったようですが、たしかにそれは間違っていなくて、AWS系のサービスの内容とHadoopについての仕組みが一通り理解できている前提での内容でしたので、かなり難解だった方も多かったかと思います。と、いうわけで参加されていた方々は、もう一度キーワードレベルで見直していただくなりして、内容を再確認いただければ幸いです。</p>]]></description>
         <link>http://blog.katsuma.tv/2010/05/aws_kyoto_predentation_201004.html</link>
         <guid>http://blog.katsuma.tv/2010/05/aws_kyoto_predentation_201004.html</guid>
         <category>aws</category>
         <pubDate>Sun, 02 May 2010 02:39:29 +0900</pubDate>
      </item>
            <item>
         <title>redisでユーザをfollowしたときにTimeLineをsortして再構築</title>
         <description><![CDATA[<p><a href="http://blog.katsuma.tv/2010/03/redtweet_by_redis_and_rails.html">前回</a>のつづき。</p>

<p>課題の1つに挙げてた中で、「Followした瞬間に、そのユーザの過去のTweetを自分のTLに追加できていない」というのがありましたが、こんなかんじでいいのかな。自分のTLに他人のTLを混ぜて、sortしてstoreし直し。(redis-rbが0.2.0じゃないと動かないかも)</p>

<pre>
  def merge_timeline(user_id)
    my_id = @login_user[:id]
    return if @redis.type?("uid:#{user_id}:posts") == "none"

    user_statuses = @redis.lrange("uid:#{user_id}:posts", 0, 100)
    user_statuses.each do |status|
      @redis.lpush("uid:#{my_id}:home", status)
    end
    @redis.sort("uid:#{my_id}:home", :order => "desc alpha", :store => "uid:#{my_id}:home")
  end
</pre>

<p>でも、そうしたあとにremoveしたときにまた再構築し直さないと駄目なことに気づいた。。と、いうかremove面倒ですねぇ、どうするんだろう。泥臭く全statusを走査し直しなのか、それとも順序付Setとか使えば楽にremoveできるのかな。また考え直しです。</p>

<p>あと、このupdateについて、github上の<a href="http://github.com/katsuma/RedTweet">RedTweet</a>のコードもpushし直してますので、興味ある方はご確認ください。</p>]]></description>
         <link>http://blog.katsuma.tv/2010/03/sort_timeline_by_redis.html</link>
         <guid>http://blog.katsuma.tv/2010/03/sort_timeline_by_redis.html</guid>
         <category>ruby</category>
         <pubDate>Sat, 27 Mar 2010 06:10:39 +0900</pubDate>
      </item>
            <item>
         <title>redisとRailsでTwitterクローン「RedTweet」を作りました</title>
         <description><![CDATA[<p>前回「<a href="http://blog.katsuma.tv/2010/03/start_redis.html">Mac OSXにredisをインストール</a>」で、redisを動かす環境まではできたので、せっかくなんでテスト的に何かサービスを作ってみよう、ということでTwitterクローンのRedTweetを作ってみました。</p>

<p><ul><li><a href="http://github.com/katsuma/RedTweet">RedTweet</a></li></ul></p>

<p>redisを使ったTwitterクローンは、PHP版の<a href="http://retwis.antirez.com/">Retwis</a>と、それをSinatraで書き直した<a href="http://retwisrb.danlucraft.com/login">Retwis-RB</a>があるのですが、サンプルコードはいくらっても世の中に少しは役立つだろうと思ってRails版で実装してみました。オンラインで動作できる環境はないので、git cloneしてscript/serverで手元の起動で確認ください、、と投げやり気味ですみません。とりあえず次の項目は一通り実装しています。</p>

<p><ol>
<li>ユーザID発行</li>
<li>Login / Logout</li>
<li>Follow / Remove</li>
<li>自分のTimeline, Public Timeline, 各ユーザのTimelineの閲覧</li>
</ol></p>

<p>ちなみにRedTweetって名前はRedisとTweetを混ぜて直感でつけた名前で、git pushしたあとで同じ名前のサイトがあることが発覚したくらい直感でつけた名前です。</p>


<h3>目的</h3>
<p>さて、今回はまじめにTwitterクローンを作ることが目的ではなくて、実際は、次の項目を目的として実装してみました。</p>

<p><ol>
<li><a href="http://code.google.com/p/redis/wiki/TwitterAlikeExample">Retwisのデザイン</a>を読んで、それに従って一通り実装してみる</li>
<li>redisのAPIの仕様を学ぶ</li>
<li>RDBを一切使わない、NoSQLでWebサービスを作るためのノウハウを身につける</li>
</ol></p>

<p>結局全て似通った話になるのですが、上記のデザイン仕様書はTwitter的なサービスを作り上げることで、KVSをどのように利用すればいいのか、がかなり分かりやすく説明されてあるので、いい勉強になりました。また、ユーザ情報はString, 各TLはList, Following/FollowerをSetで管理することで、redisの主要なAPIを網羅できたことも、redisの学習に役立ちました。
</p>

<p>と、同時に課題もすでに見えていて、</p>

<p><ol>
<li>スケーリングがどこまでできるかはまだ手元で理解できていない</li>
<li>やっぱりActiveRecord的にラップしたライブラリは必須</li>
<li>Followした瞬間に、そのユーザの過去のTweetを自分のTLに追加できていない</li>
</ol></p>

<p>なんかが今の段階で挙げられます。1.はテストデータを作ることで解決するはず。2.はやっぱりmustだなぁ、と思えるところまでははっきりした理解で、ユーザ名をIDから引くときなど毎回決まったprefixがついたkeyから探索するのは冗長すぎてやってられません。<a href="http://ohm.keyvalue.org/">Ohm</a>というHashとObjectのマッピングライブラリもあるので、このあたりも１度使ってみたほうが良さそうだな、というところ。3.はFollowした瞬間に一定数TweetをListにLPUSHして、そのlistの中で<a href="http://code.google.com/p/redis/wiki/SortCommand">SORT</a>すればいいのかな？？正直、SORTまだよくわかってません。</p>

<h3>まとめ</h3>
<p>というわけで、課題は多いものの、redisとRailsで最低限の動作をするものは実装できました。NoSQLでもサービスを作り上げることは理解できたので、Ohmなど、他のライブラリも使ったりすることで、 redisの利点をもっと伸ばして理解を深めたいな、というところですね。</p>]]></description>
         <link>http://blog.katsuma.tv/2010/03/redtweet_by_redis_and_rails.html</link>
         <guid>http://blog.katsuma.tv/2010/03/redtweet_by_redis_and_rails.html</guid>
         <category>ruby</category>
         <pubDate>Thu, 25 Mar 2010 02:04:56 +0900</pubDate>
      </item>
            <item>
         <title>Mac OSXにredisをインストール</title>
         <description><![CDATA[<p>Tokyo Cabinet / Tokyo Tyrantに代表されるKey-Value Storage,いわゆるKVSは多くのプロダクトが乱立してなかなか違いを理解するのも難しい状況になりつつあるのですが、ここ数日は<a href="http://code.google.com/p/redis/">redis</a>に注目をしています。redisとは何ぞやというと、公式サイトには次のような特徴が挙げられています。</p>

<p>
<ul>
<li>memcachedのようないわゆるKVS</li>
<li>valueにはStringだけではなく、List, Setも利用できる</li>
<li>データに対するpush/pop, add/removeのような操作はすべてatomicな操作</li>
<li>通常はメモリ上で動作するが、定期的にデータをディスクに書き出す（常に書き出すような設定も可能）</li>
<li>Master-Slaveのレプしケーションをサポート</li>
<li>Ruby, Python, Perl, Java...などの各言語のバインディングを用意</li>
</ul>
</p>

<p>と、かなり豪華なスペックで、なんでもかかってこい！なプロダクトです。国内の利用例はまだ聴いた事無いですが、海外では<a href="http://www.atmarkit.co.jp/news/201003/16/redis.html">githubやCraigslistが採用</a>したことでここ最近有名になってきました。</p>

<p>さて、そんなredisの開発環境を整えてみたいと思います。環境はMac OSX 10.5。</p>

<h3>redisのインストール</h3>
<p>ソースコードから入れてもいいのですが、Macの場合は、MacPortsでインストール可能です。</p>
<p><pre>
$sudo port -d sync
</pre></p>

<p>で、インストールリストを最新の状態にしておいて</p>
<p><pre>
$sudo port install redis
</pre></p>

<p>で、インストールされる、、はずなのですが、僕の環境だと途中で止まりました。</p>

<p><pre>
$ sudo port install redis
--->  Fetching redis
--->  Attempting to fetch redis-1.2.2.tar.gz from http://redis.googlecode.com/files/
--->  Verifying checksum(s) for redis
--->  Extracting redis
--->  Configuring redis
--->  Building redis
--->  Staging redis into destroot
--->  Creating launchd control script
###########################################################
# A startup item has been generated that will aid in
# starting redis with launchd. It is disabled
# by default. Execute the following command to start it,
# and to cause it to launch at startup:
#
# sudo launchctl load -w /Library/LaunchDaemons/org.macports.redis.plist
###########################################################
---&gt;  Installing redis @1.2.2_0
---&gt;  Activating redis @1.2.2_0
Error: Target org.macports.activate returned: couldn't open "/opt/local/var/log/redis.log": no such file or directory
Error: Status 1 encountered during processing.
</pre></p>

<p>なんかlogディレクトリがないみたいなので、ディレクトリ作成してから一度アンインストールしてやりなおしてみます。</p>

<p><pre>
$ sudo mkdir /opt/local/var/log
$ sudo port uninstall redis
$ sudo port install redis
==================================================================
* To start up a redis server instance use this command:
* 
*   redis-server /opt/local/etc/redis.conf
* 
==================================================================

--->  Cleaning redis

</pre></p>

<p>これで、インストールできました。サービスに登録したい場合は、途中のログに書いてあるとおり、</p>

<p><pre>
sudo launchctl load -w /Library/LaunchDaemons/org.macports.redis.plist
</pre></p>

<p>で、OKです。</p>

<h3>Rubyのバインディングのインストール</h3>
<p>僕は普段Rubyを使うので、Rubyのバインディングもあわせてインストールしてみることにします。gemでインストール可能です。</p>

<p><pre>
sudo gem install redis
</pre></p>


<h3>redisの起動</h3>
<p>redisを起動するときは、redis-serverを実行します。MacPortsでインストールした場合、/opt/local/bin にバイナリがインストールされてあるので</p>

<p><pre>
sudo /opt/local/bin/redis-server /opt/local/etc/redis.conf
</pre><p>

<p>で、起動します。confの中には、起動するときのポート番号や、ディスクに書き出すタイミングや条件などの設定項目があります。（ちなみに、起動時に設定ファイルのパスを与えていますが、これはビルド時？に設定しておけば、実行時に与える必要は無いようです。ただ、MacPorts利用時もそれが可能なのかどうか？は不明です）</p>

<p>では、実際に動作を確認してみたいとおもいます。確認するときは、redis-serverと同じ場所にあるredis-cli, またはtelnetで6379に対して接続してコマンドを入力します。（今回はtelnetで接続して生のコマンドを叩いて確認してみます）ValueをStringとして扱うときは、
set <key> <data_size>\r\n<data>でデータをセット, get <value>でデータを確認できます。</p>

<p><pre>
set foo 3
bar
+OK

get foo
$3
bar
</pre></p>

<p>listとして扱うときは、lpush <key> <data_size>\r\n<data>,  lrange <key> <start_index> <end_index> などのコマンドを利用します。下記の例のlrangeの0は開始インデックス、-1は末尾の意味になります。</p>

<p><pre>
lpush artists 8
fishmans
+OK

lpush artists 9
clammbon
+OK

lpush artists 7
polaris
+OK

lrange artists 0 -1
*3
$7
polaris
$8
clammbon
$8
fishmans
</pre></p>

<p>Listの要素追加もStringの要素追加と同じでO(1)で実現できるのがredisのポイントですね。実際の細かなコマンドの仕様については、<a href="http://code.google.com/p/redis/wiki/CommandReference">リファレンス</a>を参照ください。</p>

<p>ここまでざっと環境構築まで確認できたので、次回はもうすこしredisを使い倒してその結果をまとめたいと思います。</p>]]></description>
         <link>http://blog.katsuma.tv/2010/03/start_redis.html</link>
         <guid>http://blog.katsuma.tv/2010/03/start_redis.html</guid>
         <category>kvs</category>
         <pubDate>Mon, 22 Mar 2010 02:43:04 +0900</pubDate>
      </item>
            <item>
         <title>第0回AWS User Group Japan勉強会でLTしてきました</title>
         <description><![CDATA[<p>ずいぶんまた長い間があいてしまって今年初エントリになるわけですが、きたる2/23に秋葉原で行われた<a href="http://atnd.org/events/3102">第0回 AWS User Group - Japan勉強会</a>でLTの発表をしてきました。</p>

<p>もともと会社でAWSを使ってることからAmazonの小島様にお声がけいただいて、<a href="http://jaws-ug.jp/">JAWS-UG</a>に参加させていただいて、その流れで今回発表することになったわけですが、５分間のLTだとなかなか話したいことも話し切れないまま時間切れみたいになってしまって若干消化不良。。と、いうわけで、当日駆け足の発表になってよくわからなかった方や、その場での発表を聞けなかった方むけに資料を掲載しておきたいと思います。</p>

<p>内容はHiveとバッチとの連携の話なのですが、Hiveの導入事例はなかなか国内では耳にしないので（僕が耳にしたかぎりY!Japanくらい）、導入を検討してる方々にとって参考になればな、と思います。</p>

<div>
<object width="425" height="355"><param name="movie" value="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=jaws-lt-2010-02-23-100226030120-phpapp01&stripped_title=jaws-lt-2010-02-23" /><param name="allowFullScreen" value="true"/><param name="allowScriptAccess" value="always"/><embed src="http://static.slidesharecdn.com/swf/ssplayer2.swf?doc=jaws-lt-2010-02-23-100226030120-phpapp01&stripped_title=jaws-lt-2010-02-23" type="application/x-shockwave-flash" allowscriptaccess="always" allowfullscreen="true" width="425" height="355"></embed></object>
</div>]]></description>
         <link>http://blog.katsuma.tv/2010/03/jaws_ug_lt.html</link>
         <guid>http://blog.katsuma.tv/2010/03/jaws_ug_lt.html</guid>
         <category></category>
         <pubDate>Sat, 06 Mar 2010 15:58:53 +0900</pubDate>
      </item>
            <item>
         <title>楽天テクノロジーでLT&amp;デモをしてきました</title>
         <description><![CDATA[<p>少し前の情報になるのですが、<a href="http://tech.rakuten.co.jp/rtc2009/">楽天テクノロジーカンファレンス</a>で<a href="http://tokyo-jogging.com/">Tokyo-Jogging</a>ネタのLT&デモを行ってきました。</p>

<p><img src="http://tech.rakuten.co.jp/rtc2009/img/report_demo05.jpg" /></p>

<p>当日は、WiiリモコンだけじゃなくてバランスWiiボードと、最近対応したヌンチャクのデモも行いました。やや古いネタではあるものの、大勢の方に実際に体験いただいて、アドバイスや意見などいただけて楽しい時間を過ごすことができました。</p>

<p>ただ１つ残念だったのはデモブースに常駐してないとダメだったので、他の方の発表がまったく聞けなかったこと。。楽しそうな話いっぱいあったのでそこが残念でした。と、思ったら発表内容は<a href="http://www.ustream.tv/recorded/2412917">Ustream</a>で残っているみたいなので、あとで確認したいとおもいます。</p>

<p>また、ありがたいことにデモ投票では３位(!)の結果をいただけることになりました。LTでは時間切れになっちゃって消化不良だったわけですが、デモで実際に体験いただけたのがよかったのかなとおもいます。</p>

<p>最後に、貴重な場所と機会を提供いただいた楽天株式会社 開発部の方々、どうもありがとうございました！</p>]]></description>
         <link>http://blog.katsuma.tv/2009/11/rtc2009.html</link>
         <guid>http://blog.katsuma.tv/2009/11/rtc2009.html</guid>
         <category>develop</category>
         <pubDate>Sun, 08 Nov 2009 05:37:59 +0900</pubDate>
      </item>
            <item>
         <title>Hive QL(HQL)でORDER BYするときの注意点</title>
         <description><![CDATA[<p>HiveでのSQLことHQLの小ネタ。HQLでは基本的にSQLはほぼ完璧に利用できますが、たまにハマりポイントもあります。その１つが並び替えのORDER BY。</p>

<h3>ORDER BYとSORT BY</h3>
<p>HQLの文法的にORDER BYは有効ですが、実際は並び替えは行われません。（無視されているような感じ）Hiveでは代わりに<strong>「SORT BY [column]」</strong>を利用することになります。</p>

<p>ただし、ここでも罠があって、SORT BYは結果がreducerの数に依存します。(各reducerがsort処理をしたものがマージされるものになるので、全体としてはおかしな結果を得ることになります) 通常、reducerは複数走っているはずなので、結局SORT BYを利用してもORDER BYと同等の結果を得ることができません。</p>

<p>では、どうするか？と言うと明示的にreducerの数を1に指定してからSORT BYを実行すればOKです。</p>

<p><pre>
set mapred.reduce.tasks=1;
SELECT key, value FROM table_name SORT BY key;
</pre></p>

<p>また、Hiveシェルを使わない場合は1ライナーで。</p>

<p><pre>
hive -e 'set mapred.reduce.tasks=1;SELECT key, value FROM table_name SORT BY key;'
</pre></p>

<h3>HQL最適化</h3>
<p>ただ、これだとreducerの数がボトルネックになって、SORT BYと条件文などが組合わさると途端に処理が遅くなることがあります。</p>

<p>なので、このような条件文付きSORT BYを実行するときは、</p>

<p><ol>
<li>複数のreducerが条件文つきHQLでデータを整形し、中間テーブルAを作成</li>
<li>1つのreducerが、中間テーブルAを対象にSORT BYし、条件文は付けない</li>
</ol></p>

<p>な、方針でHQLを分割して実行すると、高速に動作できるかと思います。</p>

<p>ちなみに、このテーブルを分ける（カラムを厳選した中間テーブルを作成する）のはHQLの最適化でかなり有効で、SORT BY以外でもかなり有効なケースが多くあります。このあたりの最適化の話は、また別途まとめたいと思います。</p>]]></description>
         <link>http://blog.katsuma.tv/2009/10/hive_order_by.html</link>
         <guid>http://blog.katsuma.tv/2009/10/hive_order_by.html</guid>
         <category>hadoop</category>
         <pubDate>Wed, 14 Oct 2009 23:57:37 +0900</pubDate>
      </item>
            <item>
         <title>HiveのmetastoreをMySQLを使ってLocal Metastore形式で利用する</title>
         <description><![CDATA[ <p>前回、紹介した<a href="http://blog.katsuma.tv/2009/09/hive_introduction.html">Hive</a>についての続き。</p>

 <p>Hiveは内部で扱うメタデータを「metastore」というデータで保持しています。テーブルやパーティションなどの情報、またレコードが実際に保持されてある場所などのメタデータは全部このmetastoreにまとまっています。このmetastoreは、次の3種類の方法で保存することができます。
</p>

 <p><ul>
     <li>Embeded metastore</li>
     <li>Local Metastore</li>
     <li>Remote Metastore</li>
</ul></p>

 <h3>Embeded metastore</h3>
 <p>Embeded metastoreは主にテスト用途に利用されます。テスト用途なので、単一プロセスからの接続しか許可されていません。
そのため、コンソールを複数起動して、それぞれのコンソールから別のMap&Reduceを走らせる...なんてことができません。ただし、Hiveは初期設定がこのEmbededモードになっているので、特に設定することなくすぐに利用するメリットはあります。</p>

<p>また、metastoreはmetastoreディレクトリ(hive-default.xmlのhive.metastore.urisセクションに記述されています)内の
単一のファイルに保存されることになります。メタデータのバックアップをとりたいときは、このファイルをバックアップ対象にすればOKです。</p>

 <h3>Remote Metastore</h3>
 <p>1つ飛ばして、Remote Metastoreについて。Remote Metastoreはネットワーク越しにmetastoreを扱いたい場合における設定方法です。Hiveクライアントとデータを保存するMySQLの間にThriftサーバをproxyのような形で挟むことで実現しています。Thriftプロトコルを実現できていれば通信が可能なので、実際はJavaのHiveクライアントだけではなく、異なる言語によるクライアントからも接続が可能です。たとえばPHPでの例があるみたいです。</p>

 <p><ul><li><a href="http://www.cultofgary.com/2009/02/24/making-php-talk-to-hive-through-thrift/">Making PHP talk to Hive through Thrift</a></li></ul></p>

 <h3>Local Metastore</h3>

<p>Local Metastoreは、上で述べた２つの形式の間の位置づけのものです。
metastoreを単一ファイルで扱わずに、Remote Metastoreの形式にようにMySQLに保存することで、同一ホスト内から同時に複数のセッションを張ることができます。
このLocal Metastoreは簡単に実現できる割にすごく便利なので、紹介しておきます。
</p>

<h4>DBの設定</h4>
 <p>まず、MySQLでmetastoreを保存する適当なDB、およびその接続ユーザを定義します。たとえばrootで接続し、次のように定義します。</p>

 <p><pre>
create database hive;
grant all privileges on hive.* to user_hive@localhost identified by 'hive_password';
flush privileges;
</pre></p>

 <p>この設定をHiveに反映させるために設定用xmlを編集します。</p>

<h4>hive-site.xmlの編集</h4>
 <p>
Hiveの初期設定はhive-default.xmlにまとまっていますが、この設定はhive-site.xmlという名前のファイルを同一ディレクトリに用意してあげることで上書きできます。
上記設定は次の項目を編集、または追加してあげることで反映されます。
</p>


 <p><pre>
&lt;property&gt;
  &lt;name&gt;hive.metastore.local&lt;/name&gt;
  &lt;value&gt;true&lt;/value&gt;
  &lt;description&gt;controls whether to connect to remove metastore server or open a new metastore server in Hive Client JVM&lt;/description&gt;
&lt;/property&gt;

&lt;property&gt;
  &lt;name&gt;javax.jdo.option.ConnectionURL&lt;/name&gt;
  &lt;value&gt;jdbc:mysql://localhost/hive?createDatabaseIfNotExist=true&lt;/value&gt;
  &lt;description&gt;JDBC connect string for a JDBC metastore&lt;/description&gt;
&lt;/property&gt;

&lt;property&gt;
  &lt;name&gt;javax.jdo.option.ConnectionDriverName&lt;/name&gt;
  &lt;value&gt;com.mysql.jdbc.Driver&lt;/value&gt;
  &lt;description&gt;Driver class name for a JDBC metastore&lt;/description&gt;
&lt;/property&gt;

&lt;property&gt;
  &lt;name&gt;javax.jdo.option.ConnectionUserName&lt;/name&gt;
  &lt;value&gt;hive_user&lt;/value&gt;
  &lt;description&gt;metastore mysql user&lt;/description&gt;
&lt;/property&gt;

&lt;property&gt;
  &lt;name&gt;javax.jdo.option.ConnectionPassword&lt;/name&gt;
  &lt;value&gt;hive_password&lt;/value&gt;
  &lt;description&gt;metastore mysql password&lt;/description&gt;
&lt;/property&gt;

&lt;property&gt;
  &lt;name&gt;hive.metastore.warehouse.dir&lt;/name&gt;
  &lt;value&gt;/user/hive/warehouse&lt;/value&gt;
  &lt;description&gt;location of default database for the warehouse&lt;/description&gt;
&lt;/property&gt;
</pre></p>

 <p>どのプロパティ名も名前からどんなものかは凡そ予想はつくと思います。
ちなみにhive.metastore.warehouse.dirはHDFS上でのファイルパスになるので、ここだけ要注意です。</p>

 <p>xmlを編集したら、hiveクライアントのシェルを立ち上げ直します。
シェル自体はEmbeded Metastoreのときとメッセージ形式も変わらないですが、同時に複数のHQLを実行することができるので、格段に使いやすくなります。
Hiveの利用を考える場合は、Local Metastoreの利用は検討してみる価値はあるのかな、と思います。</p>


  <h3>まとめ</h3>
 <p>Hiveのmetastoreの保存形式について、また、Local Metastoreの形式について、その設定方法をまとめてみました。これらの保存方式については、公式サイトにもまとまっている資料があるので、一度目を通してみるとコンポーネント間の関係が理解しやすいかと思います。</p>

  <p><ul><li><a href="http://wiki.apache.org/hadoop/Hive/AdminManual/MetastoreAdmin?action=AttachFile&do=view&target=metastore_usage.pptx">Metastore Usage</a></li></ul></p>
]]></description>
         <link>http://blog.katsuma.tv/2009/10/hive_local_metastore.html</link>
         <guid>http://blog.katsuma.tv/2009/10/hive_local_metastore.html</guid>
         <category>hadoop</category>
         <pubDate>Mon, 12 Oct 2009 00:56:17 +0900</pubDate>
      </item>
            <item>
         <title>Tokyo-JoggingをSnow Leopardに対応させました</title>
         <description><![CDATA[<p>1年ぶりに<a href="http://www.tokyo-jogging.com/">Tokyo-Jogging</a>をupdateさせました。</p>
<p>さぼってたわけではないのですが、抜本的に通信方法を変更しようとあれこれ試行錯誤していた割に根本的に解決できない問題にぶちあたって途方に暮れていたので、路線変更で小さなバグfixとヌンチャク対応したものを一気にまとめあげてリリースしました。</p>

<p><a href="http://code.google.com/p/tokyo-jogging/downloads/list">Tokyo-Jogging - Downloads</a></p>

<h3>Snow Leopard対応</h3>
<p>Tokyo-Joggingでは内部でBluetoothの信号を扱うために<a href="http://bluecove.org/">BlueCove</a>というライブラリを利用しているのですが、どうもこれがSnow Leopardではうまく動かない模様。原因を探っているとSnow Leopardでは64bit版のJavaがデフォルトで起動するのに対して、BlueCoveのバイナリが32bit用にビルドされていることが原因みたい。インストールされてあるJavaの設定を変更してもいのですが、プログラム単位で対応するためには起動オプションに</p>

<p><pre>-d32</pre></p>

<p>を追加すればいいみたいです。</p>

<p>また、BlueCoveを2.1.0にバージョン上げたら「java.lang.IllegalArgumentException: PCM values restricted by JAR82 to minimum 4097」な例外が出て、落ちてしまってたので、これも対応。起動オプションに</p>

<p><pre>-Dbluecove.jsr82.psm_minimum_off=true</pre></p>

<p>を付けてあげればいいみたいです。</p>

<p>これらの起動オプションは付属のstart-jogging.shに反映させてあるので、最新版にupdateした上で</p>
<p><pre>./start-jogging.sh</pre></p>
<p>で、起動することでSnow Leopard対応したオプション付きで起動できます。</p>
<p>Eclipseから起動する場合は、上記の２つのオプションをRun Configurationsの"VM arguments"に追記してあげればOKです。</p>

<h3>ヌンチャク対応</h3>
<p>地味なupdateですが、ヌンチャクを利用できるようにしました。Wiimoteを認識させた後にヌンチャクを接続するとアナログスティックで方向を変えることができます。（ヌンチャクを接続させたままWiimoteを認識させてもヌンチャクが認識されないので注意）</p>
<p>これで、左手にヌンチャク、右手にWiimoteなスタイルでスムーズに方向を変えつつどこでも走ることができますね！</p>

<h3>今後はどうするの？</h3>
<p>結構、作りっぱなしで放置しているように見られがちですが、実際はジョギング自身でやりたいことはもちろん、派生系でもまだまだやりたいことはあって、ゆっくりながらもupdateしていく予定です。あと、ここへきて外でしゃべらさせていただく機会も増えそうなので、そういうタイミングにあわせてupdateしていく予定です。（今回のupdateも実はその流れ）</p>]]></description>
         <link>http://blog.katsuma.tv/2009/10/tokyo-jogging_support_snow_leopard.html</link>
         <guid>http://blog.katsuma.tv/2009/10/tokyo-jogging_support_snow_leopard.html</guid>
         <category>tokyo-jogging</category>
         <pubDate>Mon, 05 Oct 2009 01:49:06 +0900</pubDate>
      </item>
            <item>
         <title>SQL感覚でMap Reduce処理できるHiveについて</title>
         <description><![CDATA[  <p><img src="http://hadoop.apache.org/hive/images/hive_logo_medium.jpg" alt="Hive" /></p>

 <p>前回、<a href="http://blog.katsuma.tv/2009/08/hadoop_streaming_by_javascript.html">JavaScriptでMap Reduceのコードが書けるHadoop Streaming</a>について紹介しました。
標準入出力さえサポートされてあれば、任意のコードでMap Reduuceの処理が書ける、というものでしたが、エンジニアはそもそも面倒くさがり。コードも書くのも面倒です。
と、いうわけで、今回はもうコードすら書かずにSQLライクでMap ReduceできるHiveというプロダクトについて、まとめたいと思います。</p>

  <h3>Hive</h3>
  <p>Hiveとは、簡単に言うとHadoop上で動作するRDBのようなものです。
HDFSなどの分散ファイルシステム上に存在するデータに対して、HiveQLというSQLライクな言語で操作できます。
で、面白いのがHiveQLの操作は基本的にMap Reduceのラッパーになっていること。
要するに、SELECT文実行すると裏でMap&Reduceのタスクが走り出して、分散処理されて結果を得ることができます。</p>

  <p>そんなHiveは、もともとFacebookが開発を始めたものでした。2008年12月に、正式にHadoopプロジェクトにcontributeされて、いまはHiveの公式サイトもHadoopのサイト内でホスティングされてあります。</p>

  <p><ul><li><a href="http://hadoop.apache.org/hive/">Hive</a></li></ul></p>

  <p>では、さっそく導入方法について確認してみます。</p>

  <h3>ビルド</h3>
  <p>Hiveのビルドに先立って、Hadoopをインストールしておきます。Hadoopのインストール方法は<a href="http://blog.katsuma.tv/2009/08/hadoop_streaming_by_javascript.html">前回のエントリ</a>にも書いてある通りです。</p>

  <p>Hiveのビルド自体は、Subevrsionからcheckoutして、antのタスクでビルドできる簡単なものです。1ヶ月ほど前のHiveは、patchを当てないとHadoop 0.20.0用にビルドできなかったのですが、最近のtrunkのものは特に何もせずにビルドできるようです。</p>

  <p><pre>
svn co http://svn.apache.org/repos/asf/hadoop/hive/trunk hive
cd hive
ant -Dhadoop.version="0.20.0" package
</pre></p>

  <p>ビルドできたらbuild/distを環境変数$HIVE_HOMEとでも設定しておきます。また、あわせて$HADOOP_HOMEも設定しておきましょう。</p>

  <h3>セットアップ</h3>
  <p>ビルドが成功したら、Hive用のデータ保存領域のセットアップをHDFS上で行います。Hadoopを起動した状態で次のようにセットアップします。</p>

  <p><pre>
$HADOOP_HOME/bin/hadoop fs -mkdir       /tmp
$HADOOP_HOME/bin/hadoop fs -mkdir       /user/hive/warehouse
$HADOOP_HOME/bin/hadoop fs -chmod g+w   /tmp
$HADOOP_HOME/bin/hadoop fs -chmod g+w   /user/hive/warehouse
</pre></p>

  <p>すると、次のコマンドでHiveが起動されます。</p>


  <p><pre>
$HIVE_HOME/bin/hive
</pre></p>

  <h3>テーブルの作成</h3>
  <p>では、早速Hiveで扱うテーブルを作成します。
テーブルの作成方法はMySQLなんかの一般的なRDBMSのそれとほぼ同等です。
たとえば、ユーザのアクセスログをまとめたログがあると仮定します。このログを保存するテーブルは最低限、ユーザIDとそのアクセス時間が保存されればOKなので、次のように定義できます。</p>

  <p><pre>
CREATE TABLE user_logs(id INT, created_at STRING);
</pre></p>

  <p>構文については見たまんまなので。理解しやすいかと思います。ちなみに、昔のバージョンだとカラムにDATETIMEなんかの型が定義できたようですが、現在はDATETIME型はなくなっているようです。（<a href="http://wiki.apache.org/hadoop/Hive/LanguageManual/DDL#head-9c8c15fb80a9ae874cf67cc35e1903e77554b62c">Hive/LanguageManual/DDL</a>）</p>


  <p>また、CSVなどの形式ですでに既存のログファイルがある場合、便利な機能があります。
Hiveではテーブル定義時に(CSVなどの)ある形式のデータを扱うことをあらかじめ指定しておくと、
CSV形式のログデータをそっくりそのままHiveのテーブルのレコードとしてロードさせることが可能です。</p>

  <p>たとえばCSV形式のファイルを扱う場合、このような定義方法になります。</p>

  <p><pre>
CREATE TABLE user_logs(id INT, created_at STRING) row format delimited fields terminated by ',' lines terminated by '\n';
</pre></p>

  <p>この上で、次のようなコマンドで既存のログデータをロードできます。</p>

  <p><pre>
LOAD DATA LOCAL INPATH '/path/to/log_20090907.csv' OVERWRITE INTO TABLE user_logs;
</pre></p>


  <p>これで、CSVデータをHiveQLで扱えるようになりました。この時点でHDFS上にlog_20090907.csvは保存されています。/user/hive/warehouse/以下にテーブル名である「user_logs」ディレクトリが作成されてあり、該当ファイルが保存されてあります。</p>

  <p><pre>
$ $HADOOP_HOME/bin/hadoop fs -ls /user/hive/warehouse/user_logs/
Found 1 items
-rw-r--r--   1 katsuma supergroup   17800731 2009-09-06 11:01 /user/hive/warehouse/user_logs/20090907.csv
</pre></p>

<p>では、ここで早速HiveQLを実行してみましょう。全件取得するときは一般的なSELECT文が利用できます。</p>

  <p><pre>SELECT * from user_logs;</pre></p>

  <p>ただし、このままだとローカルからデータをロードするだけで、ただのCSVのSQLラッパーでしかありません。
HiveQLが真価を発揮するのはいろいろ条件付けたSQLを発行してから。</p>

  <h3>ユニークユーザ数をHiveQLで算出</h3>
<p>ここで、ユニークユーザ数(UU)を算出してみます。普通のMap Reduceの処理だと、IDごとのHashMapを作成してそのサイズからUUを算出することになりますが、HiveはSQLライクに算出することができます。つまり、こういうかんじ。</p>

  <p><pre>select count(distinct id) from user_logs;</pre></p>

  <p>すると、いきなりここからMap&Reduce処理が走り出します。
この、「SQL実行でMap&Reduceが実行される」という様子があまりにすごいので、最初これ見たときはかなりウケました。</p>

<p><pre>
Total MapReduce jobs = 1
Number of reduce tasks determined at compile time: 1
In order to change the average load for a reducer (in bytes):
  set hive.exec.reducers.bytes.per.reducer=<number>
In order to limit the maximum number of reducers:
  set hive.exec.reducers.max=<number>
In order to set a constant number of reducers:
  set mapred.reduce.tasks=<number>
Starting Job = job_200909061015_0001, Tracking URL = http://hdp-01:50030/jobdetails.jsp?jobid=job_200909061015_0001
Kill Command = /home/katsuma/hadoop/latest/bin/../bin/hadoop job  -Dmapred.job.tracker=hdp-01:9001 -kill job_200909061015_0001
2009-09-06 10:41:27,049 map = 0%,  reduce = 0%
2009-09-06 10:42:27,520 map = 5%,  reduce = 0%
2009-09-06 10:42:28,540 map = 50%,  reduce = 0%
2009-09-06 10:42:33,594 map = 69%,  reduce = 0%
2009-09-06 10:42:34,610 map = 100%,  reduce = 0%
2009-09-06 10:42:55,748 map = 100%,  reduce = 100%
Ended Job = job_200909061015_0001
OK
21509
Time taken: 105.58 seconds
</pre></p>

  <p>すると、結果が取得できました。上記例だと21509ユーザという結果を取得できていますね。あまりに簡単すぎてウケます。</p>

<p>ちなみにHiveのコンソールはサイレントモードが用意されてあって、Hiveのコンソールを起動させることなく、普段のシェルからも実行させることができます。サイレンとモードは-Sオプションをつけて実行すればよく、</p>


  <p><pre>
$HIVE_HOME/bin/hive -S -e 'select count(distinct id) from user_logs'
</pre></p>

  <p>と、すれば、途中経過をすっとばして結果だけ取得できます。もちろんこれはバッチ処理など、Hiveコンソールを利用せずにいろんな値を取得させたいときに利用すればよさそうですね。</p>


  <h3>Partitionを設定</h3>

  <p>Hiveの特徴的な機能としてPartitionというものがあります。
    これはテーブル自体にバージョン管理の概念を持たせるもので、ログ管理にすごく便利そうなものです。</p>
  
<p>たとえばデイリーのログファイルをHiveで管理したいと思ったときに、
毎日HDFS上にログファイルを転送することになるかと思いますが、Partitionを利用することで、
ログを追記でテーブルに書き込む(=ファイルにappendする)のではなく、
日付ごとに独立したファイルのままHDFSに保存することができます。
なので、「やっぱりHiveより素のMqp&Reduce書くようなフローに戻そう」と
思ったときに、Partitionを利用してロードしておいたほうが後々都合がよいかと思います。(あと、初期のHadoopはファイルのappendができない、という制約があったので、Hive側はこの制約を回避するために、このような概念を持たせて独立したファイルを透過的に見せるような仕様で実装したんじゃないかな？と推測しています)</p>

<p>
Partition自身は、ふだんのテーブルにおけるカラムのように扱えるので、実際は特別に何か意識する必要はありません。Partition付きテーブルはこのように定義できます。</p>


  <p><pre>
CREATE TABLE user_logs(id INT, created_at STRING) partitioned by(dt STRING) row format delimited fields terminated by ',' lines terminated by '\n';
</pre></p>

  <p>この場合だと、dailyの情報をpartitionに持たせるために「dt」という名前のpartitionに設定させています。その上で、このテーブルにデータをロードする場合は次のようになります。</p>


  <p><pre>
LOAD DATA LOCAL INPATH '/path/to/20090907.csv' OVERWRITE INTO TABLE user_logs partition (dt='20090907');
LOAD DATA LOCAL INPATH '/path/to/20090908.csv' OVERWRITE INTO TABLE user_logs partition (dt='20090908');
</pre></p>

  <p>すると、HDFS上ではバージョン情報をもったまま保存されていることが確認できます。</p>

  <p><pre>
$ $HADOOP_HOME/bin/hadoop fs -ls /user/hive/warehouse/user_logs/
Found 2 items
drwxr-xr-x   - katsuma supergroup          0 2009-09-06 11:18 /user/hive/warehouse/user_logs/dt=20090907
drwxr-xr-x   - katsuma supergroup          0 2009-09-06 11:17 /user/hive/warehouse/user_logs/dt=20090908
</pre></p>

  <p>これらのPartitionの情報は、もちろんHiveQL上で扱うことができて、たとえば上記例だと9月8日のUUを算出したい場合は</p>

  <p><pre>
select count(distinct id) from user_logs where dt='20090908';
</pre></p>

  <p>で、算出できます。また、9月7日以降のUUを算出したい場合だと</p>

  <p><pre>
select count(distinct id) from user_logs where dt>='20090907';
</pre></p>

  <p>な、風に書けます。直感的で便利ですよね。（この比較式はたぶん、JavaのString#compareToに従ってるんじゃないか、と推測）</p>


  <h3>まとめ</h3>
  <p>Hiveはまだ立ち上がったばっかりの若いプロジェクトですが、基本的なログ解析をするくらいの分には、かなり使えそうな印象です。上記例のように、基本的に元ファイルはそのままHDFS上に保存されているので、Hiveの不具合で何かおきた場合も自前のMap&Reduce処理に戻すことができるのも安心ですね。</p>

  <p>今回は、あまり細かな説明までしませんでしたが、HiveQLはJoinやUnionなど割と複雑なテーブル間処理も行うことができます。このあたりも興味ある方は一度、オフィシャルのマニュアルに目を通してみてはいかがでしょうか？</p>

  <p><ul><li><a href="http://wiki.apache.org/hadoop/Hive/LanguageManual">Hive/LanguageManual</a></li></ul></p>
]]></description>
         <link>http://blog.katsuma.tv/2009/09/hive_introduction.html</link>
         <guid>http://blog.katsuma.tv/2009/09/hive_introduction.html</guid>
         <category>hadoop</category>
         <pubDate>Mon, 07 Sep 2009 00:44:59 +0900</pubDate>
      </item>
            <item>
         <title>Hadoop Streamingを利用してJavaScriptでMap Reduce</title>
         <description><![CDATA[  <p>久々のBlog更新、というわけでリハビリがてらJavaScriptで軽く遊んでみたいと思います。</p>

  <p>いま、巷で流行ってるMapReduceのオープンソース実装Hadoopは「Hadoop Streaming」という標準入出力でデータのやりとりができる仕組みを使って、
  Hadoopの実装言語であるJavaにとらわれず、RubyやPerlなど他の言語でもMap＋Reduceの処理ができることが１つのウリになっています。
  で、僕たちwebエンジニアはみんなJavaScript大好きなので、「JavaScriptでもMap Reduceやりたい！」という流れになるのは必然です。
そこで、試行錯誤でいろいろ試してみると割とさっくり出来たのでそのメモを残しておきたいと思います。</p>

  <h3>環境の整備</h3>
  <p>Mac OSX上のVMWare FusionにCentOSの仮想マシンを２台立ち上げて、環境セットアップしました。以下のような手順で環境整備しました。</p>

  <h4>仮想HWの設定</h4>
  <p>仮想マシンのイメージファイルですが、僕は毎回<a href="http://www.thoughtpolice.co.uk/vmware/">thoughtpolice</a>のサイトのものを利用しています。ここからCentOS 5.3のイメージを落としてFusionでロード。</p>
  <p>1つハマったのが、同じイメージをコピーして複数台起動すると、MACアドレスがかぶって同時に複数台の仮想マシンがNWに接続できない点。なので、仮想マシンを最初に起動させる前にMACアドレスの設定をしておくことをおすすめします。</p>
  <p>MACアドレスは、vmxファイルのuuid.bios値をもとに自動生成されるようで、この値を最初から全仮想マシンでバラバラにしておけばOKです。と、いっても有効な値の範囲があるので、最後の1byte値だけズラしておけばOKだと思います。たとえば、上記サイトからイメージを取得した場合、uuid.bios値の最後は「7d」になっているので、僕はこの値を「7c」「7b」なんかにズラしておきました。（Fusion上から正規の方法？で、マシンをクローンする方法がよくわからなかったので、こういう強引な方法を取っています。綺麗な方法をご存知の方いらしたらぜひ教えてください！）
</p>


  <h4>ネットワーク設定</h4>
  <p>/etc/hostsを設定して２台のマシンの名前解決。細かな話ですけど、ホスト名には「_(アンダーバー)」は使えないのに要注意。最初「hdp_01」みたいなホスト名にしていて、実行時エラーが出てドはまってたときに全然気づかなかった。</p>
  <ul>
    <li>192.168.1.15 hdp-01</li>
    <li>192.168.1.16 hdp-02</li>
  </ul>

  <h4>SSHの設定</h4>
  <p>マシンはそれぞれ自分自身(localhopst)に対して、パスフレーズなしでSSHでログインできるように公開鍵を設定しておきます。</p>
  <ul>
    <li>ssh-keygen -t rsa -P ""</li>
    <li>cat ~/.ssh/id_rsa.pub >> ~/.ssh/authorized_keys</li>
    <li>chmod 600 ~/.ssh/authorized_keys</li>
 </ul>

  <p>また、MasterのマシンからSlaveのマシンに対しても同様の設定をしておきます。今回はMasterはhdp-01, Slaveはhdp-02という設定です。hdp-01上で、次の設定をします。</p>
  <ul>
    <li>cp ~/.ssh/id_rsa.pub ~/.ssh/id_rsa_master.pub</li>
    <li>scp ~/.ssh/id_rsa_master.pub hdp-02:/home/katsuma/.ssh/</li>
    <li>chmod 600 ~/.ssh/authorized_keys</li>
 </ul>

  <p>また、hdp-02上で、次の設定をします。</p>
  <ul>
    <li>cat ~/.ssh/id_rsa_master.pub >> ~/.ssh/authorized_keys</li>
 </ul>

  <p>これで、Masterからlocalhost, およびSlaveに対してパスフレーズなしでログインできることを確認しておきます。</p>

  <h4>セキュリティの設定</h4>
  <p>後でハマるのが面倒なので、iptablesやSELinuxは切っておきます。必要であれば適宜設定してください。</p>

  <ul>
    <li>sudo /etc/init.d/iptables off</li>
    <li>sudo /etc/sysconfig iptables off</li>
    <li>sudo vi /etc/sysconfig/selinux
      <ul>
        <li>SELINUX=disabled に変更</li>
      </ul>
    </li>
</ul>


  <h4>Shellの設定</h4>
  <p>.bashrcなんかに以下の設定をしておくと便利です。僕はzsh派なので、.zshrcに記述しました。</p>
<p><pre>
# hadoop
alias cdh='cd /home/katsuma/hadoop/latest/'
alias dls='/home/katsuma/hadoop/latest/bin/hadoop dfs -ls'       # ls
alias drm='/home/katsuma/hadoop/latest/bin/hadoop dfs -rm'       # rm
alias dcat='/home/katsuma/hadoop/latest/bin/hadoop dfs -cat'     # cat
alias drmr='/home/katsuma/hadoop/latest/bin/hadoop dfs -rmr'     # rm -r
alias dmkdir='/home/katsuma/hadoop/latest/bin/hadoop dfs -mkdir' # mkdir
alias dput='/home/katsuma/hadoop/latest/bin/hadoop dfs -put'     # HDFS に転送
alias dget='/home/katsuma/hadoop/latest/bin/hadoop dfs -get'     # HDFS から転送
alias dcpfl='/home/katsuma/hadoop/latest/bin/hadoop dfs -copyFromLocal'
alias dcptl='/home/katsuma/hadoop/latest/bin/hadoop dfs -copyToLocal'
</pre></p>


<h4>Javaのインストール</h4>
  <p><a href="http://java.sun.com/javase/ja/6/download.html">Sun</a>のサイトに行き、
    「Java SE Development Kit (JDK)」を選択して、インストーラをダウンロード。その後、以下の手順でインストールできます。
  <p><pre>
chmod +x jdk-6u7-linux-i586-rpm.bin
sudo ./jdk-6u7-linux-i586-rpm.bin
</pre></p>
</p>


<h3>Hadoopの整備</h3>
  <h4>Hadoopのインストール</h4>
  <p>Hadoopは今日時点で最新の0.20.0を利用しました。インストール場所はどこでもいいのですが、僕はホームディレクトリ直下に専用のディレクトリ掘って、いろんなバージョン試せるようにこんな感じで設置してます。<a href="http://www.apache.org/dyn/closer.cgi/hadoop/core">ここ</a>から最新版をDLが可能です。</p>
  <ul>
    <li>cd path/to/hadoop-0.20.0.tar.gz</li>
    <li>tar zxvf hadoop-0.20.0.tar.gz</li>
    <li>mv hadoop-0.20.0 ~/hadoop/</li>
    <li>ln -s hadoop-0.20.0 latest</li>
  </ul>

  <p>他のバージョンを試したくなったら~/hadoop/以下に展開して、シンボリックリンクを付け直すとOKですね。</p>

  <h4>Hadoopの設定</h4>
  <p>特に凝ったことはしていません。全ノードともに同じ設定である必要があるので、Masterで設定しちゃって、それをrsyncで他のSlaveと同期をとるのがよいと思います。</p>

  <h5>conf/hadoop-env.sh</h5>
  <pre>export JAVA_HOME=/usr/java/latest</pre>

  <h5>conf/core-site.xml</h5>
  <p>
    <pre>
&lt;configuration&gt;
  &lt;property&gt;
    &lt;name&gt;hadoop.tmp.dir&lt;/name&gt;
    &lt;value&gt;/home/${user.name}/hadoop/latest/tmp&lt;/value&gt;
  &lt;/property&gt;
  &lt;property&gt;
    &lt;name&gt;fs.default.name&lt;/name&gt;
    &lt;value&gt;hdfs://hdp-01:9000&lt;/value&gt;
  &lt;/property&gt;
&lt;/configuration&gt
</p></pre>

  <h5>conf/hdfs-site.xml</h5>
  <p><pre>
&lt;configuration&gt;
  &lt;property&gt;
    &lt;name&gt;dfs.replication&lt;/name&gt;
    &lt;value&gt;1&lt;/value&gt;
  &lt;/property&gt;
&lt;/configuration&gt;
</pre></p>


  <h5>conf/mapred-site.xml</h5>
  <p><pre>
&lt;configuration&gt;
  &lt;property&gt;
    &lt;name&gt;mapred.job.tracker&lt;/name&gt;
    &lt;value&gt;hdp-01:9001&lt;/value&gt;
  &lt;/property&gt;
&lt;/configuration&gt;
</pre></p>

  <h5>conf/masters</h5>
  <p><pre>
      hdp-01
</pre></p>


  <h5>conf/slaves</h5>
  <p><pre>
      hdp-02
</pre></p>

  <p>ここまで設定できたら、masterのイメージをrsyncしておきましょう。</p>
  <p><pre>
cd ~/hadoop/
rsync -r hadoop-0.20.0/ hdp-02:/home/katsuma/hadoop/hadoop-0.20.0
</pre></p>


  <h3>SpiderMonkeyの導入</h3>
  <p>さて、やっとHadoopの設定が終わったので、次にJavaScriptの処理系の導入です。
Hadoop Streamingは前述の通り、標準入出力の仕掛けを使って実現されているので、さすがにブラウザの処理系をそのまま利用することができません。</p>

<p>
そこで、FirefoxのJavaScriptのエンジンであるSpiderMonkeyを利用することにします。
SpiderMonkeyはファイルを入力としても処理できるし、irbのように対話型シェルとしても利用できるJavaScriptの処理系です。また、ブラウザを利用しないので、標準出力関数print、標準入力関数readlineが実装されてあるので、今回はこれを利用すればうまくいきそうです。</p>

<p>では、SpiderMonkeyを各ノードに導入します。これも最新版を導入します。あらかじめ、make, gccあたりをyumで入れておきましょう。</p>
  <p>参考：<a href="http://blog.katsuma.tv/2007/12/spidermonkey_install.html">SpiderMonkeyのインストール</a></p>
  <p><ul>
      <li>wget http://ftp.mozilla.org/pub/mozilla.org/js/js-1.8.0-rc1.tar.gz</li>
      <li>tar zxf js-1.8.0-rc1.tar.gz</li>
      <li>cd js/src</li>
      <li>BUILD_OPT=1 make -f Makefile.ref</li>
      <li>sudo install -m 755 Linux_All_OPT.OBJ/js /usr/local/bin</li>
  </ul></p>

  <h3>Map, Reduce処理のJavaScriptを記述する。</h3>

  <p>では、Map, Reduceそれぞれの処理をJavaScriptで書きます。今回はサンプルとしてよくある、ワードカウントの処理を行ってみます。</p>

  <h4>map.js</h4>
  <p>map.jsは標準入力された文章を半角スペースごとに分けて、CSVの形式に整形します。JavaScript1.7相当の機能が利用できるので、Array.prototype.forEachが利用できることもポイントです。</p>
  <p><pre>
#!/usr/local/bin/js

var line="";
while ((line = readline())!= null){
        var words = line.split(" ");
        words.forEach(function(w){
                print(w + "," + 1);
        });
}
</pre></p>

  <h4>reduce.js</h4>
  <p>reduce.jsは、map処理されたCSV形式の入力に対して、counterオブジェクトで各単語をカウントしていきます。</p>

  <p><pre>
#!/usr/local/bin/js

var counter = {};
var line = "";
while ((line = readline()) != null) {
        var words = line.split(",");
        var word = words[0]
        if(!counter[word]) counter[word] = 1;
        else counter[word]++;
}

for(var k in counter){
        print(k + ":" + counter[k]);
}

</pre></p>
</body>

  <p>これらのJavaScriptファイルをhadoop/latest/script/あたりに保存しておき、全ノードで同期させておきます。</p>

  <h3>Hadoopの起動</h3>
  <p>最初にHDFSをフォーマットしておきます。Masterで次の処理を行います。</p>
  <p><pre>
cdh
./bin/hadoop namenode -format
</pre></p>

  <p>MasterでHadoopを起動します。</p>
  <p><pre>
bin/start-all.sh
</pre></p>

  <p>MapReduce用の適当な入力ファイルを作成します。こんな内容のファイルを$HADOOP_HOME/input/file1に作成します。</p>
  <p><pre>
we are the world we change the world
</pre></p>
  <p>このファイルをHDFSに転送します。dputは bin/hadoop dfs -putのエイリアスです。</p>
  <p><pre>
dput input/file1 in/count
</pre></p>

  <p>転送されてあるかどうかは、dls(bin/hadoop dfs -ls)で確認できます。</p>
  <p><pre>
katsuma@hdp-01 ~/hadoop/latest
$ dls
Found 1 items
drwxr-xr-x   - katsuma supergroup          0 2009-07-31 02:14 /user/katsuma/in

katsuma@hdp-01 ~/hadoop/latest
$ dls in
Found 1 items
drwxr-xr-x   - katsuma supergroup          0 2009-07-31 02:56 /user/katsuma/in/count
</pre></p>

  <p>入力用ファイルの存在が確認できたので、これでやっとMapReduce処理ができます。</p>

  <p><pre>
./bin/hadoop jar ./contrib/streaming/hadoop-0.20.0-streaming.jar -input in/count -output out/count -mapper "js /home/katsuma/hadoop/latest/script/map.js" -reducer "js /home/katsuma/hadoop/latest/script/reduce.js"
</pre></p>

  <p>すると、ゆったりですけど処理が進んでいきます。</p>
  <p><pre>
packageJobJar: [/home/katsuma/hadoop/latest/tmp/hadoop-unjar4327209233542314881/] [] /tmp/streamjob4726696067913490494.jar tmpDir=null
09/07/31 10:45:05 INFO mapred.FileInputFormat: Total input paths to process : 1
09/07/31 10:45:06 INFO streaming.StreamJob: getLocalDirs(): [/home/katsuma/hadoop/latest/tmp/mapred/local]
09/07/31 10:45:06 INFO streaming.StreamJob: Running job: job_200907310237_0013
09/07/31 10:45:06 INFO streaming.StreamJob: To kill this job, run:
09/07/31 10:45:06 INFO streaming.StreamJob: /home/katsuma/hadoop/latest/bin/../bin/hadoop job  -Dmapred.job.tracker=hdp-01:9001 -kill job_200907310237_0013
09/07/31 10:45:06 INFO streaming.StreamJob: Tracking URL: http://hdp-01:50030/jobdetails.jsp?jobid=job_200907310237_0013
09/07/31 10:45:07 INFO streaming.StreamJob:  map 0%  reduce 0%
09/07/31 10:45:23 INFO streaming.StreamJob:  map 50%  reduce 0%
09/07/31 10:45:45 INFO streaming.StreamJob:  map 50%  reduce 17%
09/07/31 10:48:49 INFO streaming.StreamJob:  map 100%  reduce 17%
09/07/31 10:49:10 INFO streaming.StreamJob:  map 100%  reduce 100%
09/07/31 10:49:15 INFO streaming.StreamJob: Job complete: job_200907310237_0013
09/07/31 10:49:15 INFO streaming.StreamJob: Output: out/count
</pre></p>

  <p>HDFS上のout/count/以下に結果が格納されたファイルができているので確認してみましょう。</p>

  <p><pre>
katsuma@hdp-01 ~/hadoop/latest
$ dls out/count
Found 2 items
drwxr-xr-x   - katsuma supergroup          0 2009-07-31 10:45 /user/katsuma/out/count/_logs
-rw-r--r--   1 katsuma supergroup         43 2009-07-31 10:48 /user/katsuma/out/count/part-00000

katsuma@hdp-01 ~/hadoop/latest
$ dcat out/count/part-00000
are:1
change:1
the:2
we:2
world:2
</pre></p>


<h3>まとめ</h3>

<p>SpiderMonkeyのような処理系を用意することで、JavaScriptでもHadoopを使ってMapReduceできることが確認できました。標準入出力さえサポートされてあれば、理屈的にはどんな言語でもMapReduceできるので、MapReduceには興味あるけどJavaということで敬遠していた方は、ぜひいろんな言語で試していただければと思います。</p>

<h4>開発のTips</h4>
<p>なんだかんだ言って、最初開発にかなり苦労しました。と、いうのもシンタックスエラー以外は、実行しないとどうなるかよくわからないものなので、エラーで落ちたときにどうデバッグすればいいか悩みました。
ただ、よく考えれば、「標準入力→Map処理→Mapの標準出力→Reduceの入力→Reduceの標準出力」という流れになるので、たとえば今回のJavaScript実装の場合、次のように実行することでHadoopを介さなくとも動作確認は可能です。</p>


  <p><pre>
cat input/file1 | js script/map.js | js script/reduce.js
</pre></p>

  <p>まずは、このように手元でパイプでつないで結果を調べてみる、というのが手かと思います。実際は手元でうまく動いてもHadoop上でRuntimeエラーが起きる場合も多いので、そのときはlogディレクトリ以下にできるログファイルを調べるのがいいと思います。</p>

<p>また、エラーが発生するとJavaの例外のStackStraceが表示されるので、敬遠せずにそこからHadoopのソースを直接追いかけるのは何だかんだで早い解決法でした。コメントが割と充実しているので、そこからStreaming用のコードのバグを辿るのも難しくはないと思います。</p>]]></description>
         <link>http://blog.katsuma.tv/2009/08/hadoop_streaming_by_javascript.html</link>
         <guid>http://blog.katsuma.tv/2009/08/hadoop_streaming_by_javascript.html</guid>
         <category>Javascript</category>
         <pubDate>Sun, 02 Aug 2009 00:38:41 +0900</pubDate>
      </item>
      
   </channel>
</rss>
