8t's BBR

よくつまったあれこれをメモ

HiBenchを使ってみた

数ヶ月ぶりの更新。
先々月、就活も無事終わりました。
ぼちぼち研究もやり始めていこうということで、今回は研究で使うことになったHiBenchの導入時の話です。

※以下、HiBench 6.0時点の話。

HiBenchはビッグデータ用のベンチマークスイートです。
さまざまなビッグデータフレームワーク(Hadoop、Spark)を速度、スループット、システムリソースの利用率の点で評価するのに役立ちます。


オープンソースで公開されており、以下から利用できます。
github.com


Build

Build方法も利用目的別に丁寧に説明してくれています。
HiBench/build-hibench.md at master · intel-hadoop/HiBench · GitHub


例えば、私みたいにSparkとかを利用していなくて、Hadoop用のだけでいい場合は

mvn -Phadoopbench -Dspark=2.1 -Dscala=2.11 clean package

とするだけ。

BuildにはMahoutやNutchのような3rdパーティーのツールを使っているので時間がかかると書かれていますが、Mavenの設定とかをしっかりしておかないと、以下のようにかなり時間かかった挙句に失敗したりします。

[INFO] ------------------------------------------------------------------------
[INFO] Reactor Summary:
[INFO] 
[INFO] hibench ........................................... SUCCESS [30:19.090s]
[INFO] hibench-common .................................... FAILURE [1:21:40.787s]
[INFO] HiBench data generation tools ..................... SKIPPED
[INFO] hadoopbench ....................................... SKIPPED
[INFO] hadoopbench-sql ................................... SKIPPED
[INFO] mahout ............................................ SKIPPED
[INFO] PEGASUS: A Peta-Scale Graph Mining System ......... SKIPPED
[INFO] nutchindexing ..................................... SKIPPED
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------

※設定を適切にしてあげたら、十数分で終わりました。


BenchMarkを実行

※今回はHadoopベンチを例に説明します。Spark用とかは公式を参照してください。

前準備

Python 2.x(>= 2.6)以上を用意
・Hibenchのレポート用にbcを用意
・サポートするHadoopのバージョンを用意(Apache Hadoop 2.x, CDH5.x, HDPのいずれか)
HDFS、YARNデーモンを起動させておく


余談ですが、Apachehadoop-3.0.0-alpha4での動作も確認しました。
(追記)
一部(wordcount, terasort, sort, sleep)のみ動作を確認。
その他のワークロードは、javaのIllegalAccessErrorにより失敗するみたい。
他にも同じような方がいるっぽいので、これはサポートを待つしかないかも。
https://github.com/intel-hadoop/HiBench/issues/466

(更に追記)
IllegalAccessErrorは、対象ソースのアクセス修飾子いじれば解決できるっぽい。
dfsioeは2.x系の時からあるメソッド(名前忘れた)が削除されているため、それをもう一度組み込めば良い。
ml系のテストはmahoutのバージョンをあげたりとかで解決できました。
色々調整した結果、micro系全てとbayesとkmeansの動作は確認できました。

hadoop.confファイルの作成

これは用意されているテンプレートファイルをコピーしてくるだけです。

cp conf/hadoop.conf.templete conf/hadoop.conf
hadoop.confの設定
プロパティ 説明 apache hadoopでの例
hibench.hadoop.home hadoopのインストール場所 /home/user/hadoop-2.7.2
hibench.hadoop.executable hadoopの実行可能ファイルのパス /home/user/hadoop-2.7.2/bin/hadoop
hibench.hadoop.configure.dir hadoopの設定ファイルのパス /home/user/hadoop-2.7.2/etc/hadoop
hibench.hdfs.master HiBenchデータを置いておくHDFSのパス hdfs://localhost:9000/user/username
hibench.hadoop.release Hadoopのリリースプロバイダ。apacheかcdh5かhdpのいずれかを設定する。 apache

4つめのhibench.hdfs.masterプロパティのhdfs://localhost:9000/の部分はhadoop本体のcore-site.xmlで設定しているfs.defaultFSの値と同じにすると良いかもしれない。私の環境では、localhostのままだとうまくいかなかった。

ワークロードの実行

例えば、wordcountのワークロードを実行する時は、以下のようにするだけ。

bin/workloads/micro/wordcount/prepare/prepare.sh
bin/workloads/micro/wordcount/hadoop/run.sh

conf/benchmarks.lstとconf/frameworks.lstにある全てのワークロードを実行する場合は

bin/run_all.sh

とするだけ。

レポート
report/hibench.report ワークロード名、実行時間、データサイズ、クラスタごとのスループット、ノードごとのスループットなど、要約されたワークロードレポート
(workload)/hadoop/bench.log クライアント側の未加工のログ
(workload)/hadoop/monitor.html システム使用率モニター結果
(workload)/hadoop/conf/(workload).conf このワークロード用に生成された環境変数の設定一覧
その他

入力データサイズやその他もチューニングもできる。conf/hibench.confをいじると良い。


おまけ(HiBenchのワークロード)

では、最後に、Readmeで説明されているものを和訳(機械学習とかの専門知識ないので誤訳あるかも)しただけのものでものっけておきます。


HiBenchには19個のワークロードがあり、それらは以下の6個のカテゴリー(micro, machine learning, sql, websearch, streaming)に分けられています。


Micro Benchmark

  1. Sort (sort)
    RandomTextWriterで生成されたテキスト入力データをソート。

  2. WordCount (wordcount)
    RandomTextWriterで生成された入力データ内の各単語の出現をカウント。

  3. TeraSort (terasort)
    Jim Grayによって作成された標準ベンチマーク
    入力データは、Hadoop TeraGenサンプルプログラムによって生成される。

  4. Sleep (sleep)
    フレームワークスケジューラをテストするために、各タスクで秒単位でスリープ。

  5. enhanced DFSIO (dfsioe)
    HadoopクラスタHDFSスループットを、書き込みと読み取りを同時に実行する多数のタスクを生成することによってテスト。
    各マップタスクの平均I / Oレート、各マップタスクの平均スループット、およびHDFSクラスタの集約スループットを測定できる。
    ※注:Spark対応の実装はなし。


Machine Learning

  1. Bayesian Classification (bayes)
    Spark-MLLib / Mahoutの例で実装されたNaiveBayesian Classificationのベンチマーク

  2. K-means clustering (kmeans)
    Mahout 0.7 / Spark-MLlibのK-means(知識発見とデータマイニングのためのよく知られたクラスタリングアルゴリズムクラスタリングをテスト。
    入力データセットは、Uniform DistributionおよびGuassian Distributionに基づいてGenKMeansDatasetによって生成される。

  3. Logistic Regression (lr)
    Spark-MLLibの例で実装されたロジスティック回帰のベンチマーク。Logistic RegreesionはLBFGSによって実現。入力データセットは、ランダムバランス決定ツリーに基づいてLabeledPointDataGeneratorによって生成される。 カテゴリデータ、連続データ、バイナリデータなど、3種類のデータ型が含まれる。

  4. Alternating Least Squares (als)
    Spark-MLLibの例で実装された交互最小二乗のベンチマーク。 入力データ・セットは、商品レコメンデーションシステムのためのRating Date Generatorによって生成される。


SQL

  1. Scan (scan)

  2. Join (join)

  3. Aggregate (aggregation)

    これらはSIGMOD 09の論文「A Comparison of Approaches to Large-Scale Data Analysis」とHIVE-396に基づいて開発されており、このホワイトペーパーで説明している一般的なOLAPクエリを実行するHiveクエリ(集計および結合)が含まれる。その入力は、Zipfian分布に従ってハイパーリンクを含むWebデータを自動的に生成。


Websearch Benchmarks

  1. PageRank (pagerank)
    Spark-MLLib / Hadoop(ペガサス2.0に含まれる検索エンジンランキングベンチマーク)の例で実装されたPageRankアルゴリズムベンチマーク。データソースは、ハイパーリンクがZipfian分布に従うWebデータから生成。

  2. Nutch indexing (nutchindexing)
    一般的なオープンソースApacheプロジェクト)検索エンジンであるNutchの索引付けサブシステムをテスト。ハイパーリンクと単語の両方がZipfian分布に従って対応するパラメータを持つWebデータ(自動的に生成される)を使用。 Webページのテキストを生成するために使用されるdictは、デフォルトのlinux dictファイル。


Graph Benchmarks

  1. NWeight (nweight)
    Spark GraphXとpregelによって実装される反復グラフ並列アルゴリズム。nホップ離れた2つの頂点間の関連付けを計算する。


Streaming Benchmarks

  1. Identity (identity)
    Kafkaから入力データを読み取り、Kafkaに結果を即座に書き込む。複雑なビジネスロジックは必要なし。

  2. Repartition (repartition)
    Kafkaから入力データを読み取り、より多くのまたはより少ないパーティション・ステートを作成することによって並列性のレベルを変更する。ストリーミングフレームワークにおけるデータシャッフルの効率をテスト。

  3. Stateful Wordcount (wordcount)
    数秒ごとにKafkaから累積的に受け取った単語をカウントします。 これにより、ストリーミングフレームワークのステートフルオペレータパフォーマンスとCheckpoint / Ackerコストがテストされる。

  4. Fixwindow (fixwindow)
    ウィンドウベースの集約を実行し、ストリーミングフレームワークでのウィンドウ操作のパフォーマンスをテスト。

久しぶりにphp扱ってみたら動作しない

 
以前phpで作成したアプリケーションを久しぶりにいじろうと思ったのですが、ブラウザにはコードが表示されたり、うまく動作しなかったりとで戸惑いました。


apache動いている?」
 -> http://localhost で確認。ちゃんと「It works!」と言ってくれる。


phpのバージョンあげたっけ?」
 -> terminalでphp -versionで確認。以前と同じで上がってない。


「あれ?なのにphpが動作しないの?」
 -> terminal で<?php phpinfo(); ?>と書いただけのphpファイル実行。うまくいく。


「え、ブラウザだけ駄目なん?」
 -> /etc/apache2/httpd.conf を確認したら、LoadModule php5_module libexec/apache2/libphp5.soコメントアウトされている。こいつか・・・



全然知りませんでしたがMacではOSアップデートの際に、/etc/apache2/httpd.confがデフォルトに書き換わるようですね。
そういえば以前OSアップデートしたなぁ・・・。

以前動いていたものが、久しぶりに触ると動かなくなっていて、びっくりしたお話でした。

Play Framework を使ってみた ③

前記事:Play frameworkを使ってみた ② - 8t's BBR


前回からかなり時間が経ってしまいましたが、今回はPlayフレームワーク
データベースとEbeanを扱うにはどうするかについてまとめようかと思います。


※データベース初心者が送るデータベース初心者向けの説明になります。厳しい指摘は歓迎します。

※play2.5系のjavaの説明になるので、違うバージョンまたはscala使用者は公式などを参考にしてください。
Home - 2.5.x

データベースを扱うための設定

conf/application.conf

データベースの情報を記述します。単一のデータベースしか扱わないのであればデータソースの名前はdefaultのままで大丈夫です。
H2とかSQLiteとか色んなデータベースを扱うことができますが、今回はMySQLを例にとって説明していきます。

db.default.driver=com.mysql.jdbc.Driver
db.default.url="jdbc:mysql://localhost/playdb"
db.default.username=playdbuser
db.default.password="a strong password"

urlの最後は使用するデータベース名。usernameやpasswordは各自設定したものを。

build.sbt

以下の設定がなされていることを確認。なければ設定してください。

libraryDependencies += javaJdbc

また、使用するデータベースがH2以外のものであれば、以下の設定も必要です。
以下の例はMySQLの場合。最後の数字部分はバージョンですので適宜変更を。

libraryDependencies += "mysql" % "mysql-connector-java" % "5.1.36"

 

データベースへのアクセス

以下のようにするだけでデータベースを利用できます。

import javax.inject.Inject;
import play.mvc.*;
import play.db.*;

class Application extends Controller {

    private Database db;

    @Inject
    public Application(Database db) {
        this.db = db;
    }

}

クエリ実行

あまり推奨しませんが(理由は後述)、以下のようにすればクエリを実行できます。

import javax.inject.Inject;
import play.mvc.*;
import play.db.*;
import java.sql.*;

class Application extends Controller {

    private Database db;
    private Statement stmt;

    @Inject
    public Application(Database db) {
        this.db = db;
        Connection con = db.getConnection();
 
        try {
            stmt = con.createStatement();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

    public Result getMemberList() {
        String query = "SELECT * FROM MEMBER";
        ResultSet rs = stmt.executeQuery(query);
//             :          
        return ok();
    }

}

Ebeanの利用

先ほどクエリの実行の仕方を紹介しましたが推奨しませんと言いました。なぜなら、

  • クエリをコード中に書く必要がある
  • コードの記述量が多くなる

といったことによって、ミスをする可能性が高くなったり、読みづらくなったりと問題点があるからです。

では、どうすればいいのか。これをサポートする機能をPlayは提供してくれています。
具体的にはEbeanというものを利用することになります。
これ自体についてはまだ知ったばかりなので間違っているかもしれませんが、DB操作を楽にしてくれるものです。
たった一行でDB操作が可能になります。すごいですね。


では早速、設定ファイルをいじっていきます。

project/plugins.sbt

まずはこのファイルの最後に以下の設定を記述します。

addSbtPlugin("com.typesafe.sbt" % "sbt-play-ebean" % "3.0.0")

build.sbt

次に、PlayEbeanのプラグインを有効化します。おそらく最後のPlayEbeanの部分を追記するだけで大丈夫です。
PlayEbeanを認識してくれない場合がありますが、build.sbtをリフレッシュすれば直ります。(これに気づけず、すごい時間を浪費しました・・・)

lazy val root = (project in file(".")).enablePlugins(PlayJava, PlayEbean)

conf/application.conf

データソースの名前がdefaultのままであれば、以下の記述を追記してください。
違う場合はそれに合わせてdefault部分を変更してください。

ebean.default = "models.*"

この設定ではmodelsパッケージ以下を管理する形になりますが、お好きなパッケージを指定しても大丈夫です。



以上で準備完了です。


実際の利用例

まずは、データベースで管理するデータをクラスとして作成します。
ポイントはクラス宣言の前に@Entityアノテーションを付与することです。
これにより、データベースが管理するエンティティクラスとなります。


以下は適当に作成したMemberクラスです。

package models;

import java.util.*;
import javax.persistence.*;

import com.avaje.ebean.Model;
import play.data.format.*;
import play.data.validation.*;

@Entity
public class Member extends Model {

    @Id
    public Long id;

    @Constraints.Required
    public String name;

    public boolean isMale;

    public Long score;

    public static Finder<Long, Member> find = new Finder<Long,Member>(Member.class);
}
  • @Id : 登録時、主キーとなるIDを自動生成してくれるようになる。
  • @Constarints : 値の制限をかけることができる。Requiredの他にも色々ある。
  • Finder : 検索時に使います。おまじない的に書いてしまいましょう。

 


あとはMemberクラスのインスタンス(member)を生成すれば、

member.save();

で、データベースに登録できます。memberインスタンスのidは自動で生成されます。
idの値を保持しており、他の情報を変更したい場合は、

member.update();

とするだけです。


逆にデータベースからデータを引き出し、それを元にインスタンス生成することもできます。

Member member = Member.find.byId(id);

データを削除したい場合は、この後に

member.delete()

とするだけです。なんとわかりやすいことか。

トランザクション

データベースを扱うのであれば当然必要です。
メソッドに@Transactionalをつけるか、Ebean.beginTransaction()Ebean.commitTransaction()Ebean.endTransaction()を活用するかのどちらかで対応できます。

GeekToolでMacのデスクトップをかっこよく


Macのデスクトップをカッコ良くしたい。
以前からずっと考えてはいたが実行してなかったので、今回挑戦。

使用したのはGeekTool。

先に完成形を見せるとこんな感じです。
f:id:ykng0:20170131093103p:plain
まぁかっこよくなったかと言われれば人によりけりでしょうが、個人的にはそれっぽくなったので満足です。
あまりUnixコマンドに詳しくなくても、ネットの力を借りてなんとかここまでできました。


順に見ていこうと思いますが、参考にさせていただいた記事を先に紹介させていただこうと思います。
http://www.lifehacker.jp/2012/07/120727geektool.html
http://iici.cocolog-nifty.com/blog/2011/09/geektool-1b5c.html
http://gunbird.blog.fc2.com/blog-entry-1808.html
http://leopardgecko.hatenablog.com/entry/2016/10/25/161147


基本的なGeekToolの使い方

これは、こちらの記事を参考にしてください。
http://www.lifehacker.jp/2012/07/120727geektool.html

シェル系のgeekletならCommandRefresh everyFontsさえ指定するだけでも十分だと思います。
ちなみに、見た目が汚くてもフォント変えると整形されたりするので、色々試してお気に入りのフォントを探してみてください。
私は、ほぼ全てをCourierのボールドにしました。

以下が設定したコマンド一覧です。

 

基本情報

上から順に、OS、PCのモデル、CPU、メモリ情報です。

echo `sw_vers -productName` \(v`sw_vers -productVersion`\);
sysctl -n hw.model;
sysctl -n machdep.cpu.brand_string;
sysctl -n hw.memsize | awk '{print $0/1073741824" GB RAM"}';

 

システム情報

上から順に、CPUアイドル、メモリの空き、HDDの空いてる容量(あと、何パーセント使用されているか)、Uptimeです。
Uptimeは下のシェルスクリプトです。普通のuptimeコマンドもありますが、こっちの方がわかりやすい。丸パクリです。

top -l 2 | awk '/CPU usage/ && NR > 5 {print "CPU Idle: " $7}';
top -l 1 | awk '/PhysMem/ {print "RAM Free: " $6}';  
df -hl | grep 'disk1' | awk '{print "HDD Free: " $4" ( " $5 " used ) "}';

#!/bin/bash
then=$(sysctl kern.boottime | awk '{print $5}' | sed "s/,//")
now=$(date +%s)
diff=$(($now-$then))
days=$(($diff/86400));
diff=$(($diff-($days*86400)))
hours=$(($diff/3600))
diff=$(($diff-($hours*3600)))
minutes=$(($diff/60))
function format {
if [ $1 == 1 ]; then
echo $1 ' ' $2
else
echo $1 ' ' $2's'
fi
}
echo 'Uptime: '`format $days "d"` `format $hours "h"` `format $minutes "m"`

 

バッテリー情報

これはさっぱり解読不能でしたが、素晴らしい出来栄えだったので、即採用。

ioreg -l | grep -i capacity | tr '\n' ' | ' | awk '{print ("System Battery: ",$10/$5 * 100,"%")}';pmset -g batt |awk '{print $4 $5 $6}'|grep ';'|sed 's/;/ /g'; osascript -e 'set a to do shell script "ioreg -w0 -l | grep Capacity"' -e "set h to word 5 of a" -e "set z to word 33 of a" -e "set b to word 38 of a" -e "set c to 1000 * b / z" -e "set d to round c" -e "set f to d / 10" -e "set q to 1000 * h / b" -e "set w to round q" -e "set j to w / 10" -e '"Battery Health: " & j &"%"' | iconv -f utf-8 -t ucs-2-internal; ioreg -w0 -l | grep "Cycle Count" | awk 'BEGIN { FS = "=" } ; {print $8}' | awk 'BEGIN { FS = "}" } ; {print $1, "Cycles"}';

 

プロセス一覧(CPU利用率順)

稼働しているプロセスを、CPUをくっている順に表示します。
最後の数字を変えれば、表示数を変えることができます。

ps -arcwwwxo "command %cpu" | grep -v grep | head -13

 

プロセス一覧(メモリ利用率順)

稼働しているプロセスを、メモリをくっている順に表示します。
これも、最後の数字で表示数を変えることができます。

ps -amcwwwxo "command %mem" | grep -v grep | head -13

 

プロセス情報と平均ロード

上側がプロセス情報で、下が平均ロードプロセス数です。
プロセス情報は見た通りです。
平均ロードプロセス数については、左から順に1分、5分、15分単位です。
この数は1を切っている方がいいそうですが、基本1超えてる・・・
geekletの更新頻度が高いのが多すぎるせいかもしれません・・・

echo "Processes";
top -l 1 | awk '/Processes/ {print "total: " $2}';
top -l 1 | awk '/Processes/ {print "running: " $4}';
top -l 1 | awk '/Processes/ {print "sleeping: " $6}';
top -l 1 | awk '/Processes/ {print "threads: " $8}';

echo;
echo "Load Avg";
top -l 2 | awk '/Load Avg/ && NR > 5 {print $3 " " $4 " " $5}';

 

ネットワーク状況

接続しているネットワークの情報を教えてくれます。
繋がってないならOFFLINEとか書いてくれるし、かなりスマート。
時々、Script time outとなるのが非常に残念。なんとかできないものか・・・。
あと、MacBook Airの場合は有線LANが無いのでe0がWi-Fiだが、有線LAN付属モデルの場合はe0が有線、e1がWiFiとなるのでスクリプトを修正する必要があるそうなので、ご注意を。

#!/usr/bin/perl

$en0_info = `ifconfig en0 | grep "inet" | grep -v 127.0.0.1`;
$en1_info = `ifconfig en1 | grep "inet" | grep -v 127.0.0.1`;
$ext_info = `curl --silent http://checkip.dyndns.org | grep -Eo '([0-9]{1,3}\.){3}[0-9]{1,3}'`;
$wifi_network = `/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I | awk -F: '/ SSID: / {print $2}' | sed -e 's/.*SSID: //'`;
$wifi_txRate = `/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I | awk -F: '/ lastTxRate: / {print $2}' | sed -e 's/.*lastTxRate: //'`;
$wifi_maxRate = `/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I | awk -F: '/ maxRate: / {print $2}' | sed -e 's/.*maxRate: //'`;
$wifi_channel = `/System/Library/PrivateFrameworks/Apple80211.framework/Versions/A/Resources/airport -I | awk -F: '/ channel: / {print $2}' | sed -e 's/.*channel: //' -e 's/,1//'`;
if($ext_info) {
 $output .= "External: $ext_info";
} else {
 $output .= "External: OFFLINE \n";
}
if($en0_info) {
 $en0_info =~ /inet (.*) netmask/s;
 $en0_info = $1;
 $output .= "Wi-Fi: $en0_info \n";
 $output .= "  SSID: $wifi_network";
 $output .= "  Channel: $wifi_channel";
 $output .= "  Transmit Rate: $wifi_txRate";
 $output .= "  Max Rate: $wifi_maxRate";
} else {
 $output .= "Wi-Fi: INACTIVE \n";
}
if($en1_info) {
 $en1_info =~ /inet (.*) netmask/s;
 $output .= "Ethernet: $1 \n";
} else {
 $output .= "Ethernet: INACTIVE \n";
}
print "$output";

 

天気

これが一番大変だった。
基本的にYahoo天気などを利用するものだが、昔の記事のやつだと、APIの仕様が今と違うようで、そのままコードを使えない。
かといって、どこを変えればいいかもわからない・・・
そのため、新しめの記事のものを採用させていただきました。
説明は全て丁寧に書かれてあるので記事の紹介だけにします。
http://leopardgecko.hatenablog.com/entry/2016/10/25/161147

 

日付と時刻

この部分は一番アレンジしがいのある部分になるかと思います。
基本的に一つのgeekletにつき一つしかフォントや大きさを指定できないので、別々に作って組み合わせていくのがオシャレにできるポイントかなと思います。

また、この類のgeekletはたくさん作られているので、以下などから探すのもオススメです。
http://www.macosxtips.co.uk/geeklets/alltime/page/1

私が採用したシンプルなやつはこちらになります。上が日付で、下が時間です。
曜日を英語表記にしたい方は、下の方にあるset locale environmentにチェックを入れてください。

date "+%m.%d (%a)"
date "+%H:%M"

 

カレンダー

フォントによっては結構ぐちゃぐちゃの形になってしまうので、綺麗に整形されるものを選択する必要があるかと思います。
ちなみに私が使用したのは上にも書きましたが、Courierのボールドです。
私の設定では、今日の日付は色付けしてくれます。途中の31の数字をいじれば他の色にできたりします。

cal_head=`cal | head -1`; cal_tail=`cal | tail -7`; today=`date "+%e"`; echo "$cal_head"; echo "${cal_tail/${today}/\033[1;31m${today}\033[0m}";

 

最後に

自分なりの画面が完成した時の達成感は半端なく、感動的でしたが、なんだかんだシンプルな画面もそれはそれでかっこいいので、気分によって変えたりできればと思います(笑)

Play frameworkを使ってみた ②

前記事:Play frameworkを使ってみた ① - 8t's BBR


前記事に続き、今回はPlayフレームワークでのアプリケーションの開発に最低限必要な部分をまとめたいと思います。

基本的には公式のDocumentationに沿って翻訳しただけになります。


あくまで最低限の部分のみを説明するので、他の実装方法などより詳しい情報は公式を確認してください。

[公式ドキュメント] Home - 2.5.x
[日本語版(但し2.4まで)] Home - 2.4.x


Action

まず、Actionについての説明から。

ざっくり言うと「Play アプリケーションが受け取ったリクエストを処理し、クライアントへ送るレスポンスを生成する Java のメソッド」です。

以下はその一番簡単な例です。

public Result index() {
    return ok("Got request " + request() + "!");
}
  • Result:クライアントへ送るレスポンス。play.mvc.Result型。
  • ok()HTTPステータスコード200(OK)のレスポンスを返す。
  • request():受け取ったリクエストを呼び出す

以上のことから、このJavaメソッドは「受け取ったリクエスト内容をステータスコード200でレスポンスしている」ことがわかると思います。

この3点が基本です。


Controller

ではここで、
「ActionとかいうJavaメソッドはわかったけど、どのクラスに書けばええねん。なんでもええんか?」
という疑問が出てきます。答えはNOです。

名前は自由ですが、play.mvc.Controller型を継承しているクラスでないといけません。
でも逆に言えばこれだけです。

package controllers;

import play.*;
import play.mvc.*;

public class SimpleApplication extends Controller {

    public Result index() {
        return ok("It works!");
    }

}

言ってしまえば、これだけでアプリケーションの動作の記述はほぼ完成してしまいます。
まぁこのままでは、何のロジックも持たず、ただ「It works!」としか言わないクソみたいなアプリケーションですが(笑)


HTTPルーティング

先ほどクソみたいなアプリケーションを作りましたが、次は「どうリクエストしたら「It works!」って言うねん」ってなりますね。
これはconf/routesに書いていきましょう。

GET  /     controllers.SimpleApplication.index()

はい、これだけです。

先頭から順に

  • HTTPメソッド
  • URL
  • アクション呼び出し先

になります。


HTTPメソッド

これは言うまでもないかもしれませんが、
GET、PATCH、POST、PUT、DELETE、HEAD
です。お好きなものを指定できます。

URL

URLの指定方法はいくつかあります。

静的

リクエストを例えばGET/clients/all に完全一致させたいときは、次のように定義できます。

GET  /clients/all     controllers.Clients.list()             

これが基本ですかね。

動的

リクエストの際に、URL からパラメータ(例えば、クライアント ID) を取得するような場合には、動的パートを追加する必要があります。

GET  /clients/:id     controllers.Clients.show(id: Long)

渡したいパラメータ部分の前に:をつける感じですね。
また、呼び出し先にも引数を指定しますが、例のようにパラメータ名: 型という記述の仕方であることに注意してください。

その他

複数の/をまたぐ動的パートや、動的パートで独自の正規表現を使うなど
他にもありますが、その辺は公式ドキュメントを参考にしてください。
https://www.playframework.com/documentation/ja/2.4.x/JavaRouting




これらだけでは、今時のWEBアプリケーションとまでは全然いきません。
ですが、最低限これだけ押さえておけばとりあえずPlayでアプリケーションを作れます。





次回は、「playでデータベースを使うには」でいきたい。

Play frameworkを使ってみた ①

遅くなったが新年初エントリー。就活で書く暇がなかった。


という訳で、今回はPlayというフレームワークを使ってみました。
軽く調べてみると以前使ったことのあるSpringの次くらいにトレンドな感じの印象。


使ってみた感想として、確かに慣れれば開発がはかどりそうだが、やはり初心者が触り始めるには難しい点があります。

  • Documentationが英語
  • Documentationに書かれていることがすべて正しいとは限らない
  • うまくいかない時の対処法はググるしかない

これらは割と何に対しても言えることかもしれないが、特に2番目の問題はきつい。
情報自体が間違っているという訳ではないです。
ただ昔のバージョンでの書き方のまま更新されておらず、いざ真似すると非推奨と怒られたり、うまく動作しなかったりでもう・・・。



そこで今回は複数回にわたって、Playフレームワークの使い方を簡単に紹介します。

第1回ではIntellijで開発を始めるまでを説明しようかなと思います。

ダウンロード

まずはダウンロードから。以下のページからできます。
https://www.playframework.com/download

いろいろとダウンロードできるものがありますが、とりあえずPlayフレームワークを使ってみたいという人は画面中腹あたりのPlay with Activatorという項目のActivator 1.3.12 including Play 2.5.12というものを選択してください。ダウンロードが始まります。

f:id:ykng0:20170123222435p:plain


これを動かすにはJDK8が必要だが、Playフレームワークを使おうと思っている方ならまず入っていると思います。

「え・・・・」って方は以下で今すぐJavaをインストールしておきましょう。PATHに追加しておくのも忘れずに。
Java SE Development Kit 8 - Downloads
Javaのインストール方法、およびPATHへの追加の仕方は調べればいくらでも出てきます。


ダウンロード以降はこちらが非常に参考になります。
Installing - 2.4.x

クイックスタートの項目の最初に最新の Typesafe Activator を ダウンロードする とありますが、これは先ほどダウンロードしたActivatorなので気にしない。
あとは手順通りにやれば、とりあえずうまくいくはず・・。

activatorコマンドがないという方はbinディレクトリにあるはずなのでそれを指定してください。
また、そこにPATHを通しておくと便利です。


Playのプロジェクト作成法

Playのプロジェクトの作り方は細かく説明すると大変なので、とりあえず簡単な作り方を。

まずはプロジェクトを作りたいディレクトリまで移動してから、以下のコマンドを順に実行します。

// [project-name]にはお好きなプロジェクト名を指定してください。
$ activator new [project-name] play-java
$ cd [project-name]
$ activator run

プロジェクトをactivator newで生成後、activator runせずにIntellijにインポートしてからRunしようとすると
view.htmlなどのシンボルが見つかりませんとのエラーが出ることがあります。
ので、こうなってもなってなくても3の手順は一回踏むべきかもしれない。(その後に Ctrl + D で終了しても大丈夫)
ちなみに、javaじゃなくてscalaで開発したいって方は、最初のnewでplay−javaではなくてplay-scalaと指定してください。


Intellijへのインポート手順

Playのアプリケーションはeclipseなどでも開発できますが、この記事ではIntellijでのインポート手順を説明します。

Intellij派の人もそうでない派の人もこちらを参考に進めてください。
https://www.playframework.com/documentation/ja/2.4.x/IDE


Intellijで展開するにあたって、注意しなければいけないのが、先ほどのページにも書かれているが、Play2.4からはNew Projectから作成のは非推奨であるという部分。
これは先ほどのactivator newからプロジェクトを作成する方法をせずに、Intellijで直接作成するというなんとも便利そうな話であるが、少なくとも2.5の私の環境では途中で失敗してできなかった。非推奨ではなくて、やめてくださいと書いてほしい。
大人しく、activator newからプロジェクトを作成してそれをIntellijにインポートするようにしましょう。


では、前置きが長くなりましたが、以下がIntellijへのインポート手順になります。

  1. Intellijのメイン画面で Import Projectを選択し、先ほど作成したプロジェクトを選択。
  2. Import project from external modelからSBTを選択。Nextを選択し、次もJDKが正しく設定されているのを確認したらFinishを選択。
  3. プロジェクトを展開できたら、Project Structure を開き、 Modulesの項目からroot の Dependencies の項目に scalasdk があることを確認。なければ追加。

f:id:ykng0:20170123230757p:plain

最後にRun Configurationの設定も行いましょう。+をクリックして SBT Tasks を選択。Tasks に run とだけ書いて apply して保存。これで Control + r で実行できます。

実行したらhttp://localhost:9000でアクセスして、動いていることを確認できます。


うまくいかない時

Intellijにインポートする時に、Import project from external modelからSBTを選択しようにも項目が出てこない場合があります。
これを解決するには、Intellijscalaプラグインをインストールする必要があります。
Intellijのメイン画面から、Configure->Pluginsを選択し、Install JetBrains plugins...を選択。
そしてscalaと検索し、出てきたプラグインをインストールすれば問題は解決されると思います。
f:id:ykng0:20170123231726p:plain
f:id:ykng0:20170123232030p:plain
f:id:ykng0:20170123232202p:plain





次回は、Playを使ったアプリケーション開発をする上で最低限必要なポイントを紹介したいと思います。
Play frameworkを使ってみた ② - 8t's BBR

Slackのボットのアイコン画像の指定

こんばんは、世間はクリスマスで賑わっていますが、僕はいつもと変わらぬ1日でした。
いえ、ボッチではありません。Slack Incoming Webhooks を利用してBotと遊んでいましたよ。

さて、ヤジが飛んでくる前に本題に入ります。
先ほど紹介したSlackのBotですが、いろいろ凝りだすと、やはりアイコンにもこだわりたくなるものです。

普通はBotの設定ページにて、[Upload an Image]か[Choose an emoji]から選択するだけで済みます。
f:id:ykng0:20161225222952p:plain


・・が、僕のようなひねくれ者は、JSONBotのパラメータを設定しているのでJSONをいじって変更したい。
そんな時は、icon_urlicon_emojiで指定します。

          :
    'icon_url' : 'http://path/to/image',
    'icon_emoji' : ':ghost:',
          :

みたいな感じです。ちなみに、このicon_emojiの例は名前どおりゴーストです。結構かわいい感じ。
絵文字チートシートEmoji cheat sheet for GitHub, Basecamp and other services

2つとも指定した場合は、icon_emojiの方が優先されます。


困ったことに、icon_urlはあくまでHTTPアクセスできるもの限るっぽいです。
ローカルにある画像を指定したいのですが、どこかにアップロードしてそのURLを指定するしかなさそうです。

ローカルにあるものを直接指定できる方法をご存知の方はどうかご一報ください。