なからなLife

geekに憧れと敬意を抱きながら、SE、ITコンサル、商品企画、事業企画、管理会計、総務・情シス、再び受託でDB屋さんと流浪する人のブログです。

「アプリケーションエンジニアのためのApache Spark入門」読んでみた

先にまとめておく

  • ApacheSpark2.2.0ベースでの記述で、サンプルソースはSaclaではなくPython(pyspark)。(個人的にはPython歓迎!だが、scalaベースで学びたい人には残念かもね。)
  • Sparkの話だけではなく、fluentd+Kafkaで常時データが生成される環境を作る、具体的なシナリオベースでの解説。これはありがたい!
  • 4章以降、順番に消化していかないとソースとしては動かない構成。
  • 共著で章別に担当したらしく、イマイチ連携取れてないと感じるところがある。共著って、一人あたりの執筆負荷は減るけど、こういうところが難しいよね。
  • サンプルソースがダウンロードできるが、本文にソースのファイル名が記載されていないことがある。
  • サンプルとしてシンプルなものを扱いつつ、実運用に向けて考慮すべき話も各章で言及されているあたり、テクニカルライターというより現場の技術者である、という矜持を感じる。
  • 電子書籍版(Kindleepubかpdf)で欲しかった(発売から3ヶ月過ぎても出る気配なし)
  • 全体としては、人に推薦できる「良本」です。これからSpark触りたい人、ついでにストリーミングデータの扱いについて理解したい人にとって、手を動かしながら学べる本は少ないですからね。貴重です。


以下、章別にメモ垂れ流します。



Chapter1: データ分析プラットフォームの概要

概要の概要なので、言及割愛。


Chapter2:Spark概要

Sparkの概要。ベースとなる環境構築の話。

VagrantVirtualBoxCentOS 7.2+Spark2.2.0」を構築する手順が解説されていますが、「Vagrantなし+VirtualBoxCentOS 7.5+Spark2.3.0」でやりました。

よって、先々でてくるソースを写経するにあたり、Sparkのバージョン指定や、標準不足のライブラリをオプション指定する際に、微妙にバージョンが違うことがあり、時々躓きました。
「Sparkがこのバージョンだから、指定するライブラリはこのバージョンだけど、違う場合は変えてね」とかいう補足がなかったなと。

あと、この環境、IPアドレスが決め撃ちされていて、そのIPアドレスであることが前提として以降の章のソースなども記述されているので、ここも自分の環境に置き換えて行く必要がありますが、スタンドアロンで全部構築しているのに、サンプルソース上も「localhost」ではなくIPアドレスが記述されているので、ソースコピペで動きを見ようとするとコケます。

このとき、エラーメッセージから原因がソコであることを推測しにくいのが難点ですね。

Chapter3:サンプルユースケース概要

仮想の農場に仕込んだセンサーのデータをFluentd+Kafkaでストリーミングデータとして送り込んで、Apache Spark上でデータをアレコレするよ、って話です。

Chapter4:Fluentd、Kafkaによるデータ収集

Spark上でお料理するデータを取り込む仕組みのお話です。Sparkが主体の本ですから、それぞれの説明はサラっとしていますが、最低限の説明はしっかりされています。一応別でFluentdとKafkaの勉強はしたから大丈夫でしたが、ここで初めて触る人にはちょっとツラいかも。

この章は、記載されているソースに番号が振ってなくて、サンプルソースのファイルとの対応関係が取れていません。なので、ファイル開いてみないとわからないです。残念。

たとえば、P62のサンプルソース(こういうところでソースに番号がついてないと説明もツラい)で、ConsoleProducerは9092ポートにつないでいるのに、ConsoleConsumerが2182ポートにつなぐところがあって、見事にメッセージが取れない。直後のP63のConsumerは9092につないでいるので無事メッセージ取れます。


また、P51のセンサーデータ用Fluentd設定で、

/var/log/td-agent/pos/sensor_data.pos

が権限不足。

systemctl start td-agent

が裏でずっとエラーを吐き続け、過去に通ったはずのCURLによる稼働確認すら通らなくなるので、先に「td-agent:td-agent」で
/var/log/td-agent/pos/
を作成するか、むしろ一切記述しない、といった対応が必要になります。

この設定を使う話は、次の5章P99でやっと話が出てくるので、本来この時点では設定を入れる必要がない(そういうシナリオになってない)のですが、本文解説でも出てくるしダウンロードできるソース(04-01.conf)にも書いてあるので、勢いで設定するとハマります。



Chapter5:Spark Streamingによるデータ処理

Spark Streaming、および、Spark2.2系からProduction ReadyになったSpark Structured Streamingについて扱っています。これ両方書いてあるのなにげにありがたい。

ここでの躓きどころ。

P90 の

nc -lk 9999

は、前の章からの流れで、td-agentをport:9999で立ち上げっぱなしにすると衝突します。
よって、

systemctl stop td-agent

してから実行すると、標準のプロンプトに戻らず、ポート9999に文字列を継続送信可能な状態になります。



P96でSpark「Structured」Streamingの「Checkpointの設定設定コード」が紹介されていますが、これをどのソースのどこに埋めるのかに埋めるべきかの指示記述がないです。

ここは、05-02.pyで同じ「query = 」の行を置き換えれば、wordCounts.writeStreamを使わなくなってしまうけど大丈夫かとおもいます。

とはいえ、05-02のソースなのに、出力先が05-01用のディレクトリ向いてるのも気になるところです。


P99から、いよいよ、fluentdとKafkaとの連携が本格化します。

で、そのP99で、fluentdに食わせるセンサーデータログを生成し続けるプログラムをcrontab+シェルスクリプトという形で作ることになりますが、ここでAppendixに飛びます。

ここでしかAppendixに飛ぶタイミングがないので、むしろここで書いても良かったんじゃないか、という。

で、Appendixに書いてあるソースですが、「mdkir」なのに「.log」とファイル名まで書いちゃってる。ダウンロードできるスクリプトの方は正しいですね。



なお、fluentdのエラーにならなければ、仮想マシンに割り当てるCPUは1個でも十分処理できました。
が、pysparkの実行は、CPU使用率の割に時間がかかります。立ち上がりの処理が重いからですかね。
起動のオーバーヘッドが大きいからこそ、ある程度の量のデータを捌くシステムで使わないと、Sparkの速さを享受できない、ってことでしょうか。



Chapter6:外部ストレージへのデータ蓄積

5章はfluentd+kafkaからSparkに取り込んで処理した結果はコンソールで確認するまででしたが、ここでは、ファイルにjsonやparquetで保存したり、Cassandraに保存するケースが取り上げられています。
できれば一般的なRDBMSとしてMySQLPostgreSQLあたりとの連携も取り上げてほしかったなあ。。。


で、Cassandraインストールなのですが、P143にあるyumリポジトリ設定の記述だとうまくいきませんでした。
「repo_gpgcheck=1」が抜けていて「KEYがインストールされてない」といってインストールが止まってしまいますので、追加して切り抜けました。


さらに、インストールの直後、

systemctl start cassandra

しても起動できず、

systemctl daemon-reload

を叩く必要がありました。

Cassandra公式サイトに書いてはあるものの、CentOS7系前提で執筆されている本なので、このへんはフォロー欲しいところですね。



で、その後もP150とかP152の実行の際に、「java.lang.NoClassDefFoundError」で落ちるという現象を回避できず、直近でCassandraを扱う予定もなかったことから、Cassandra連携を試すのは諦めました。



Chapter7:SparkStreamingによるデータ分析

Chapter5ではストリームデータ1行1行を取り込むところを扱いましたが、こちらでは複数行をまとめて集計分析等を行うケースを扱っています。
ストリームデータ分析自体の説明にもページを割いている点は好印象ですが、ちょっとその先が荒っぽい印象を持った章です。


P173で突然「環境前提」があるのですが、具体的に何が動いているべきかのコード番号等がないので、ちょっと面食らいます。

サラッと書かれているけど、以下のことをやる必要があります。
特に、前の章までの勢いを中断して再開したような場合、確実に躓きます。

P56:zookeeper起動(コード番号なし)
P57:kafka起動(コード番号なし)
P99:05-06_command.txt+P100 05-01.conf(/etc/fluentd/fluentd.confへの追加設定)+systemctl start td-agent
P334:appendix1のexecute_create_sensor_data.shの用意+crontab設定
P117:05-13_command.txtの実行(及び呼び出される05-08.pyの用意)

この順で起動した後に、07-01_command.txtを実行することになります。以降、07-06までずっと使用するので起動しっぱなしで良いです。


この「前提」のところの躓きさえクリアすれば、あとは特に躓くこともなく、Window方式を変えたりいろいろなパターンの集計処理が扱われていて実践的な話が豊富です。


Chapter8:Spark SQLによるデータ処理

タイトルはSpark SQLですが、ここから唐突にJupyterを使うことになります。そして、pandasとmatplotlibも。


そして、この章はChapter7以上に前提の切り方が荒いです。サンプルデータの提示がなく、こんな感じのデータがある前提で進めます、という進み方です。
その前提となるデータをどうすればよいのかが、かなり投げやりで、以前のどこの章、すら書いてません。この章用のディレクトリを掘れ、とも書いていません。そうなっていることを前提とします、だけです。


ここは、以下のような感じで切り抜けました。

  • センサーデータのJSON

過去の章でkafkaトピック「sensor-data」として登録していたデータをJSON形式で。
chapter06でsensor_dataをjsonファイルに出力する事例がありますので、コレにならって/opt/spark-book/chapter06/data/jsonの下.jsonファイルを、sample.sensor.*.jsonのファイル名形式にrinameしながら、あるいはfluentdが拾う前の/var/log/sensor_data/sensor_data.logを、そのままsample.sensor.sensor_data.jsonとかいう名前にRenameして/opt/spark-book/chapter08/dataの下にコピーしておけばよいかと。


結果サンプルはともあれ、処理のサンプルコードでは日付を条件指定していないのに、サンプルデータの年月日を固定しつつデータは用意しない、というのは不親切じゃないかなと思いますね。

  • 畑マスタのCSV

P109のものを、1行目のカラム名定義行を_c0,_c1に書き換えて、/opt/spark-book/chapter08/masterの下にsample_sensor_filed.csvという名前で置いておきましょう。




P212の「日付でgroupBy count」をやるときに、date列にdate_format()を行うのですが、ただし、日付のフォーマットが上記2例で用意したものだとyyyy/mm/ddとスラッシュ区切りになっていますが、そのままだとdate_format()に食わせるときに認識してくれません。
jsonファイル内でyyy-mm-ddフォーマットに変換するか、このサンプルコードを実行するときだけ

date_format("date", "yyy/MM")

date_format(replace(date, '/','-'), 'yyy/MM')

と、spark.sqlの中のSQLを書き換えてあげましょう。


pysparkの方だと、

from pyspark.sql.functions import *
base_sensor_rep = base_sensor.withColumn('date', regexp_replace('date', '/', '-'))
base_sensor_rep.groupBy(date_format("date", "yyy/MM").alias("new_date")).count().show()

といった具合に、regexp_replace(他に適した関数ある?)といった変換を1ステップ挟んであげましょう。

とにかく日付形式の文字列を日付として認識させるにはハイフン「-」区切りでないとうまくいかないようです。


欠損値やNull値の処理方法の解説がP213、214とありますが、同様に上記の方法で準備したデータに対象となるようなデータがありません。あしからず。



また、dateでグルーピングする集計例が複数出てきますが、用意できたデータの日付に偏り(1日分しかないなど)がある場合、yyy-MMで集計している例をyyy-MM-ddにするなどしてバラしてあげないと面白くない結果が帰ってきます。




P226冒頭のjsonファイルの出力パスは誤植なのか共著者間の調整不足なのかな?という部分ですね。

/opt/shuwa-book/chapter08/result/field_data/

は、これまでの流れだと

/opt/spark-book/chapter08/result/field_data/

でしょう。

ダウンロードできるサンプルソースも、この章はJupyterNotebookの「.ipynb」ファイル1個だけ、という感じで、全体的に粗さが目立つ章でした。

扱うテーマが割と実用的な話なだけに、ちょっと残念。
あと、Jupiter、Pandas、Matlotlibについては、Spark関係なく別でそこにフォーカスした本があるはずなので、そっちでキャッチアップしたほうが良さそうです。


Chapter9:Spark MLlibによるデータ分析

MLlibの名の通りMachine Learningの話なので、まず大前提となる機械学習概論に冒頭かなりのページ数が割かれています。
喫緊で機械学習をやる予定のない場合、かなりしんどいと思いますし、機械学習を学ぶ必要がある場合は、別途勉強するのがオススメでしょう。


とりあえず、記述通りに動くかどうかだけ試しました。
なお、ここでのサンプル実行処理は重いです。仮想マシンにvCPUを追加で割当しておきました。


Chapter8と同じJupytorを使いますが、こちらの章はテスト用のデータがダウンロードソースの中にcsvで提供されています。
データの配備先がchapter09ディレクトリではないのが微妙ですが。


ユースケースに関する回帰分析の実施サンプルで、2番目で突然セッションとスキーマの定義を省略(前にやったから省略するよ、ってだけで、どこを見ろと書いてない)になるところでびっくりした以外は、わりと順調に進みました。

あと、同じところでcsvファイルからdf6というデータフレームを作るところで何度もエラーで落ちたのですが、原因わからないまま仮想マシンの再起動を実施したら治りました。HiveMetastoreへの書き込みが詰まったらしいのですが、なんでそうなったのかは未だに分からず。




ここ中身理解せず雰囲気で機械学習(写経)しましたが、結構な量があってツラかったです。が、誤植等によるエラーはなかったのが救いですね。




Chapter10:プロダクションに向けたシステムアーキテクチャを考える

この章はアーキを考える章なので、ソースを動かしてどうこう、って話ではありません。
アーキの話を冒頭じゃなくココに持ってくるの珍しい&一通り「雰囲気でやってみた」後に、ちゃんと理解しようって順番もイイ。


Sparkがどう動いている、ってだけじゃなく、AWSGCPでどう構成する、って話まで及んでいるのも嬉しいですね。できればAWS Glue(PySpark)にも触れてほしかったけど、あれは完全マネージドでそれ以上の中身の話は公表されてもいないから難しいか。

最後に

直近Sparkを触らなくてはいけないという強烈な課題意識のもとに読み始めたこともあって、かなりしっかり読み込めました。
そして、期待に沿う内容でした。

共著ゆえの難しさは経験したので理解しているつもりで、小さい所は逐次上記で指摘はしたものの、一貫したコンセプトがブレることなく、しっかりまとめてあったと思います。
私の中では「良本」にランクインしてますね。


また、Sparkに限った話じゃないけど、イノベーター・アーリーアダプター層が早い段階でいじって騒いで、その層にはある程度普及したプロダクト、レイトマジョリティ層が触るころにはバージョンアップにともなってアーキも一部変わってたり、当時ベースのネット記事は陳腐化してるし、新しい情報も出てこないし、当時の人たちは新しいプロダクトに飛びついていたりして、余程定着して「知の高速道路」がメンテ続けられてるものじゃないと、わりとツラいんです。


出版社も、出てきた当初の盛り上がりには敏感だけど、安定期にはいったプロダクトに関する書籍の出版の企画には、あまり積極的になってくれない。つらい。


私がこの本を読む前にSparkについて勉強したときの本は「Apache Spark入門 動かして学ぶ最新並列分散処理フレームワーク」で、2015年初版、Sparkは1.5系で、DataFrameじゃなくRDDベースです。これはこれで良い本でしたが、購入時点でSpark2系が出ていたのに対応している本がなかったです。個人的には当時よりSpark学習欲が高まった(ていうか喫緊の課題としてSparkを使う用事がある)ときに、今回の本が出版されたのはホントにありがたい。


そういう点で、この本はもっと評価されていいんじゃないかと思ってます。
でも、Amazon上、評価の良し悪し以前に件数自体がすごく少ない。。。一応「ベストセラー」は付くようになったから、それなりに売れて入るんでしょうけど。


「だからとにかく、技術書は問答無用で電子も出してくれ。」


いろいろな場所で仕事する隙間に読んで触って書き残して、ってやるのに、紙の本はホント不都合なんですよ。
電子じゃないので買うのためらう+買っても物理的制約で読み進まない=ブログ記事に落とすまでに時間がかかってしまったら、普及に貢献することすらできないです。

良い本は広めたい。


アプリケーションエンジニアのためのApache Spark入門

アプリケーションエンジニアのためのApache Spark入門