23:57hadoopHiveでのSQLことHQLの小ネタ。HQLでは基本的にSQLはほぼ完璧に利用できますが、たまにハマりポイントもあります。BYは有効ですが、実際は並び替えは行われません。[column]」を利用することになります。BYは結果がreducerの数に依存します。BYと同等の結果を得ることができません。BYを実行すればOKです。key;また、Hiveシェルを使わない場合は1ライナーで。BYと条件文などが組合わさると途端に処理が遅くなることがあります。BYし、条件文は付けないな、方針でHQLを分割して実行すると、高速に動作できるかと思います。BY以外でもかなり有効なケースが多くあります。このあたりの最適化の話は、また別途まとめたいと思います。00:56hadoop前回、紹介したHiveについての続き。Hiveは内部で扱うメタデータを「metastore」というデータで保持しています。テーブルやパーティションなどの情報、またレコードが実際に保持されてある場所などのメタデータは全部このmetastoreにまとまっています。このmetastoreは、次の3種類の方法で保存することができます。metastoreは主にテスト用途に利用されます。テスト用途なので、単一プロセスからの接続しか許可されていません。そのため、コンソールを複数起動して、それぞれのコンソールから別のMap&Reduceを走らせる...なんてことができません。Hiveは初期設定がこのEmbededモードになっているので、特に設定することなくすぐに利用するメリットはあります。metastoreはmetastoreディレクトリ(hive-default.xmlのhive.metastore.urisセクションに記述されています)内の単一のファイルに保存されることになります。メタデータのバックアップをとりたいときは、このファイルをバックアップ対象にすればOKです。Metastoreについて。Metastoreはネットワーク越しにmetastoreを扱いたい場合における設定方法です。Hiveクライアントとデータを保存するMySQLの間にThriftサーバをproxyのような形で挟むことで実現しています。Thriftプロトコルを実現できていれば通信が可能なので、実際はJavaのHiveクライアントだけではなく、異なる言語によるクライアントからも接続が可能です。PHPでの例があるみたいです。Metastoreは、上で述べた2つの形式の間の位置づけのものです。Metastoreの形式にようにMySQLに保存することで、同一ホスト内から同時に複数のセッションを張ることができます。Metastoreは簡単に実現できる割にすごく便利なので、紹介しておきます。DBの設定まず、MySQLでmetastoreを保存する適当なDB、およびその接続ユーザを定義します。rootで接続し、次のように定義します。privileges;この設定をHiveに反映させるために設定用xmlを編集します。hive-site.xmlの編集Hiveの初期設定はhive-default.xmlにまとまっていますが、この設定はhive-site.xmlという名前のファイルを同一ディレクトリに用意してあげることで上書きできます。上記設定は次の項目を編集、または追加してあげることで反映されます。warehouse&lt;/description&gt;&lt;/property&gt;どのプロパティ名も名前からどんなものかは凡そ予想はつくと思います。ちなみにhive.metastore.warehouse.dirはHDFS上でのファイルパスになるので、ここだけ要注意です。xmlを編集したら、hiveクライアントのシェルを立ち上げ直します。Metastoreのときとメッセージ形式も変わらないですが、同時に複数のHQLを実行することができるので、格段に使いやすくなります。Metastoreの利用は検討してみる価値はあるのかな、と思います。Metastoreの形式について、その設定方法をまとめてみました。これらの保存方式については、公式サイトにもまとまっている資料があるので、一度目を通してみるとコンポーネント間の関係が理解しやすいかと思います。Streamingについて紹介しました。Reduuceの処理が書ける、というものでしたが、エンジニアはそもそも面倒くさがり。コードも書くのも面倒です。ReduceできるHiveというプロダクトについて、まとめたいと思います。HiveHiveとは、簡単に言うとHadoop上で動作するRDBのようなものです。HDFSなどの分散ファイルシステム上に存在するデータに対して、HiveQLというSQLライクな言語で操作できます。Reduceのラッパーになっていること。要するに、SELECT文実行すると裏でMap&Reduceのタスクが走り出して、分散処理されて結果を得ることができます。そんなHiveは、もともとFacebookが開発を始めたものでした。2008年12月に、正式にHadoopプロジェクトにcontributeされて、いまはHiveの公式サイトもHadoopのサイト内でホスティングされてあります。Hiveでは、さっそく導入方法について確認してみます。ビルドHiveのビルドに先立って、Hadoopをインストールしておきます。Hadoopのインストール方法は前回のエントリにも書いてある通りです。Hiveのビルド自体は、Subevrsionからcheckoutして、antのタスクでビルドできる簡単なものです。0.20.0用にビルドできなかったのですが、最近のtrunkのものは特に何もせずにビルドできるようです。packageビルドできたらbuild/distを環境変数$HIVE_HOMEとでも設定しておきます。あわせて$HADOOP_HOMEも設定しておきましょう。セットアップビルドが成功したら、Hive用のデータ保存領域のセットアップをHDFS上で行います。Hadoopを起動した状態で次のようにセットアップします。/user/hive/warehouseすると、次のコマンドでHiveが起動されます。$HIVE_HOME/bin/hiveテーブルの作成では、早速Hiveで扱うテーブルを作成します。テーブルの作成方法はMySQLなんかの一般的なRDBMSのそれとほぼ同等です。ユーザのアクセスログをまとめたログがあると仮定します。このログを保存するテーブルは最低限、ユーザIDとそのアクセス時間が保存されればOKなので、次のように定義できます。STRING);構文については見たまんまなので。理解しやすいかと思います。ちなみに、昔のバージョンだとカラムにDATETIMEなんかの型が定義できたようですが、現在はDATETIME型はなくなっているようです。(Hive/LanguageManual/DDL)また、CSVなどの形式ですでに既存のログファイルがある場合、便利な機能があります。Hiveではテーブル定義時に(CSVなどの)ある形式のデータを扱うことをあらかじめ指定しておくと、CSV形式のログデータをそっくりそのままHiveのテーブルのレコードとしてロードさせることが可能です。CSV形式のファイルを扱う場合、このような定義方法になります。'\n';この上で、次のようなコマンドで既存のログデータをロードできます。user_logs;これで、CSVデータをHiveQLで扱えるようになりました。この時点でHDFS上にlog_20090907.csvは保存されています。/user/hive/warehouse/以下にテーブル名である「user_logs」ディレクトリが作成されてあり、該当ファイルが保存されてあります。/user/hive/warehouse/user_logs/20090907.csvでは、ここで早速HiveQLを実行してみましょう。全件取得するときは一般的なSELECT文が利用できます。user_logs;ただし、このままだとローカルからデータをロードするだけで、ただのCSVのSQLラッパーでしかありません。HiveQLが真価を発揮するのはいろいろ条件付けたSQLを発行してから。ユニークユーザ数をHiveQLで算出ここで、ユニークユーザ数(UU)を算出してみます。Reduceの処理だと、IDごとのHashMapを作成してそのサイズからUUを算出することになりますが、HiveはSQLライクに算出することができます。user_logs;すると、いきなりここからMap&Reduce処理が走り出します。この、「SQL実行でMap&Reduceが実行される」という様子があまりにすごいので、最初これ見たときはかなりウケました。secondsすると、結果が取得できました。上記例だと21509ユーザという結果を取得できていますね。あまりに簡単すぎてウケます。ちなみにHiveのコンソールはサイレントモードが用意されてあって、Hiveのコンソールを起動させることなく、普段のシェルからも実行させることができます。user_logs'と、すれば、途中経過をすっとばして結果だけ取得できます。これはバッチ処理など、Hiveコンソールを利用せずにいろんな値を取得させたいときに利用すればよさそうですね。Partitionを設定Hiveの特徴的な機能としてPartitionというものがあります。これはテーブル自体にバージョン管理の概念を持たせるもので、ログ管理にすごく便利そうなものです。日付ごとに独立したファイルのままHDFSに保存することができます。「やっぱりHiveより素のMqp&Reduce書くようなフローに戻そう」と思ったときに、Partitionを利用してロードしておいたほうが後々都合がよいかと思います。(あと、初期のHadoopはファイルのappendができない、という制約があったので、Hive側はこの制約を回避するために、このような概念を持たせて独立したファイルを透過的に見せるような仕様で実装したんじゃないかな?と推測しています)Partition自身は、ふだんのテーブルにおけるカラムのように扱えるので、実際は特別に何か意識する必要はありません。Partition付きテーブルはこのように定義できます。'\n';この場合だと、dailyの情報をpartitionに持たせるために「dt」という名前のpartitionに設定させています。その上で、このテーブルにデータをロードする場合は次のようになります。(dt='20090908');すると、HDFS上ではバージョン情報をもったまま保存されていることが確認できます。dt='20090908';で、算出できます。dt>='20090907';な、風に書けます。直感的で便利ですよね。(この比較式はたぶん、JavaのString#compareToに従ってるんじゃないか、と推測)まとめHiveはまだ立ち上がったばっかりの若いプロジェクトですが、基本的なログ解析をするくらいの分には、かなり使えそうな印象です。上記例のように、基本的に元ファイルはそのままHDFS上に保存されているので、Hiveの不具合で何かおきた場合も自前のMap&Reduce処理に戻すことができるのも安心ですね。今回は、あまり細かな説明までしませんでしたが、HiveQLはJoinやUnionなど割と複雑なテーブル間処理も行うことができます。ArchiveAboutこのBlogはクックパッドに勤めるWebエンジニアがLLネタや情報技術について直感で思ったことを何も考えず発信するサイトです。コメントやお問い合わせ、執筆依頼などは@ryo_katsuma宛のmention、またはメールなどでお待ちしています。