<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
    <title>blog.katsuma.tv</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/" />
    <link rel="self" type="application/atom+xml" href="http://blog.katsuma.tv/atom.xml" />
   <id>tag:blog.katsuma.tv,2009://1</id>
    <link rel="service.post" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1" title="blog.katsuma.tv" />
    <updated>2009-11-07T20:57:18Z</updated>
    <subtitle>適当に直感で思ったことを何も考えず発信</subtitle>
    <generator uri="http://www.sixapart.com/movabletype/">Movable Type  3.33-ja</generator>
 
<entry>
    <title>楽天テクノロジーでLT&amp;デモをしてきました</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/11/rtc2009.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=214" title="楽天テクノロジーでLT&amp;デモをしてきました" />
    <id>tag:blog.katsuma.tv,2009://1.214</id>
    
    <published>2009-11-07T20:37:59Z</published>
    <updated>2009-11-07T20:57:18Z</updated>
    
    <summary>少し前の情報になるのですが、楽天テクノロジーカンファレンスでTokyo-Jogg...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="develop" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![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>]]>
        
    </content>
</entry>
<entry>
    <title>Hive QL(HQL)でORDER BYするときの注意点</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/10/hive_order_by.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=213" title="Hive QL(HQL)でORDER BYするときの注意点" />
    <id>tag:blog.katsuma.tv,2009://1.213</id>
    
    <published>2009-10-14T14:57:37Z</published>
    <updated>2009-10-14T15:28:08Z</updated>
    
    <summary>HiveでのSQLことHQLの小ネタ。HQLでは基本的にSQLはほぼ完璧に利用で...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="hadoop" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![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>]]>
        
    </content>
</entry>
<entry>
    <title>HiveのmetastoreをMySQLを使ってLocal Metastore形式で利用する</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/10/hive_local_metastore.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=212" title="HiveのmetastoreをMySQLを使ってLocal Metastore形式で利用する" />
    <id>tag:blog.katsuma.tv,2009://1.212</id>
    
    <published>2009-10-11T15:56:17Z</published>
    <updated>2009-10-11T16:01:37Z</updated>
    
    <summary> 前回、紹介したHiveについての続き。  Hiveは内部で扱うメタデータを「m...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="hadoop" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![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>
]]>
        
    </content>
</entry>
<entry>
    <title>Tokyo-JoggingをSnow Leopardに対応させました</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/10/tokyo-jogging_support_snow_leopard.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=211" title="Tokyo-JoggingをSnow Leopardに対応させました" />
    <id>tag:blog.katsuma.tv,2009://1.211</id>
    
    <published>2009-10-04T16:49:06Z</published>
    <updated>2009-10-04T17:13:50Z</updated>
    
    <summary>1年ぶりにTokyo-Joggingをupdateさせました。 さぼってたわけで...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="tokyo-jogging" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![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>]]>
        
    </content>
</entry>
<entry>
    <title>SQL感覚でMap Reduce処理できるHiveについて</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/09/hive_introduction.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=210" title="SQL感覚でMap Reduce処理できるHiveについて" />
    <id>tag:blog.katsuma.tv,2009://1.210</id>
    
    <published>2009-09-06T15:44:59Z</published>
    <updated>2009-09-06T15:55:03Z</updated>
    
    <summary>    前回、JavaScriptでMap Reduceのコードが書けるHado...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="hadoop" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![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>
]]>
        
    </content>
</entry>
<entry>
    <title>Hadoop Streamingを利用してJavaScriptでMap Reduce</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/08/hadoop_streaming_by_javascript.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=209" title="Hadoop Streamingを利用してJavaScriptでMap Reduce" />
    <id>tag:blog.katsuma.tv,2009://1.209</id>
    
    <published>2009-08-01T15:38:41Z</published>
    <updated>2009-08-01T16:00:39Z</updated>
    
    <summary>  久々のBlog更新、というわけでリハビリがてらJavaScriptで軽く遊ん...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="Java" />
            <category term="Javascript" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![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>]]>
        
    </content>
</entry>
<entry>
    <title>emacs.el, anything.el, anything-rcodetools.elを導入</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/05/install_elips.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=208" title="emacs.el, anything.el, anything-rcodetools.elを導入" />
    <id>tag:blog.katsuma.tv,2009://1.208</id>
    
    <published>2009-05-31T09:12:38Z</published>
    <updated>2009-05-31T09:18:25Z</updated>
    
    <summary>前回のemacs導入時にtomoyaさんにコメントいただいたり、negipoさん...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="emacs" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[<p>前回のemacs導入時にtomoyaさんに<a href="http://b.hatena.ne.jp/tomoya/20090511#bookmark-13394468">コメント</a>いただいたり、<a href="http://polog.org/">negipo</a>さんにもanything.elいれるといいよー！てずっと言われてて、軽く試してもなんかうまく導入できなくて途方に暮れて放置してたところ、この週末に時間とって試してみるとすんなり入りました。得てしてそういうものですよね。。あと、あわせてrails.el, anything-rcodetools.elなんかも入れてみました。その導入メモを残しておきたいと思います。</p>

<h3>anything.el</h3>
<p><a href="http://www.emacswiki.org/emacs/download/anything.el">ここ</a>からanything.elをDL.ロードパスが通ってるディレクトリにつっこみます。僕は<a href="http://d.hatena.ne.jp/tomoya/20090121/1232536106">ここのサイト</a>の影響で .emacs.d/elisp/ 以下につっこんでます。ロードパスを変えたいときは、.emacs.elに</p>

<p><pre>
(setq load-path (cons "~/path/to/loadpath" load-path))
</pre></p>

<p>みたいな記述を書けばOKです。</p>

<p>さて、anything.elをロードパスに置いたら、次の内容を.emacs.elに追記します。</p>

<p><pre>
(require 'anything-config)
(setq anything-sources (list anything-c-source-buffers
                             anything-c-source-bookmarks
                             anything-c-source-recentf
                             anything-c-source-file-name-history
                             anything-c-source-locate))
(define-key anything-map (kbd "C-p") 'anything-previous-line)
(define-key anything-map (kbd "C-n") 'anything-next-line)
(define-key anything-map (kbd "C-v") 'anything-next-source)
(define-key anything-map (kbd "M-v") 'anything-previous-source)
(global-set-key (kbd "C-;") 'anything)
</pre></p>

<p>これで、emacsを再起動させると、編集中にC-;を打つとanythingが起動します。すると、Bufferの中に保存された内容や、最近開いたファイルやら何やらが表示されます。これをC-n,C-p / C-v,M-vで選択できます。</p>

<p>もう、これすごい。みんなすごいって言ってた意味がやっとわかりました。QuickSilverみたいなかんじで編集したいファイルに辿り着けるのがすごく便利。C-x,C-fでファイル選択するの、ちょっと扱いづらいなぁと思ってたけど、これで一気に解決できそうです。</p>

<p>
（参考）<a href="http://yamashita.dyndns.org/blog/anythingel/">anything.elが手放せなくなった</a>
</p>



<h3>rails.el</h3>

<p>必要なファイルは「<a href="http://rubyforge.org/projects/emacs-rails/">rails.el</a>」一式、「<a href="http://www.webweavertech.com/ovidiu/emacs/find-recursive.txt">find-recursive.el</a>」「<a href="http://www.kazmier.com/computer/snippet.el">snippet.el</a>」の３種類。これらをロードパスが通ったところに設定します。（上の例だと.emacs.d/elisp/）</p>

<p>その上で、次のような内容を.emacs.elに追加。</p>

<p><pre>
;; rails.el
(defun try-complete-abbrev (old)
  (if (expand-abbrev) t nil))

(setq hippie-expand-try-functions-list
      '(try-complete-abbrev
        try-complete-file-name
        try-expand-dabbrev))
(setq rails-use-mongrel t)
(require 'rails)

;; 対応するファイルへの切り替え(C-c C-p)
(define-key rails-minor-mode-map "\C-c\C-p" 'rails-lib:run-primary-switch)
;; 行き先を選べるファイル切り替え(C-c C-n)
(define-key rails-minor-mode-map "\C-c\C-n" 'rails-lib:run-secondary-switch)

(setq auto-mode-alist  (cons '("\\.rhtml$" . html-mode) auto-mode-alist))
</pre></p>

<h4>対応ファイルへの切り替え</h4>
<p>Controller, View上でC-c C-p をタイプ。すると該当のアクション箇所、またはViewにさくっとジャンプ。これすごい。今まで毎回毎回ウィンドウ分割してファイルを選択して、、てやってたのが２キーでジャンプ。やばい！</p>


<h4>行き先を選択するメニューの表示</h4>
<p>C-c C-nでメニューがポップアップ表示され、ここからHelperやpartialにジャンプできます。これもすごい。。</p>

<h4>view間の移動</h4>
<p>
  &lt;%= render :partial =&gt; 'news' %&gt; みたいになってる箇所で C-Enterをタイプ。すると_news.rhtmlのpartialファイルに一気にジャンプ。これも便利すぎてウケます。</p>

<p>まとめると、とにかく、これでもかというくらいに移動系が便利になってます。
Railsは、あちらこちらに移動してファイルいじることが多いので、rails.elは確かに必須。
今まで入れてなくて相当損してました。。</p>

<p>（参考）<a href="http://d.hatena.ne.jp/higepon/20061222/1166774270">rails.elまとめ</a>
</p>


<h3>anything-rcodetools.el</h3>
<p>Rubyそのものを書くときに、補完周りなんかで便利になるelispです。これインストールかなりハマりました。次の手順でインストールをすすめます。anything.elはあらかじめ入れておきましょう。</p>

<p><ol>
    <li>gem install rcodetools</li>
    <li>gem install fastri</li>
    <li><a href="http://www.emacswiki.org/cgi-bin/wiki/download/anything-rcodetools.el">ここ</a>からanything-rcodetools.elを導入</li>
    <li>~/.gem/ruby/1.8/gems/rcodetools-0.x.x/にあるrcodetools.elをロードパスの通った場所にコピー</li>
</ol></p>

<p>ハマりどころは4.のrcodetools.elを持ってくるところ。ずっとこのファイルのロードエラーが出て困ってましたが、自分で持ってこないといけないみたい。ちなみにRubyに慣れてる人なら当然かもしれませんが、gemでインストールするときに、sudoでインストールすると上記ファイルは.gem/以下に作られないので、そこもあわせて注意です。（これもハマった）</p>

<p>その上で、次のような内容を.emacs.elに追加しておきます。</p>

<p>
<pre>
(require 'anything)
(require 'anything-rcodetools)
;; Command to get all RI entries.
(setq rct-get-all-methods-command "PAGER=cat fri -l")
;; See docs
(define-key anything-map "\C-e" 'anything-execute-persistent-action)
</pre>
</p>

<p>これで"def"と入力した後に、スペースを入力すると、自動的に"end"が挿入されるなど、Rubyに特化した補完が効いてきます。これもタイプ数さぼるために便利。</p>

<p>ただ、anything-rcodetoolsは、明らかにまだまだもっと便利そうな機能がいっぱいありそうなんですけど、まだ何をどうやってどうなれば便利なのか、自分の中でそのメリットが確認できていません。ここは要研究。</p>

<p>（参考）<a href="http://haraita9283.blog98.fc2.com/blog-entry-298.html">(solved) anything-rcodetools.el が動かない （Ubuntu Studio 8.04）</a></p>

<h3>github</h3>
<p>また、いつものようにここまでの内容を<a href="http://github.com/katsuma/config/tree/master">github</a>にpushしています。興味ある方はご参考ください。あと「こうすればもっと便利になるよ！」みたいな意見は相変わらずどんどん募集中です。</p>]]>
        
    </content>
</entry>
<entry>
    <title>githubで新しい環境から自分のレポジトリにpush</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/05/github_push.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=207" title="githubで新しい環境から自分のレポジトリにpush" />
    <id>tag:blog.katsuma.tv,2009://1.207</id>
    
    <published>2009-05-31T04:49:16Z</published>
    <updated>2009-05-31T05:12:24Z</updated>
    
    <summary>小ネタだけど、少しハマってたネタについて。 githubの「自分のレポジトリに最...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="develop" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[<p>小ネタだけど、少しハマってたネタについて。</p>

<p>githubの「自分のレポジトリに最初にpushしていたマシンとは別」のマシン上でgit cloneでデータを取得して、そこで編集、変更を反映するためにpushしようとしたらエラーになりました。</p>

<p><pre>
$ git push
fatal: protocol error: expected sha/ref, got '
*********'

You can't push to git://github.com/user/repo.git
Use git@github.com:user/repo.git

*********'
</pre></p>

<p>何だこれー！と自分のレポジトリなのになぜエラー？？と思ってたら、cloneするときのURLには"Public Clone URL"と"Your Clone URL"の２種類あることを知りました。僕は前者をずっと使ってたのですが、こちらが「公開用URL」後者が「自分専用の(pushをがんがんする前提のURL」という感じなのかな。</p>

<p>と、いうわけでもういちど次のような手順でcloneすると無事、別環境でもpushできました。
</p>

<p><pre>
git clone git@github.com:katsuma/config.git
(編集)
git add .
git commit
(コメント追記)
git push
</pre></p>

<p>今回はこちらの記事を参考にさせていただきました。ありがとうございます！</p>
<p>（参考）<a href="http://d.hatena.ne.jp/tenkoma/20080906/1220728367">githubからローカルにコピーするところまで</a></p>]]>
        
    </content>
</entry>
<entry>
    <title>はじめてのCarbon Emacs</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/05/start_carbon_emacs.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=206" title="はじめてのCarbon Emacs" />
    <id>tag:blog.katsuma.tv,2009://1.206</id>
    
    <published>2009-05-10T15:40:19Z</published>
    <updated>2009-05-10T15:45:30Z</updated>
    
    <summary>	僕はエディタに今までそこまで拘りがなくて、Windowsで作業をするときは秀丸...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="develop" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[	<p>僕はエディタに今までそこまで拘りがなくて、Windowsで作業をするときは秀丸かEclipseを利用することがほとんどでした。
	  と、いうのも僕にとってエディタは</p>
	<p><ul>
		<li>シンタックスハイライト</li>
		<li>そこそこの精度の自動補完</li>
		<li>タブ化</li>
		</ul></p>
	<p>くらいが実装されていればよく、JavaだったらEclipseでもちろんよくて、それ以外の言語を書くときも秀丸で十分満足いく設定を実現できていました。（なので、よく言われるvi対Emacsの戦争には関わることは無かったのですね）</p>

	<h3>Macでのエディタ</h3>
	<p>とはいえ、最近は家ではもちろん、仕事でも作業をMacで行うようになり、さてエディタをどうするか、という話を本格的に考える必要が出てきました。いままでMacでもいろんなエディタを試してきたものの、秀丸的なポジションのしっくりくるものを見つけることができずにいました。</p>

<p>そんな中、仕事ではEmacsを使ってる人が多そうだったのでずっと導入しかけてはやめてたEmacsの導入を試みてみました。
Emacsは（超ありがちな理由ですが）ずっとキーバインドやその操作方法に慣れなくて導入しては止め、の連続だったのですが、さすがにそろそろどうにかするか、と。</p>

	<p>また、素のEmacsでもいいのかもしれませんが、<a href="http://homepage.mac.com/zenitani/emacs-j.html">Carbon Emacs</a> がインターフェース的に良さそうだったので、これを利用。
いろいろ試行錯誤しながら、こんなかんじにカスタマイズすると初心者でも結構使いやすくなってきました。</p>
	<p><a href="http://www.flickr.com/photos/katsuma/3515635909/" title="Emacs setting by katsuma, on Flickr"><img src="http://farm4.static.flickr.com/3620/3515635909_7ac66b8c30_m.jpg" width="240" height="150" alt="Emacs setting" /></a></p>
  <p><ul>
<li>フルスクリーン</li>
<li>背景を透過</li>
<li>メニューバーを隠す</li>
<li>タブ化</li>
<li>行番号表示</li>
<li>編集中の行をハイライト</li>
<li>Mac標準のキーバインドを有効</li>
<li>Optionキーをメタキーに</li>
<li>Shiftキー＋矢印で範囲選択</li>
<li>ビープ音を消す</li>
<li>対応する括弧を光らせる</li>
<li>自動補完を有効</li>
</ul></p>

  <p>これくらいを有効にすることで、初心者でもかなり使いやすくなりました。</p>

<h3>雑感</h3>
	<p>特に、Mac標準のキーバインド、Shiftキー＋矢印で範囲選択を有効にするだけで、普通のエディタと使い勝手はほぼ一緒になりました。コピペやカット&ペーストもCommand+αでOKです。この上で、ファイルを開く＋保存、ウィンドウ分割、行頭や行末移動くらいのコマンドさえ覚えておけばとりあえずまったく問題なく使える感じ。
さすがにこれくらいのコマンドはすぐに覚えられますし、標準の移動系などのコマンドももちろん同時に使えるので、僕のようなキーバインドで悩んでいた人も、Mac標準のキーバインドから少しづつ移行していけばいいのかな、と。また、自動補完も秀丸と同じくらいの精度ではさくさく動かせますし、HTMLタグの補完もOKです。</p>

	<p>あと、個人的によかったのがフルスクリーンでの表示。これをすることで、モニタにエディタ以外に何も表示されなくなったことで集中力がかなり上がった気がします。エディタ以外に視界に入るものが無いということは非常に効果的です。
また、背景を透過させておくことで、IMやブラウザが気になってもアプリケーションを切り替えることなく同時に視界に入れることができるのは、当たり前ながら相当使い勝手がいいなぁと感じました。</p>

<p>
ただ、このあたりの下りは使いこなしてる方からすると「こいつほんとゆとりの使い方だな。。」と突っ込まれそうな感じはムンムンするのですが、それでもとりあえず使ってみる、という視点でいくと最初はこんな感じでどうか許してください、という思いです。。
</p>

<p>
ちなみに、これらの設定は<a href="http://github.com/katsuma/config/tree/master">github</a>に上げてみました。もっとこうしたほうがいい！なご意見があり
ましたら是非教えていただければと思います。</p>

<h3>最後に</h3>
	<p>RubyやRails系の補完周りの設定をもう少しいじってみたいのですが、まだうまくいっていないものが多いです。このあたりはまだ研究中ですね。</p>]]>
        
    </content>
</entry>
<entry>
    <title>CakePHPとRuby on Railsの違い</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/05/cakephp_and_rails.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=205" title="CakePHPとRuby on Railsの違い" />
    <id>tag:blog.katsuma.tv,2009://1.205</id>
    
    <published>2009-05-09T18:48:34Z</published>
    <updated>2009-05-09T19:01:27Z</updated>
    
    <summary>	最近、仕事でRailsを使い始めたので、今までよく使っていたCakePHPとど...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="php" />
            <category term="ruby" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[	<p>最近、仕事でRailsを使い始めたので、今までよく使っていたCakePHPとどこが一緒でどこが違うのかをざっくりまとめてみました。まだRailsは勉強中なので、理解が不十分だったり間違っている箇所もあるかと思いますが、それらの点についてはコメントなどでご教授いただければ幸いです。</p>
	
	<h3>Controller</h3>
	<p>CakePHPの場合、任意のアクションにおいて、/users/show/katsuma のように、URLで「/」で区切られているものは、アクション以降の文字列も勝手に引数に分けてくれます。なので、アクション側の定義で</p>
	<p><pre>function show($id, $name)</pre></p>
	<p>のように引数を分けて定義しておいてあげれば、勝手に値が割り当てられることになります。</p>
	
	<p>Railsの場合はconfig/routes.rbで振り分け方法を定義しておいてあげる必要があります。上の例だと</p>
	<p><pre>
	map.connect 'users/show/:id/:name', :controller => 'users', :action => 'show'	</pre></p>
	<p>こんな感じになるでしょうか。</p>
	<p>一方で、Railsの場合、routes.rbはものすごい強力で、map.connetのかわりに好きな名前のメソッドを指定するだけで「(名前)_url」で指定したcontroller, actionなどを含むURLを作成することなんかできたりします。たとえば</p>
	<p><pre>
ActionController::Routing::Routes.draw do |map|
 map.berryz '', :controller => "berryz", :action=> "show"
end</pre></p>
	<p>こんな感じにroutes.rbで定義しておいた上で、</p>
	<p><pre>
berryz_url(:id => 'miyabi')
</pre></p>
	<p>で呼び出すと、</p>
	<p><pre>http://localhost:3000/berryz/show/miyabi</pre></p>
	<p>を意味することになります。Railsすごい。。。！</p>
	<p>また、GETで引数指定で渡ってきたも、routes.rbで指定された引数も、すべて param[:hoge]のシンボル指定で取得できるのも特徴でしょうか。</p>


	<h3>ApplicationController</h3>
	<p>CakePHPの場合、任意のControllerクラスの継承元であるApplicationControllerは "app/" ディレクトリ直下に "application_controller.php" の名前で設置されます。</p>
	<p>Railsの場合は、"app/controllers/" の中に "application.rb"の名前で設置され、その場所と名前が微妙に異なります。</p>
<p>この名前については、これ規約からも外れてるよなぁ。。と思ってたら、どうやらRails 2.3.0からは"application_controller.rb"に名前が変わるようですね。詳しい話はこちらに書いてました。（参照元：<a href="http://d.hatena.ne.jp/takihiro/20081127/1227776059">そういえば ApplicationController ってファイル名の規約を守ってなかったんだな</a>）</p>



	<h3>View(レイアウト)</h3>
	<p>CakePHPの場合、大枠のレイアウトはviews/layouts/default.ctp に、そのレイアウトのHTMLを記述します。</p>
	<p>Railsの場合は、views/layouts/application.rhtmlに記述することになり、その名前は異なります。統一性の観点から言うと、Railsのこの名前の方が個人的には好きです。</p>



	<h3>部分テンプレート</h3>
	<p>CakePHPの場合、部分テンプレート(element)は、views/elements/ 以下に header.ctp の名前で保存しておきます。elementの呼び出す場合は、View側で</p>
	<p><pre>$this->element('header') </pre></p>
	<p>の、ように呼び出します。</p>

	<p>Railsの場合は、特定のcontroller内での共通テンプレート、全controllerでの共通テンプレートとそれぞれ別に分けることができます。
	  前者の場合は、 views/user/_header.rhtml のように、"views/controller名/_{部分テンプレート名}.rhtml"の形式になります。
	  逆に後者の場合、views/shared/_header.rhtmlのように、"views/shared/_{部分テンプレート名}.rhtml" の形式になります。</p>
	<p>部分テンプレートの呼び出し方は、前者の場合は、&lt;%=render :partial=>'header'/&gt; のように、後者の場合は :partialで指定する値が"shared/header"のようになります。</p>
	<p>この点については、Railsはここまで細かい指定がなくてもいいのにな、、と思います。Cakeの方が直感的な規約だし、呼び出し方も簡単かな、と。</p>



	<h3>Filter</h3>
	<p>Cake,Railsともにcontrollerにおいて、その前後にフィルタをかけることが可能です。いわゆるbeforeFilter, afterFilterですね。
	  Cakeでは特定のController、またはApplicationControllerにおいてbeforeFilter/afterFilterアクションを定義しておくことで、そのフィルタを通すことが可能です。</p>
	<p>Railsの場合、フィルタにはメソッドはもちろんですが、クラス、ブロックの３つのレベルで指定可能です。また、複数のフィルタが定義されている場合は、その定義された順番にフィルタが適用されます。</p>
	<p>このRailsの細かな指定は凄い、としか言いようがないかんじ。特にブロックで渡すことができる柔軟性は使いこなせばすごく便利そうな印象です。（まだ自分はそこまで使いこなせてません）</p>

	<h3>静的ファイル</h3>
	<p>CakePHPの場合、画像やCSSファイルなど、静的ファイル（や、routes.phpのルーティングに外れるもの）は、"webroot/" 以下に設置しておけばOKです。</p>
	<p>逆に、Railsの場合は、"public" ディレクトリに設置することになり、そのディレクトリ名が異なっています。</p>
	<p>これについては、Railsを意識しまくったCakeとしては、どうしてここの名前だけ変えたのかはよく分かりません。。。</p>


	<h3>まとめ</h3>
	<p>ざっと目につきやすい相違点をまとめてみました。Railsについてはまだまだ触り始めたばかりなので、相違点はまだまだあるでしょうし、注意して理解を深めて行きたいと思います。
	 また、今回こうやって相違点を考えていくことで、むしろお互いの理解が深まるんじゃないかな、とも思っています。</p>
	<p>ちなみに、チュートリアルについて、<a href="http://book.cakephp.org/ja/">book.cakephp.org</a>は日本語化されてるわけですが、<a href="http://guides.rubyonrails.org/">guides.rubyonrails.org</a>は日本語化されてないんでしょうか？？
	  すごくよくまとまってそうなので、できれば日本語で読んでみたいのですが。。</p>
]]>
        
    </content>
</entry>
<entry>
    <title>退職のご報告</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/05/job_change.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=204" title="退職のご報告" />
    <id>tag:blog.katsuma.tv,2009://1.204</id>
    
    <published>2009-04-30T15:00:00Z</published>
    <updated>2009-04-30T15:05:29Z</updated>
    
    <summary>4月30日をもってウタゴエ株式会社を退職しました。 5月1日からは白金台の某社に...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="diary" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[<p>4月30日をもってウタゴエ株式会社を退職しました。</p>
<p>5月1日からは白金台の某社に勤務いたします。今後ともよろしくお願いいたします。</p>

<p><a href="http://www.flickr.com/photos/katsuma/3488820998/" title="Entrance by katsuma, on Flickr"><img src="http://farm4.static.flickr.com/3633/3488820998_f7041ef3f8_m.jpg" width="180" height="240" alt="Entrance" /></a></p>]]>
        
    </content>
</entry>
<entry>
    <title>Tokyo Cloud Developers Meetupに行ってきました</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/04/tokyo_cloud_developers_meetup_01.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=203" title="Tokyo Cloud Developers Meetupに行ってきました" />
    <id>tag:blog.katsuma.tv,2009://1.203</id>
    
    <published>2009-04-10T23:10:09Z</published>
    <updated>2009-04-12T06:53:46Z</updated>
    
    <summary> AmazonさんでS3, EC2などのクラウド系のカンファレンス Tokyo ...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="diary" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[<p>
<a href="http://www.flickr.com/photos/katsuma/3433147447/" title="@ Tokyo Cloud Developers Meetup by katsuma, on Flickr"><img src="http://farm4.static.flickr.com/3639/3433147447_b86e045338_m.jpg" width="240" height="180" alt="@ Tokyo Cloud Developers Meetup" /></a>
</p>

<p>AmazonさんでS3, EC2などのクラウド系のカンファレンス <a href="http://atnd.org/events/481">Tokyo Cloud Developers Meetup </a>が開かれるとのことだったので参加してきました。クロスタワーにあるAmazonオフィスはすごくかっこよかったです！以下、簡単なメモ。</p>

<h3>Jeff Barrさん</h3>
<p>
<ul>
<li>Amazon Web Service : Building Blocks
 <ul>
 <li>Infrastructure</li>
 <li>People</li>
 <li>Payment</li>
 <li>Fulfilment</li>
 <li>Alexa</li>
 </ul>
</li>

<li>Fully programmable
 <ul>
 <li>XML</li>
 <li>SOAP</li>
 <li>REST/HTTP</li>
 </ul>
</li>


<li>Using
 <ul>
 <li>HTTPS</li>
 <li>Private & Public key</li>
 <li>X.500 certificate</li>
 </ul>
</li>

<li>S3
 <ul>
 <li>540,000 Developers</li>
 <li>52,000,000,000 S3 objects</li>
 <li>1,000,000,000,000 S3 requests per year from 90 countries</li>
 </ul>
</li>


<li>EC2
 <ul>
 <li>Region
  <ul>
  <li>US : east</li>
  <li>Euro : west</li>
  <li>Future : ?</li>
  </ul>
 </li>

 <li>Security groups
  <ul>
  <li>outside world to EC2</li>
  <li>EC2 instance to EC2 instance</li>
  <li>IP address</li>
  <li>Network port</li>
  </ul>
 </li>
 </ul>
</li>
</ul>
</p>
<p>(もちろん)英語でのプレゼンだったので聞き取るの必死でした。資料なかったら半分も内容わからなかったと思います。。</p>
<p>一番見所とすると、やっぱりS3の利用状況の数値じゃないでしょうか。１兆リクエストとか数字にされると凄いものがありますね。あとプレゼンのときにちらっと映ってましたけど、JeffさんもS3のクライアントとして<a href="https://addons.mozilla.org/ja/firefox/addon/3247">Organizer</a>を利用されてるみたいです。</p>


<h3>LT : <a href="http://blog.livedoor.jp/sparklegate/">山崎さん</a>(<a href="http://axsh.jp/information/">株式会社あくしゅ</a>)</h3>
<p>
<ul>
<li>Dynamic cloyd configuration "Wakame"</li>
<li>複数インスタンスのEC2おける動的なconfigurationを実現</li>
<li>ロードバランシングなんかもうまくやってくれるみたい（詳細よく理解できませんでした）</li>
<li>RubyForgeで4/22にはリリース予定</li>
</ul>
</p>

<h3>LT : <a href="http://d.hatena.ne.jp/rx7/">並河さん(id:rx7さん)</a></h3>
<p>
<ul>
<li>社内SNS SKIPをリリース</li>
<li>SKIPのSAAS化(SKIPAAS)</li>
<li>EC2, SB2, S3を利用</li>
<li>レスポンスが遅い、英語の情報ばかり、障害おきてもよくわからない(クラウドの中)あたりが悩みの種</li>
<li>EC2の日本進出に期待！</li>
</ul>
</p>


<h3>LT : <a href="http://mtl.recruit.co.jp/mt/mt-search.cgi?IncludeBlogs=19&search=%E3%83%95%E3%83%8A%E3%83%9F%E3%82%BF%E3%82%AB%E3%82%AA">フナミさん</a>(<a href="http://mtl.recruit.co.jp/">MTL</a>)</h3>
<p>
<ul>
<li><a href="http://airyakiniku.cosaji.jp/">AIR YAKINIKU</a>について</li>
<li>SKIPのSAAS化(SKIPAAS)</li>
<li>EC2は開発環境、非同期のバッチ処理なんかに利用</li>
<li>エア焼肉リリース時は回線が相当やばいことになった</li>
<li>1swf, 5flvで200MB超えしてた（すごいw）</li>
<li>その後、２時間でEC2に乗せてクラウド化に</li>
</ul>
</p>


<h3>LT : お名前失念。。(<a href="http://www.manabing.jp/">学びing株式会社</a>)</h3>
<p>
<ul>
<li><a href="http://www.kentei.cc/">けんてーごっこ</a>について</li>
<li>ユーザが増えてきたのでだんだんとサーバを増強</li>
<li>その後クラウドも利用してきた</li>
<li>レスポンスはやっぱり遅い</li>
<li>ので、重めのコンテンツは日本に、軽めのコンテンツはクラウドに、と利用目的を分けてる</li>
</ul>
</p>

<h3>LT : 安藤さん(<a href="http://www.exa-corp.co.jp/">株式会社エクサ</a>)</h3>
<p>
<ul>
<li>EC2はSSLを利用すると遅い</li>
<li>SSLを利用しない場合は問題なく使える</li>
<li>利用にあたって上司を説得する場合において</li>
<li>自家発電しないでしょ？</li>
<li>固定資産を持ちたくないでしょ？</li>
<li>データは暗号化しておけばいいでしょ？</li>
<li>あたりが説得材料になるのでは</li>
</ul>
</p>


<h3>まとめ</h3>
<p>思ったよりも日本のクラウド利用場面ってかなり多そうだなぁ、という印象を持ちました。いろんなサービスもパッと見るくらいだとどこにサーバがあるのかはよくわからないので、今回のような利用実績について生の声を聞くとかなり新鮮な印象を持ちました。
一方で、レスポンス速度や日本語情報の少なさなど、まだまだ問題も多いかと思いますので、このように技術者が集まれる場所がある、というのはすごく有意義だな、とも感じました。</p>]]>
        
    </content>
</entry>
<entry>
    <title>モダンブラウザでAppletを扱うときに知っておくこと</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/04/applet_at_modern_browser.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=202" title="モダンブラウザでAppletを扱うときに知っておくこと" />
    <id>tag:blog.katsuma.tv,2009://1.202</id>
    
    <published>2009-04-06T22:41:42Z</published>
    <updated>2009-04-07T07:12:45Z</updated>
    
    <summary>[09/04/07 16:00 追記]　embedでの呼び出し結果の表に誤りがあ...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="develop" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[<p>[09/04/07 16:00 追記]　embedでの呼び出し結果の表に誤りがあったので訂正しました。</p>

<p>
世間ではiPhone OS3.0で騒がれていますが、そんな中メインストリームとは逆行してJava Appletについていろいろ調べていました。
</p>


<h3>情報が少なすぎる</h3>
<p>
世間的にはJava Appletの話なんて枯れすぎてる話題なので、いくら調べても2000年過ぎの情報ばかりが大半です。「ただしこの方法ではNetscape4.0以上の環境では。。。」とか言われても困るわけです。今どきのWebアプリケーションらしくJavaScriptと連携させるにはどうすればいいんでしょうか。そもそもappletのロード方法１つとってもSafariやChromeなんかのモダンブラウザに対応したロード方法とかまったくわかりません。あとJava Runtimeのインストールチェックなんてどうすればいいのでしょうか？？疑問は尽きません。
</p>

<p>そこで、今回これらの情報、</p>
<ol>
<li>JavaScriptからAppletを呼び出す方法</li>
<li>AppletからJavaScriptを呼び出す方法</li>
<li>モダンブラウザに適したAppletのロード方法</li>
</ol>
<p>について調べてみたのでまとめておきたいと思います。</p>

<h3>Java Runtime のバージョンチェック</h3>
<p>そもそもAppletを実行できる環境であるかどうか、を判定する必要がありますが次のようなロジックで確認をすることが可能になります。</p>
<ol>
<li>Applet側でRuntimeのバージョン情報をpublicなフィールドに格納しておく </li>
<li>JavaScriptから1.のフィールドを参照する </li>
<li>参照に失敗、または参照先の値が不正な場合はRuntimeがない、と判断。参照先に値があった場合はその値がバージョン情報</li>
</ol>

<p>
次に、JavaScriptとの連携を考えるわけですが、ここでは「JavaScriptからAppletのメソッドを呼び出す」「AppletからJavaScriptの関数を呼び出す」の２パターンがあります。まず、前者の方から考えていきましょう。</p>

<h3>AppletからJavaScriptを呼び出す</h3>
<p>こちらは非常にシンプルで「document.{$AppletをロードしたHTML要素のid}.{$appletにおけるpublic修飾子のメソッド、またはフィールド}」でアクセスすることができます。たとえば次のようなAppletがあるとします。</p>

<p>
<pre>
import java.applet.Applet;

public class VMInfo extends Applet {
  public String jreVersion = "";
  public void init() {
    this.jreVersion = System.getProperty("java.version");
  }
}
</pre></p>

<p>
また、次のようにappletタグでappletをロードしておくとします。
</p>


<p><pre>
&lt;applet name="app" code="VMInfo" mayscript="true" archive="plugin.jar" width="430" height="200"&gt;&lt;/applet&gt;
</pre></p>


<p>このとき、JavaScriptからAppletのjreVersionフィールドにアクセスする場合、</p>

<p><pre>
document.app.jreVersion
</pre></p>

<p>で、アクセスが可能です。ここでのappはapplet要素のname属性値になります。非常に簡単ですね。</p>


<p>また、FlashのExternalInterface経由でJavaScriptからFlashのメソッドにアクセスする場合、IE系はdocument経由、それ以外のブラウザはwindow経由でFlashの参照を取得するなど、参照の取得方法は異なります。ところが、Appletの場合はIEでもFirefoxでもChromeでもすべて同じ「document経由」で参照を取得する、というのは１つのポイントになります。</p>


<h3>AppletからJavaScriptを呼び出す</h3>
<p>先ほどとは逆に、JavaからJavaScriptのメソッドを呼び出す方法について考えてみます。方法としては、</p>

<ol>
<li>JSObjectを利用する方法 </li>
<li>共通 DOM API を介してアクセスする方法</li>
</ol>

<p>の2種類の方法が存在します。ここでは単純な1の方法を紹介します。</p>

<p>
JSObjectクラスのメソッド群を利用すると、HTML ページの DOM へのアクセスが容易になります。JSObjectを利用する場合、次のjarファイルをクラスパスに通しておく必要があります。</p>


<p><pre>{$jdk}\jre\lib\plugin.jar</pre></p>

<p>
plugin.jarにクラスパスを通すと、netscape.javascript.JSObject を利用することが可能になります。JSObjectはstaticメソッドでglobalなwindowオブジェクトの参照を取得します。windowオブジェクトの参照を取得すると、あとは任意のJavaScriptのコードをeval()で実行することが可能になります。たとえばwindow.alert()を呼び出す場合は次のようなコードになります。</p>

<p><pre>
import java.applet.Applet;
import netscape.javascript.JSObject;

public class VMInfo extends Applet {
   public void init() {
　　JSObject win = JSObject.getWindow(this);
　　String jsContext = "alert()";
　　win.eval(jsContext);
   }
}</pre></p>


<p>要はActionScript3におけるExternalInterface.callのようなもの、というイメージで良いと思います。JSObectのAPIについては、<a href="http://java.sun.com/javase/ja/6/webnotes/6u10/plugin2/liveconnect/jsobject-javadoc/netscape/javascript/JSObject.html">こちらのドキュメント</a> にまとまっているので、さらに詳しく知りたい方はご参照ください。</p>

<p>ここで1つポイントとして、JSObjectを利用してappletとJavaScriptとの連携を行うときは、appletをロードするときのHTML要素に対して「mayscript」属性を追加しておく必要があります。属性値はtrueにでもしておけばいいですが、実際は属性が存在すれば問題は無いようです。このあたりの話は「<a href="http://moyolab.blog57.fc2.com/blog-entry-64.html">JavaScriptを使用するアプレットの単体テスト</a>」で述べられていますので、ご参考ください。</p>


<h3>ロード方法</h3>
<p>さて、appletのロード方法についても、パッと考えただけでもいろんな方法が思いつきます。</p>

<ol>
<li>appletタグでロード </li>
<li>objectタグでロード </li>
<li>embedタグでロード</li>
</ol>

<p>
Flashのような発想をすると、objectタグとembedタグの組み合わせでロードするのが本筋のような気もしますが、とりあえずこれまでで述べてきたJavaScript連携のコードを含んだAppletのロードを全パターンで試してみました。</p>

<p>
対象となるAppletのコードは次のようにしています。
appletがロードされると、JREのバージョン、およびベンダ情報を取得し、JS側のVMInfo.notify()を呼び出します。（Java→JavaScript呼び出しの確認）</p>

<p><pre>
import java.applet.Applet;
import java.awt.TextField;
import netscape.javascript.JSObject;

public class VMInfo extends Applet {
&nbsp;&nbsp;&nbsp; 
&nbsp;&nbsp; &nbsp;public String jreVersion = "";
&nbsp;&nbsp; &nbsp;public String jreVendor = "";

&nbsp;&nbsp; &nbsp;private TextField versionField;
&nbsp;&nbsp; &nbsp;private TextField vendorField;

&nbsp;&nbsp; &nbsp;public void init() {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;this.jreVersion = System.getProperty("java.version");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;this.jreVendor = System.getProperty("java.vendor");
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;this.versionField = new TextField(jreVersion, jreVersion.length());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;this.vendorField = new TextField(jreVendor, jreVendor.length());
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add(versionField);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;add(vendorField);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;// callback
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;JSObject win = JSObject.getWindow(this);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;String jsContext = "VMInfo.notify({\"version\":\"" + jreVersion + "\", \"vendor\":\"" + jreVendor + "\"})";
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;win.eval(jsContext);
&nbsp;&nbsp; &nbsp;}
}

</pre></p>

<p>
検証するJavaScriptの関数VMInfo.norifyは次のように用意しておきます。構造は単純で、Objectを引数に受け取り、alertで確認しています。
</p>

<p>.<pre>
&lt;script type="text/javascript"&gt;
 //&lt;![CDATA[
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; var VMInfo = {
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;notify : function(info){
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;var version = info.version || "";
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;var vendor = info.vendor || "";
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;window.alert([version, vendor]);
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;}
&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;};
 //--&gt;
&lt;/script&gt;
</pre>
</p>

<p>
あわせて、JavaScript→Javaの呼び出しの確認として、次のようにAppletのプロパティを直接参照してみます。
</p>

<p><pre>
&lt;script type="text/javascript"&gt;
//&lt;![CDATA[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; alert(document.app.jreVersion);
//--&gt;
&lt;/script&gt;
</pre></p>


<h4>呼び出し方法は実はこれではダメ</h4>
<p>当初、この組み合わせでいろいろ試していたのですが、実はOperaだけJavaScript→Javaの呼び出しで失敗することが多くて(undefinedが返る)、さてどうしたものか、と悩んでいました。それ以外のブラウザでは正確にAppletのプロパティにアクセスできるので、アクセス方法は間違ってることは無さそう。OperaはAppletへのアクセスはサポートしてないのかな、、と思ってたときに、そういえばAJAXまわりの話題でOperaはロードのタイミングが他のブラウザと比べておかしい、みたいな話題を見たことをフと思い出しました。「もしやappletがロードし終わる前にアクセスしようとしてる？」と思い、プロパティへのアクセスをwaitをかけてズラしてみました。</p>


<p><pre>
&lt;script type="text/javascript"&gt;
//&lt;![CDATA[
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var d = document;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTimeout(function(){alert(d.app.jreVersion)}, 3000);
//--&gt;
&lt;/script&gt;
</p></pre>


<p>ビンゴ！</p>
<p>setTimeoutでアクセス時間をズラしてあげることで、Operaでもアクセスが可能になりました。やはりOperaはAppletへのプロパティアクセスが他のブラウザよりも早く(?)行われていたみたいです。本当は3000ms決め打ちじゃなくて、一定回数試行した方がいいのですが、とりあえず今回の実験はこの方法を取る事にして、いろんなappletロード方法の組み合わせと比較してみたいと思います。</p>

<p>ちなみに、今回試したブラウザの細かなバージョンについては、IE 7, Firefox 3.0.8, Safari 3.2.2, Opera 10.00 alpha, Chrome 2.0.171.0となっています。すべてWindows XP上での動作確認です。</p>

<h4>パターン1 : appletタグでロード</h4>
<p>まずは一番シンプルでレガシーな方法。</p>

<p><pre>
&lt;applet name="app" code="VMInfo" mayscript="true" archive="plugin.jar" width="430" height="200"&gt;&lt;/applet&gt;
</pre></p>

<p>結果は次の通り。</p>

<table cellpadding="3" cellspacing="0" border="1">
<thead>
<tr>
<th width="25%">Browser</th>
<th width="25%">表示</th>
<th width="25%">JS→Java</th>
<th width="25%">Java→JS</th>
</thead>
</tr>
<tbody>
<tr>
<td width="25%">IE7</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td width="25%">Fx3</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td width="25%">Safari3</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td width="25%">Opera10</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td width="25%">Chrome2</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
</tbody>
</table>


<p>全部OK! レガシーな方法はモダンブラウザでもちゃんと動くようです。</p>

<h4>パターン2 : objectタグでシンプルにロード</h4>
<p>次にobjectタグでロード。ただし、オプション情報はすべてobject要素の属性に設定するシンプルなロード方法にしてみます。</p>

<p><pre>
&lt;object id="app" classid="java:VMInfo" archive="plugin.jar"
mayscript="true" type="application/x-java-applet" width="230"
height="100"&gt;
</pre></p>

<p>結果は次の通りとなりました。</p>


<table cellpadding="3" cellspacing="0" border="1">
<thead>
<tr>
<th width="25%">Browser</th>
<th width="25%">表示</th>
<th width="25%">JS→Java</th>
<th width="25%">Java→JS</th>
</tr></thead>
<tbody>
<tr>
<td width="25%">IE7</td>
<td align="center">×</td>
<td align="center">×</td>
<td align="center">×</td>
</tr>
<tr>
<td>Fx3</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td>Safari3</td>
<td align="center">○</td>
<td align="center">×</td>
<td align="center">○</td>
</tr>
<tr>
<td>Opera10</td>
<td align="center">○</td>
<td align="center">×</td>
<td align="center">○</td>
</tr>
<tr>
<td>Chrome2</td>
<td align="center">○</td>
<td align="center">×</td>
<td align="center">×</td>
</tr>
</tbody>
</table>


<p>この形式だとIEだと表示すらしてくれませんでした。JSからの呼び出しもなかなかうまくいかない模様です。
むしろシンプルな方法だとobjectタグを利用した場合、IE以外のブラウザでも表示してくれるのは新しい発見でした。</p>



<h4>パターン3 : objectタグでparamタグと組み合わせてロード</h4>
<p>次にparamタグと組み合わせてobjectタグでロード。</p>

<p><pre>
&lt;object id="app"
classid="clsid:8AD9C840-044E-11D1-B3E9-00805F499D93" width="230"
height="100"&gt;
&lt;param name="code" value="VMInfo"
/&gt;
&lt;param name="archive" value="plugin.jar" /&gt;No
applet
&lt;/object&gt;
</pre></p>

<p>結果は次の通りとなりました。</p>


<table cellpadding="3" cellspacing="0" border="1">
<thead>
<tr>
<th width="25%">Browser</th>
<th width="25%">表示</th>
<th width="25%">JS→Java</th>
<th width="25%">Java→JS</th>
</tr></thead>
<tbody>
<tr>
<td width="25%">IE7</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td>Fx3</td>
<td align="center">×</td>
<td align="center">×</td>
<td align="center">×</td>
</tr>
<tr>
<td>Safari3</td>
<td align="center">×</td>
<td align="center">×</td>
<td align="center">×</td>
</tr>
<tr>
<td>Opera10</td>
<td align="center">×</td>
<td align="center">×</td>
<td align="center">×</td>
</tr>
<tr>
<td>Chrome2</td>
<td align="center">×</td>
<td align="center">×</td>
<td align="center">×</td>
</tr>
</tbody>
</table>


<p>これも面白い結果。object/paramの組み合わせ方法はやはりAppletの場合でもIEしか有効では無い模様です。</p>

<h4>パターン4 : embedタグでロード</h4>
<p>次にパターン2,3とは逆にembedタグのみでロードしてみました。</p>

<p><pre>
&lt;embed code="VMInfo.class" width="230" height="100" name="app"
type="application/x-java-applet;version=1.6"
pluginspage="http://java.sun.com/javase/downloads/ea.jsp" /&gt;
</pre></p>

<table cellpadding="3" cellspacing="0" border="1">
<thead>
<tr>
<th width="25%">Browser</th>
<th width="25%">表示</th>
<th width="25%">JS→Java</th>
<th width="25%">Java→JS</th>
</tr></thead>
<tbody><tr>
<td>IE7</td>
<td align="center">×</td>
<td align="center">×</td>
<td align="center">×</td>
</tr>
<tr>
<td>Fx3</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td>Safari3</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
<tr>
<td align="center">Opera10</td>
<td align="center">○</td>
<td align="center">○(*)</td>
<td align="center">○(*)</td>
</tr>
<tr>
<td width="25%">Chrome2</td>
<td align="center">○</td>
<td align="center">○</td>
<td align="center">○</td>
</tr>
</tbody>
</table>

<p>こちらは、IE, Opera以外は総じて良い結果になりました。
Operaは、JavaScriptからJavaの呼び出しにおいて、「○」としましたが、不安定なことが多く成功したりしなかったり、ということが繰り返されていたことを注釈として付け加えておきます。</p>

<h3>まとめ</h3>
<p>モダンブラウザにおいてもJavaScriptからAppletの呼び出し、AppletからJavaScriptの呼び出しなど、言語間の連携は可能であることが確認できました。また、Appletのプログラムは、その呼び出し方法によってブラウザごとでまったく挙動が異なることが分かりました。特に気にしなければappletタグで呼び出すのが最も安定した呼び出し方法で、IEのみでロードをさせたいときはFlashと同じくObject/paramタグの組み合わせで呼び出すのがベストなようです。</p>

<p>さて、今回はここで終わりますが実はappletの呼び出し方法はappletタグでの呼び出しはベストな解ではありません。</p>
<ul><li>Java-pluginがインストールされていないときの自動プラグインインストール</li>
<li>appletのキャッシュコントロール</li></ul>
<p>などを考えたいときに、もっと凝った方法を取る必要があります。この話は次回に書いてみたいと思います。</p>]]>
        
    </content>
</entry>
<entry>
    <title>meeting24.tvがTechCrunchに掲載されました</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/04/meeting24tv_on_techcrunch.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=201" title="meeting24.tvがTechCrunchに掲載されました" />
    <id>tag:blog.katsuma.tv,2009://1.201</id>
    
    <published>2009-04-03T18:24:50Z</published>
    <updated>2009-04-03T18:33:28Z</updated>
    
    <summary>meeting24.tvがTechCrunchに掲載されました。 Meeting...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[<p><a href="http://meeting24.tv">meeting24.tv</a>が<a href="http://www.techcrunch.com">TechCrunch</a>に掲載されました。</p>

<p><ul><li><a href="http://www.techcrunch.com/2009/04/03/meeting24tv-keeps-online-meetings-simple/">Meeting24.tv Keeps Online Meetings Simple</a></li></ul></p>

<p>TechCrunchに掲載されたのは<a href="http://www.techcrunch.com/2008/08/31/utagoe-live-100-unites-video-communication-broadcasting-and-simultaneous-display-of-100-live-streams/">Live100のとき</a>に続いて２回目になります。BloggerのSerkanさん、ありがとうございます！</p>

<h3>関連記事</h3>
<p><ul>
<li><a href="http://blog.katsuma.tv/2008/11/meeting24tv.html">meeting24.tvをリリースしました</a></li>
<li><a href="http://blog.katsuma.tv/2009/03/meeting24tv_at_tokyo20.html">Tokyo 2.0でmeeting24.tvを発表してきました</a></li>
</ul></p>]]>
        
    </content>
</entry>
<entry>
    <title>CakePHPでモデルキャッシュを利用する</title>
    <link rel="alternate" type="text/html" href="http://blog.katsuma.tv/2009/04/cakephp_model_cache.html" />
    <link rel="service.edit" type="application/atom+xml" href="http://blog.katsuma.tv/mt-atom.cgi/weblog/blog_id=1/entry_id=200" title="CakePHPでモデルキャッシュを利用する" />
    <id>tag:blog.katsuma.tv,2009://1.200</id>
    
    <published>2009-03-31T15:32:02Z</published>
    <updated>2009-03-31T15:53:34Z</updated>
    
    <summary>Cakeでキャッシュ周りの調査をしていたら、モデルのメソッドの実行結果をキャッシ...</summary>
    <author>
        <name>ryo_katsuma</name>
        <uri>http://katsuma.tv</uri>
    </author>
            <category term="php" />
    
    <content type="html" xml:lang="ja" xml:base="http://blog.katsuma.tv/">
        <![CDATA[<p>Cakeでキャッシュ周りの調査をしていたら、モデルのメソッドの実行結果をキャッシュさせるbehaviorがあるのを見つけました。</p>

<ul><li><a href="http://www.exgear.jp/blog/2008/11/cakephp12-behavior%E3%81%A7%E3%83%A2%E3%83%87%E3%83%AB%E3%81%AE%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%AD%E3%83%A3%E3%83%83%E3%82%B7%E3%83%A5%E3%82%92%E8%A1%8C%E3%81%86/">CakePHP1.2 Behaviorでモデルのメソッドキャッシュを行う</a></li></ul>

<p>これが相当いい感じなので、その利点や導入方法についてまとめておきたいと思います。</p>

<h3>コントローラのスリム化</h3>
<p>
MVCモデルでキャッシュを利用しようという話になると、大抵Controllerでキャッシュヒットの有無を確認して、ヒットしない場合キャッシュをリセットする、というロジックがまず頭に浮かぶと思います。</p>

<p><pre>
if (($posts = Cache::read('posts')) === false) {
 $posts = $this->Post->find('all');
 Cache::write('posts', $posts);
}
</pre></p>

<p>ただ、コントローラで毎回このようなキャッシュヒットを確認していると同じようなコードがあちこちに散らばることになるので、保守性が悪くなります。なので、こういうキャッシュ周りの処理はできるだけモデルに振ってしまったほうがよいです。また、基本的なフロー以外の余計なロジックを考えなずにくてよいので、可読性も格段に上がると思います。</p>

<p>
<pre>
// キャッシュヒットすればキャッシュから、ヒットしない場合はDBアクセス
$posts = $this-&gt;Post-&gt;find('all');
</pre></p>

<h3>Paginationもキャッシュできる</h3>
<p>CakePHP1.2から導入されたPaginationですが、実態はfind('all')＋ページ情報をセットする処理を隠蔽したものとなっています。ポイントは、$controller->paginate()メソッドの中で、これらの処理を全部行いつつも、returnで戻ってくるのはfind('all')の結果なので、paginate()の結果だけキャッシュさせていても、ページ情報がキャッシュされずにView側でエラーになる、ということです。（このあたりのページ処理についてはcake/libs /controller/controller.phpの1056行目あたりにあります）
この理由から、controller側でpaginateの結果をキャッシュさせる作戦はうまくいかないので、Paginationは毎回遅くなります。</p>

<p>そこで、controller側ではなく、Model側でキャッシュを行わせます。paginate()内で行われるfind以外の処理、つまりページ情報の処理についてはその処理時間は高々知れているので、結局findの処理をキャッシュさせておくことでpaginate()の高速化が期待できます。
</p>

<h3>導入方法</h3>
<p>今回は、モデルキャッシュをmemcachedにキャッシュさせるようにしました。コードは上記リンクから入手できるので、app/models/behaviorにcache.phpで保存しておきます。</p>

<p>まず、app/config/core.phpのCache::configを次のようにFileエンジンの設定をコメントアウトし、Memcacheエンジンを利用します。</p>

<p><pre>
Cache::config('default', array(
    'engine' =&gt; 'Memcache', //[required]
    'duration'=&gt; 3600, //[optional]
    'probability'=&gt; 100, //[optional]
    'prefix' =&gt; Inflector::slug(APP_DIR) . '_', //[optional]  prefix every cache file with this string
    'servers' =&gt; array(
    	'127.0.0.1:11211' // localhost, default port 11211
     ), //[optional]
    'compress' =&gt; false, // [optional] compress data in Memcache (slower, but uses less memory)
));
//Cache::config('default', array('engine' =&gt; 'File'));
</pre></p>

<p>そして、キャッシュを利用したモデルにおいてactsAsで設定します。</p>

<p><pre>
var $actsAs = array('Cache');
</pre></p>

<p>
findをオーバーライドします。僕は、findの第一引数にいろんなバリエーションを持たせることをよくやるので、</p>

<p><pre>
    function find($type, $queryData = array()){
        switch ($type) {
            case 'popular' :
                return $this-&gt;find('all', Set::merge(array("conditions"=&gt;array("Model.rating"=&gt;5)), $queryData));

            case 'latest' :
                return $this-&gt;find('all', Set::merge(array("limit"=&gt;10, "order"=&gt;"Model.created"), $queryData));
               
            default:
                $args = array($type, $queryData);
                if ($this-&gt;Behaviors-&gt;attached('Cache')) {
                    if($this-&gt;cacheEnabled()) {
                        return $this-&gt;cacheMethod($cache_time, __FUNCTION__, $args);
                    }
                }
                $parent = get_parent_class($this);
                return call_user_func_array(array($parent, __FUNCTION__), $args);
        }
    }
</pre></p>

<p>こんなかんじで、第一引数のタイプをcase文で振って、return文では素のfind('all')を通らせることで必ずdefaultに処理を落とすようにさせ、そこでキャッシュをかけるようにさせます。これでシンプルでスッキリした構成にできました。
</p>

<h3>まとめ</h3>
<p>１つ思ったのは、このビヘイビアではcacheMethodメソッドにおいて第一引数ではキャッシュ時間を指定させるのですが、この時間は第三引数にしてオプション扱いにしてほしかったかなぁということ。と、いうのは単純な話で、このメソッドにおいて重要度は　__FUNCTION__ &gt; $args &gt; $cache_timeであるから。組み込みのエンジンを利用できるのだからcacheのexpireもCache::configのduration値を標準で見てくれてもいいのかな、と思います。</p>

<p>とはいえ、これでコントローラ側では普通にfindを呼び出すだけでキャッシュ付きの処理を行うことができるので、非常に有効なライブラリかと思います。ちなみにキャッシュはModelに対応したテーブルのレコードが変化するたびにクリアされる(=afterSaveをフックしている)ので、頻繁に saveが起こるようなModelでは、あまりキャッシュが有効にならない場合も多いかと思うので、その点はご注意を。</p>]]>
        
    </content>
</entry>

</feed> 

