社内se × プログラマ × ビッグデータ

プログラミングなどITに興味があります。

awk でパターンにマッチする行のみを抽出する

こんな感じでスラッシュで挟んで指定すれば良いらしい。

$ xwininfo | awk '/Width/'
  Width: 1360

ただ、単に抽出するだけなら、 grep で十分かも。

$ xwininfo | grep 'Width'
  Width: 1360

抽出した結果を変数に入れて処理するには便利そう。

$ xwininfo | awk '/Width/ {width = $2} END { print "width="width }'
width=1360

Java challenge cloneable

Java challenge 既出のコードです。
出力結果を考えてみます。

ソースコード
public class CloneableChallenge {
    public static void main(String[] args) throws CloneNotSupportedException {
        Human human17 = new Human("cells");
	Human human18 = (Human) human17.clone();
		
	System.out.println(human17.equals(human18));
    }
	
    static class Human implements Cloneable {
	Cell cell;
		
	public Human(String cellName) {
	    this.cell = new Cell(cellName);
	}
		
	@Override
	public Object clone() throws CloneNotSupportedException {
	    return super.clone();
	}
    }
	
    static class Cell {
	String name;
	public Cell(String cellName) {
	    name = cellName;
        }
    }
}
予想

"false" が出力される。
正直、Cloneable をちゃんと使ったことがないので、clone 自体のコードに問題があるか分からないです。
単純に Human クラスのインスタンスが正常に clone 出来たと仮定したら、 それぞれ別のメモリ上に存在するはず。

結果

"false" が出力された。
うーん。ただ、上記の理解で正しいのかが分からない。
実際にこの challenge をした人のコメントを見てみると、human17.cell.equals(human18.cell) では true が返ってくるらしい(手元の環境でも true になった)。

Human class は別々のオブジェクトだが、クラス変数である Cell は同じオブジェクトを参照しているということか。

以下のサイトも参考になりました。
promamo.com

試したソースコード
github.com

Java private フィールドをモックする

private フィールドをモックする junit 書きたいなと思って調べたら、すぐに出てきたのが mockito の whitebox.
以前使ったことがあった気がするけど、忘れていました。

とりあえず簡単なサンプルで
public class WhiteBoxExample {
	
	private String message = "This is example.";
	
	public WhiteBoxExample() {
	}
	
	public String getMessage() {
		return message;
	}
}

これの message 変数に格納されている内容を書き換えるということです。

junit の方は
public class WhiteBoxExampleTest {

        // 1つ目は何もせずに、そのまま出力させるテスト
	@Test
	public void testWithoutWhiteBox() {
		WhiteBoxExample wb = new WhiteBoxExample();
		assertTrue(wb.getMessage().equals("This is example."));
	}

        // 2つ目は whitebox を使って、値を書き換えてます
	@Test
	public void testWithWhiteBox() {
		WhiteBoxExample wb = new WhiteBoxExample();
		Whitebox.setInternalState(wb, "message", "overwritten the message.");
		
		assertTrue(wb.getMessage().equals("overwritten the message."));
	}
}

Whitebox.setInternalState(対象クラスのインスタンス, "モックするフィールド名", 置き換える値);
たったこれだけで private フィールドが置き換わってしまいました。
非常に強力なライブラリだと思いますが、何でも置き換えてしまうと、本来の仕様に沿ったテストから遠ざかってしまう気がします。
テストのコア部分を置き換えるのではなくて、そこに到達するまでのあくまで補助的に使った方が良いですね。
そもそも頼らないでテスト出来るように設計出来れば良いのかもしれませんが。

SparkSql で5教科の成績に評価を付けてみる

SparkSqlはSpark上でSQLを利用するためのコンポーネントです。
Sparkの分散環境上で大量データに対して高速なSQLを実行できます。

SparkSqlでソートする練習のために、5教科の成績に評価を付けるプログラムを書いてみました。
例えば、今5人(A君~E君)がいるとして、英語の成績が以下であるとします。
A君:100点
B君:80点
C君:60点
D君:40点
E君:20点

その順位に応じた評価点をつけます。
上記の場合、A君:5点、B君:4点、C君:3点、D君:2点、E君:1点という感じです。
これを5教科(国語、数学、英語、理科、社会)に対して行い、合計の評価点を計算します。

元の点数そのまま使えばいいやんという感じでもありますが、ソートして連番を付ける練習がしたかったので、こんな計算をするようにしています。

ソースコードはこちらgithub.com

SparkSql で扱うエンティティには getter を定義しなければならない!

今回、成績を格納するエンティティとして、RecordData というクラスを定義しましたが、必ず各フィールドに対して getter を定義する必要がありました。
最初は定義していなかったのですが、DataFrame に対して、printSchema() を実行しても、select 文を発行しても何のデータも得られませんでした。
どうやら、getter 経由でデータを取得してくる仕様のようです。

SparkSql でも Window関数が使える!

select 文の結果に対して連番を付与する場合、SQLではWindow関数のrow_numberという機能がありますが、SparkSqlでもそれが使えるようです。
DataFrame には zipWithIndex 関数もありませんし、これは便利ですね。

df.select(row_number().over(Window.partitionBy().orderBy(orderElement1))
Window関数を使うためには HiveContext が必要!

HiveContext なしで使おうとすると、以下のエラーメッセージが表示されてしまいました。

Exception in thread "main" org.apache.spark.sql.AnalysisException: Could not resolve window function 'row_number'. Note that, using window functions currently requires a HiveContext;

なので、SQLContext は HiveContext から作りました。

SQLContext sqlCtx = new HiveContext(jsc);

ただ、コンテキストの生成処理に体感でも数秒間時間がかかっている気がします。

実行確認

printSchema() の実行結果。

root
 |-- english: integer (nullable = true)
 |-- japanese: integer (nullable = true)
 |-- mathematics: integer (nullable = true)
 |-- name: string (nullable = true)
 |-- science: integer (nullable = true)
 |-- social: integer (nullable = true)

日本語の成績。このように点数の多い人から、高い score が付けられています。

+-----+-------+--------+
|score|   name|japanese|
+-----+-------+--------+
|    1| Edison|       3|
|    2|Clinton|      13|
|    3|    Abe|      51|
|    4| Donald|      63|
|    5|   Bush|      66|
+-----+-------+--------+

数学の成績。みんな低すぎでしょ。

+-----+-------+-----------+
|score|   name|mathematics|
+-----+-------+-----------+
|    1| Donald|          2|
|    2| Edison|          2|
|    3|   Bush|          6|
|    4|    Abe|          9|
|    5|Clinton|         40|
+-----+-------+-----------+

英語の成績。単なる乱数とは言え、0点が出てしまった。

+-----+-------+-------+
|score|   name|english|
+-----+-------+-------+
|    1| Donald|      0|
|    2|    Abe|     29|
|    3|Clinton|     40|
|    4|   Bush|     49|
|    5| Edison|     51|
+-----+-------+-------+

社会の成績。

+-----+-------+------+
|score|   name|social|
+-----+-------+------+
|    1| Donald|    12|
|    2|Clinton|    53|
|    3| Edison|    72|
|    4|    Abe|    84|
|    5|   Bush|    98|
+-----+-------+------+

最後は、理科の成績。

+-----+-------+-------+
|score|   name|science|
+-----+-------+-------+
|    1| Edison|      6|
|    2| Donald|      7|
|    3|Clinton|     61|
|    4|   Bush|     69|
|    5|    Abe|     90|
+-----+-------+-------+

そして、総合成績。totalScore は綺麗に3の倍数になりました。

+-------+----------+--------+-----------+-------+------+-------+
|   name|totalScore|japanese|mathematics|english|social|science|
+-------+----------+--------+-----------+-------+------+-------+
|   Bush|        21|      66|          6|     49|    98|     69|
|    Abe|        18|      51|          9|     29|    84|     90|
|Clinton|        15|      13|         40|     40|    53|     61|
| Edison|        12|       3|          2|     51|    72|      6|
| Donald|         9|      63|          2|      0|    12|      7|
+-------+----------+--------+-----------+-------+------+-------+
まとめ

今までは、DataFrame で出来ないことを RDD に変換してから処理して、また DataFrame に戻すみたいなことをしていたけど、SparkSql(DataFrame) のままでも出来ることは思っていたより多い。
変換処理のオーバーヘッドも減らせるだろうし、使っていくのが楽しみになってきました。

Apache ZooKeeper の基本について調べてみる

概要

・分散アプリケーションを構築する上では、同期、設定管理、グルーピング、名前管理などの機能が必要となる。

→これらの実装は複雑で面倒なもの

→Zookeeper はこれらの機能を提供してくれる

・ただし、Zookeeper が提供するのは、基本機能要素そのものではなく、基本機能要素を独自に実装できるようにするための、ファイルシステム的なAPIを提供する。

・基本機能要素を実装したものをレシピと呼ぶ。

→レシピは znode と呼ばれる小さいデータノードの操作で構成される

・ ZooKeeper はJavaで書かれており、 jvm 上で動作可能。

 

API

・ znode を生成、削除したり、znode にデータを格納するようなものが提供されている

・ ZooKeeper クライアントは、ZooKeeper サービスに接続し、セッションを確立する。

→セッションを通してAPIを呼び出す

 

注意点

・ znode のデータは部分的に書いたり、読み出したりすることはできない

→完全置き換え、完全読み出し

→原子性の確保とも言えるかも

 

znode のモード

・永続(persistent) znode

→意図的に delete しないと削除されない

→これを作成したクライアントセッションが無くなったとしても、維持しなければならない場合に役立つ

 

・短命(ephemeral) znode

→作成したクライアントがクラッシュしたり、接続がクローズされると自動的に削除される

→これを作成したクライアントセッションが有効な間だけ存在するべき情報を保持する場合に役立つ

→クライアントから意図的に削除することも可能。作成したクライアントでなくても削除可能。

→基本的に消えてしまう性質から、短命 znode には子ノードは作成できない。(今も?)

 

・シーケンシャル znode

永続 znode、短命 znode 何れもシーケンシャルにすることが可能。

→znode にユニークな番号を付与するのに便利

Apache Spark の SparkConf について調べてみる

Spark のチューニングにおいて重要な要素の一つとなるであろう SparkConf について調べてみる。

 

概要

・SparkConf クラスは、Sparkにおける主要な設定の仕組みである。

・SparkConf のインスタンスは新しい SparkContext を生成するときに必要になる。

・SparkConf のインスタンスには、ユーザがオーバライドしたい設定オプションが、キー/値ペアとして含まれている。

 

SparkConf の構築例 (Scala)

val conf = new SparkConf()
conf.set("spark.app.name", "App name")
conf.set("spark.master", "local[*]")

val sc = new SparkContext(conf)

 

・set メソッドは自分自身のインスタンスを返すので、メソッドチェーンで連続して set が可能。

spark-submit 実行時に設定する場合
・spark-submit で設定された値は自動的に検出され、新しい SparkConf の構築時に設定される。
→ アプリケーション側では、空の SparkConf を構築したとしても、spark-submit での設定値が反映される
→ spark-submit でSpark の設定値を受け付ける汎用の --conf フラグがある

設定ファイルからのロード
・spark-submit はファイルから設定値をロード可能
→ デフォルトでは、conf/spark-defaults.conf ファイルを読み取ろうとする
→ ファイルの場所は spark-submit の --properties-file フラグでカスタマイズ可能

注意点
・SparkConfは、一旦 SparkContext のコンストラクタに渡された後は変更できない
→ Spark の設定は途中で変更出来ないということ
・複数の場所で同じプロパティに対する設定が行われた場合、優先順位がある。
→優先順位の高いものから
アプリケーションコード内でset -> spark-submit のフラグ ->
プロパティファイル値 -> デフォルト値
→ Web UI を使えば、有効になっている設定のリストが見られる

応用
For unit tests, you can also call new SparkConf(false) to skip loading external settings and get the same configuration no matter what the system properties are.
→ つまりは "VM引数を読み込まない" ということらしい

・spark-shell において、SparkConf を設定した場合、 sc.stop で sc を停止した後、改めて定義する必要があるらしい。

http://stackoverflow.com/questions/31397731/customize-sparkcontext-using-sparkconf-set-when-using-spark-shell/31402667#31402667

・使用できるプロパティ

https://spark.apache.org/docs/latest/configuration.html#available-properties

Apache Curator Framework のリトライ処理について調べてみる

zookeeper サーバと接続出来なかった場合、そのリトライ処理はどのように実装されるのか?

 

概要

・ Curator とは、Zookeeper 上に構築された一連の高レベルライブラリ

→複雑な接続処理を容易にするAPIを提供してくれるもの

 

前提

・ローカル環境で Zookeeper サーバを起動していない状態において、Curator を使用したアプリを起動してみる。

→当然、接続はされないはず

→設定されたタイムアウト時間、リトライ回数後に終了してくれるはず?

 

実践

・新しい curator クライアントを生成する。

https://github.com/blueskyarea/zookeeper/blob/master/curator/sample-newClient.java

→新しい curator クライアント生成時において、セッションタイムアウト時間、コネクションタイムアウト時間、リトライ回数などを定義出来るようだ。

 

まとめ

・セッションタイムアウト時間は、一度はコネクションはされたものの、サーバと通信出来なくなった場合のタイムアウト時間っぽい。

・コネクションタイムアウト時間は、サーバに初めて接続を試みたが、サーバと通信出来ない場合のタイムアウト時間と思う。

・セッションタイムアウト時間、コネクションタイムアウト時間はそれぞれ1試行内の猶予時間。タイムアウトしたとしても、リトライ回数が残って入れば改めてタイムアウト時間まで接続を試みる。

 

応用

・curator を生成するだけでは、zookeeper への接続は必ずしも発生しない?

→curator 生成するだけなら、 zookeeper 停止していてもエラーにならないかも

→znode を作成するタイミングで zookeeper に接続しにいくから、そこでエラーになる

・デフォルトのセッションタイムアウト時間、コネクションタイムアウト時間は?

https://github.com/apache/curator/blob/master/curator-framework/src/main/java/org/apache/curator/framework/CuratorFrameworkFactory.java

→バージョンによって異なるとは思うが、セッションタイムアウトは60秒で、コネクションタイムアウトは15秒。

・リトライが終了したら、 例えば ConnectionLossException が発生する(はず)

 

参考リンク

http://curator.apache.org/curator-client/

http://curator.apache.org/getting-started.html

https://curator.apache.org/apidocs/org/apache/curator/framework/CuratorFrameworkFactory.html

https://curator.apache.org/apidocs/org/apache/curator/framework/CuratorFrameworkFactory.Builder.html