Taste of Tech Topics

Acroquest Technology株式会社のエンジニアが書く技術ブログ

Elasticsearch設定に関する小ネタ

こんにちは、ツカノ(@)です。

この記事はElasticsearch Advent Calendar 2014の21日目です。
20日目はjtodoさんの「Spark on elasticsearch-hadoop トライアル」でした。

さて、以前、「Elasticsearchソースコードリーディング~内部構造把握の第一歩~」と題してElasticsearchのスレッド構成といった内部構造の話を書きましたが、今回もまた、似たような話です。
今回はElasticsearchの設定ファイルについてです。
f:id:acro-engineer:20140131080117p:plain

1.ノード名について

Elasticsearchのデフォルトのログフォーマットでは、ノード名が出力されます。クラスタで運用することも考えると、ノード名って重要ですよね。ノード名の設定方法については、公式ページに記載があります。
ここで面白いのが、設定を省略した場合の動きです。Marvelのキャラクター名からランダムで設定されるそうです。
githubにある設定を実際に見てみましょう。

2826個も名前が書いてあります。
ざっと見ると、Iron ManとかX-Manとかって名前がありますね。運が良ければ(?)あなたのノード名が「Iron Man」になるかもしれません。

この設定ファイルには、以下のような名前も書いてありますね。日本っぽい名前だけれど、私はMarvelは良く分からないので、Marvelの何に由来しているのか分かりません。。。

  • Kimura
  • Mariko Yashida
  • Mikado
  • Shingen Harada
  • Shirow Ishihara
  • Sushi
  • Yukio

こういうノード名が付く可能性があるんですね。

2.設定ファイルのフォーマット、読み込む順序

Elasticsearchの設定ファイルはjson形式でもyaml形式でもproperty形式でも書け、結構便利ですね。
設定ファイルも「elasticsearch.拡張子」と書いてconfigディレクトリに置けば勝手に読んでくれます。
どんな風に読み込んでいるのか気になったので、コードを読んでみました。
ElasticsearchのInternalSettingsPreparerクラスを読むと、以下のようなコードが書いてあります。

                try {
                    settingsBuilder.loadFromUrl(environment.resolveConfig("elasticsearch.yml"));
                } catch (FailedToResolveConfigException e) {
                    // ignore
                } catch (NoClassDefFoundError e) {
                    // ignore, no yaml
                }
                try {
                    settingsBuilder.loadFromUrl(environment.resolveConfig("elasticsearch.json"));
                } catch (FailedToResolveConfigException e) {
                    // ignore
                }
                try {
                    settingsBuilder.loadFromUrl(environment.resolveConfig("elasticsearch.properties"));
                } catch (FailedToResolveConfigException e) {
                    // ignore
                }

「elasticsearch.json→elasticsearch.yml→elasticsearch.properties」の順序で設定ファイルを探して、読み込んでいるんですね。
同じ設定を記述した場合は、後から記載した設定で上書きされるので、設定ファイルの優先順序は以下のようになります。

  1. elasticsearch.properties
  2. elasticsearch.json
  3. elasticsearch.yml

また、yamljsonで階層構造で設定を記述した場合は、階層を「.」でつないだ設定名になります。
例えば、json形式で以下の2つのケースは同じ設定で、Elasticsearch内部では、「node.name」として扱われます。

{
  "node" :
      { "name" : "json" }
}
{
  "node.name" : "json"
}

yaml形式で設定を記述するときも、同様に階層を「.」でつないだ設定名になります。
property形式の場合は「node.name=json」のように記載するしかないですね。

設定ファイルを記述する際の参考になればと思います。ちょっとした小ネタでした。

それではまた~

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ

Impalaにファイルで投入したデータはいつから検索可能になるの?

こんにちは。kimukimu(@)です。

このエントリはSpark, SQL on Hadoop etc. Advent Calendar 2014 - Qiitaの12/14分です。

多くの人がSQLなら書けるということで、
開発者でなくても自在に検索を定義可能なSQL on Hadoopが今非常に広まりつつあります。
私はそんなSQL on Hadoopの中でImpalaを今使用しているため、Impalaについて書かせていただきますね。
f:id:acro-engineer:20141209070857j:plain

Impalaをデータの集計で使用しているのですが、
その際に「元々存在しているテーブルにデータをファイルで投入する」ことがあります。


ですが、ファイル投入後クエリを実行してみても投入した結果が表示されないことがありました。
かつ、Impalaのサイトを見てもどのタイミングでデータが検索可能になるか、は明確には見つからないんですよね・・・

そのため、「Impalaにファイルで投入したデータはいつから検索可能になるの?」が
気になったので確認してみました。

1.前提環境

今回の確認は下記の環境で確認しています。

  • CDH 5.2.0(Cloudera Managerで構築、完全分散モード)
  • CentOS 6.6

Cloudera Managerを使うとHadoopクラスタ構築が本当に楽になりますね。

2.使用するファイル

実際に投入して確認してみるファイルの内容は下記です。

いつから検索可能になるかを確認できればいい、ということと、
あとは確認をわかりやすくするため、各ファイルには必要最小限のデータのみ定義しています。
■201412141000.csv

2014-12-14 10:00:00,Record1,100,12.34,Record1 Comment

■201412141100.csv

2014-12-14 11:00:00,Record2,200,34.56,Record2 Comment

■201412141200.csv

2014-12-14 12:00:00,Record3,300,45.67,Record3 Comment

■201412141300.csv

2014-12-14 13:00:00,Record4,400,56.78,Record4 Comment

2.ファイル投入後の表示タイミング確認パターン

Impalaに対してファイルで投入したテーブルの内容を表示するための関連オペレーションとして、
下記の4つの処理があります。

  1. Impalaにテーブル(EXTERNAL TABLE)を定義する。
  2. 定義したテーブルに対してクエリを発行し、結果を表示する。
  3. ファイルを投入する。
  4. ファイルを削除する。

すると、ざっと考えて下記くらいのパターンが挙げられると思います。
ファイル追加/ファイル削除の順番入れ替えはパターンも多くなるので省きます。

  • A.テーブル定義→クエリ発行(1→2、基本)
  • B.テーブル定義→ファイル追加→クエリ発行(1→3→2)
  • C.テーブル定義→クエリ発行→ファイル追加→クエリ発行(1→2→3→2)
  • D.テーブル定義→ファイル削除→クエリ発行(1→4→2)
  • E.テーブル定義→クエリ発行→ファイル削除→クエリ発行(1→2→4→2)
  • F.テーブル定義→ファイル追加&削除→クエリ発行(1→3&4→2)
  • G.テーブル定義→クエリ発行→ファイル追加&削除→クエリ発行(1→2→3&4→2)

3.確認結果

では各パターン毎に実際に実行してみて結果がどうなるかを確認してみます。
まず下準備としてimpalaユーザの操作可能なディレクトリ上に先ほど定義したファイルを配置します。
その上でHDFS上にImpalaがアクセス可能な下記のディレクトリを作成しておきます。

/ImpalaTest/TestPattern1
/ImpalaTest/TestPattern2
/ImpalaTest/TestPattern3
/ImpalaTest/TestPattern4
/ImpalaTest/TestPattern5
/ImpalaTest/TestPattern6
/ImpalaTest/TestPattern7

結果上では通常のLinux impalaユーザのコマンドを「>」、impala-shellからの実行コマンドを「[impala:21000] >」と記述しています。
また、impala-shellからimpala-daemonへの接続といった共通コマンドや、冗長な記述は省いています。

3-A.テーブル定義→クエリ発行(1→2、基本)

> hadoop fs -copyFromLocal 20141214* /ImpalaTest/TestPattern1
[impala:21000] > CREATE EXTERNAL TABLE test_pattern_1(record_time TIMESTAMP, record_name STRING, record_value_int INT, record_value_float FLOAT, record_comment STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/ImpalaTest/TestPattern1';
[impala:21000] > select * from test_pattern_1 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
| 2014-12-14 12:00:00 | Record3     | 300              | 45.66999816894531  | Record3 Comment |
| 2014-12-14 13:00:00 | Record4     | 400              | 56.77999877929688  | Record4 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+

データを投入してからテーブルを定義し、クエリを発行するという基本パターンですので、当然のことながら全データが表示されます。

3-B.テーブル定義→ファイル追加→クエリ発行(1→3→2)

> hadoop fs -copyFromLocal 2014121410* /ImpalaTest/TestPattern2
> hadoop fs -copyFromLocal 2014121411* /ImpalaTest/TestPattern2
[impala:21000] > CREATE EXTERNAL TABLE test_pattern_2(record_time TIMESTAMP, record_name STRING, record_value_int INT, record_value_float FLOAT, record_comment STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/ImpalaTest/TestPattern2';
> hadoop fs -copyFromLocal 2014121412* /ImpalaTest/TestPattern2
> hadoop fs -copyFromLocal 2014121413* /ImpalaTest/TestPattern2
[impala:21000] > select * from test_pattern_2 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
| 2014-12-14 12:00:00 | Record3     | 300              | 45.66999816894531  | Record3 Comment |
| 2014-12-14 13:00:00 | Record4     | 400              | 56.77999877929688  | Record4 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+

テーブル定義後にファイルを追加した場合でも、クエリを発行する前に追加しておけば追加結果が反映されることがわかります。

3-C.テーブル定義→クエリ発行→ファイル追加→クエリ発行(1→2→3→2)

> hadoop fs -copyFromLocal 2014121410* /ImpalaTest/TestPattern3
> hadoop fs -copyFromLocal 2014121411* /ImpalaTest/TestPattern3
[impala:21000] > CREATE EXTERNAL TABLE test_pattern_3(record_time TIMESTAMP, record_name STRING, record_value_int INT, record_value_float FLOAT, record_comment STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/ImpalaTest/TestPattern3';
[impala:21000] > select * from test_pattern_3 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+
> hadoop fs -copyFromLocal 2014121412* /ImpalaTest/TestPattern3
> hadoop fs -copyFromLocal 2014121413* /ImpalaTest/TestPattern3
[impala:21000] > select * from test_pattern_3 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+

テーブル定義後、クエリを実行した後にファイルを追加した場合は追加結果はそのままでは反映されないようです。
そのため、クエリ初回実行時に実際に検索対象となるデータに対して何かしらのインデックス処理のようなものを施している・・?
尚、これは1日たっても結果はそのままでしたので、タイミング問題、というわけでもないようです。

3-D.テーブル定義→ファイル削除→クエリ発行(1→4→2)

> hadoop fs -copyFromLocal 20141214* /ImpalaTest/TestPattern4
[impala:21000] > CREATE EXTERNAL TABLE test_pattern_4(record_time TIMESTAMP, record_name STRING, record_value_int INT, record_value_float FLOAT, record_comment STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/ImpalaTest/TestPattern4';
> hadoop fs -rm /ImpalaTest/TestPattern4/201412141300.csv
[impala:21000] > select * from test_pattern_4 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
| 2014-12-14 12:00:00 | Record3     | 300              | 45.66999816894531  | Record3 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+

削除についても追加と同じく、テーブル定義後クエリ発行前に実施しておけば反映されるようです。

3-E.テーブル定義→クエリ発行→ファイル削除→クエリ発行(1→2→4→2)

> hadoop fs -copyFromLocal 20141214* /ImpalaTest/TestPattern5
[impala:21000] > CREATE EXTERNAL TABLE test_pattern_5(record_time TIMESTAMP, record_name STRING, record_value_int INT, record_value_float FLOAT, record_comment STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/ImpalaTest/TestPattern5';
[impala:21000] > select * from test_pattern_5 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
| 2014-12-14 12:00:00 | Record3     | 300              | 45.66999816894531  | Record3 Comment |
| 2014-12-14 13:00:00 | Record4     | 400              | 56.77999877929688  | Record4 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+
> hadoop fs -rm /ImpalaTest/TestPattern5/201412141200.csv
> hadoop fs -rm /ImpalaTest/TestPattern5/201412141300.csv
[impala:21000] > select * from test_pattern_5 ORDER BY record_time;
WARNINGS: Failed to open HDFS file hdfs://cluster1:8020/ImpalaTest/TestPattern5/201412141200.csv
Error(2): No such file or directory
Backend 1:Failed to open HDFS file hdfs://cluster1:8020/ImpalaTest/TestPattern5/201412141200.csv
Error(2): No such file or directory

クエリを実行した後にファイルを削除した場合、その後再度クエリを実行するとファイルが存在しない旨のエラーとなります。
結果も表示されませんでした。
やはりクエリの初回実行時にファイル単位のインデックス作成に近いものを行っていて、
以後クエリを実行した場合はそのインデックスにそって検索を行うようです。

・・と、とりあえずここまでで大体動きの予測はつきますが、念のため追加と削除を両方行うパターンについても確認しておきます。

3-F.テーブル定義→ファイル追加&削除→クエリ発行(1→3&4→2)

> hadoop fs -copyFromLocal 2014121410* /ImpalaTest/TestPattern6
> hadoop fs -copyFromLocal 2014121411* /ImpalaTest/TestPattern6
> hadoop fs -copyFromLocal 2014121412* /ImpalaTest/TestPattern6
[impala:21000] > CREATE EXTERNAL TABLE test_pattern_6(record_time TIMESTAMP, record_name STRING, record_value_int INT, record_value_float FLOAT, record_comment STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/ImpalaTest/TestPattern6';
> hadoop fs -copyFromLocal 2014121413* /ImpalaTest/TestPattern6
> hadoop fs -rm /ImpalaTest/TestPattern6/201412141200.csv
[impala:21000] > select * from test_pattern_6 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
| 2014-12-14 13:00:00 | Record4     | 400              | 56.77999877929688  | Record4 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+

予想通り、ではありますが、クエリを初回実行前にファイルの追加削除を両方行っても問題なく検索可能です。

3-G.テーブル定義→クエリ発行→ファイル追加&削除→クエリ発行(1→2→3&4→2)

> hadoop fs -copyFromLocal 2014121410* /ImpalaTest/TestPattern7
> hadoop fs -copyFromLocal 2014121411* /ImpalaTest/TestPattern7
> hadoop fs -copyFromLocal 2014121412* /ImpalaTest/TestPattern7
[impala:21000] > CREATE EXTERNAL TABLE test_pattern_7(record_time TIMESTAMP, record_name STRING, record_value_int INT, record_value_float FLOAT, record_comment STRING) ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' LOCATION '/ImpalaTest/TestPattern7';
[impala:21000] > select * from test_pattern_7 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
| 2014-12-14 12:00:00 | Record3     | 300              | 45.66999816894531  | Record3 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+
> hadoop fs -copyFromLocal 2014121413* /ImpalaTest/TestPattern7
> hadoop fs -rm /ImpalaTest/TestPattern7/201412141200.csv
[impala:21000] > select * from test_pattern_7 ORDER BY record_time;
WARNINGS: Failed to open HDFS file hdfs://cluster1:8020/ImpalaTest/TestPattern7/201412141200.csv
Error(2): No such file or directory
Backend 1:Failed to open HDFS file hdfs://cluster1:8020/ImpalaTest/TestPattern7/201412141200.csv
Error(2): No such file or directory

予想通り、クエリを1回実行後にファイルの追加削除を行った場合、対応できませんでした。

4.テーブル定義後にファイルの追加削除を行った場合結果に反映させるには?

では、ファイルの追加削除を反映させるためにはどうすればいいのでしょうか。
Impalaクエリのマニュアルを見てみると「REFRESH」というコマンドがありました。
REFRESHコマンドを実行することで、追加削除の結果が反映され、現状のファイルに対して検索を行うことが可能でした。

[impala:21000] > REFRESH test_pattern_7;
[impala:21000] > select * from test_pattern_7 ORDER BY record_time;
+---------------------+-------------+------------------+--------------------+-----------------+
| record_time         | record_name | record_value_int | record_value_float | record_comment  |
+---------------------+-------------+------------------+--------------------+-----------------+
| 2014-12-14 10:00:00 | Record1     | 100              | 12.34000015258789  | Record1 Comment |
| 2014-12-14 11:00:00 | Record2     | 200              | 34.56000137329102  | Record2 Comment |
| 2014-12-14 13:00:00 | Record4     | 400              | 56.77999877929688  | Record4 Comment |
+---------------------+-------------+------------------+--------------------+-----------------+

5.確認結果まとめ

これまでの結果をまとめると下記のようになります。

  1. ImpalaはEXTERNALテーブル定義後、クエリを初回実行した際にインデックスのようなものを作成する。
  2. インデックス(?)を作成する前に行ったファイル追加削除はクエリ実行結果に反映される。
  3. インデックス(?)を作成した後に行ったファイル追加削除はクエリ実行時に反映されない。(削除の場合はエラーになる)
  4. REFRESHコマンドを実行することで現状の最新の状況にインデックス(?)が更新される。

テーブル定義後、データを投入しながらインクリメンタルにクエリを発行する場合、
データ投入時の事後処理かクエリ発行時の事前処理でREFRESHコマンドを実行すればOK
となりますね。
これで追加しながら検索、もデータ未反映を気にすることなく実行可能ですね。

小ネタでしたが、以上です。

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ

Pepperについて調べてみました&会いに行ってみました

こんにちは、ツカノ(@)です。

皆さん、ロボットは好きですか?

子どもの頃、ロボットアニメに興奮した方も多いと思います。
私も好きなロボットアニメがありました。

昔は夢の話だったロボットも、科学が進歩し、段々と人型ロボットが実現されてきました。
AIBOが走ったり、東大発のロボット関連ベンチャーGoogleに買収されたりと、研究的な部分で進歩する一方で、ソフトバンクから家庭向けにPepperというロボットが発表されました。
f:id:acro-engineer:20140916003007p:plain
今回は、ソフトバンクから来春発売されるPepperの話です。

初めての方には基礎知識の紹介、知っている方にはおさらい、ということで、まずはPepper関連の情報をまとめてみました。

Pepperとは?

Pepperソフトバンクが2015年2月に発売する、子どもくらいの身長のロボットです。
孫さんが自ら発表するくらい期待しているようで、感情を理解して自ら動くロボットとのこと。
価格は19万8000円。これなら、一般家庭でも購入できる価格ですね(少々高価ですが)。ロボットを家庭に届けたい、という孫さんの意気込みを感じます。

発表会の様子はこのサイトで見ることができます。


ソフトバンクにはPepperについて書かれたページがあります。Pepperの紹介や、動画も公開されていて面白いです。




Pepperのコンセプト

これらページの情報をまとめると、以下のような感じです。
コンセプトは「人によりそうロボット」。世界初の感情認識パーソナルロボットだそうです。

道具として役立ってきたこれまでの機械とは違い、人間とのふれあいの中で自律的に反応しながら、あなたを楽しませてくれます。

あなたが悲しんでいるときに励ましてくれたり、あなたが嬉しいときに一緒に喜んでくれたり、そんな存在になれることを目指しています。

Pepperは共に暮らす家族とのやり取りを受けて少しずつ成長していきます。

お掃除ロボットやお茶くみロボットと違い、道具として役立つ事が目的ではないようです。
人間とコミュニケーションを取って、楽しませてくれるのが目的のようです。
学習するそうなので、成長していく過程を見るのも楽しそうですね。

PepperSDK

技術者として期待するのは以下の記述。

開発環境(SDK)が公開される予定ですので、思いもよらない機能が今後アプリストアに追加されていくことでしょう。

SDKが公開され、Pepperで動くアプリを開発できるとの事。
また、アプリストアもできるそうで、アプリをインストールすることでPepperに様々な機能を持たせる事ができるようです。
個体毎に異なった振る舞いをするPepperに育っていくと面白そうですね。


では、機能面のうち、一般受けしそうな点を見てみましょう。

  • クラウド連携で豊富な知識を披露
    • インターネットにアクセスして最新のニュースや天気などを教えてくれるそうです。やはりYahoo! Newsと連携するのでしょうか?
  • あんしんのセーフティー機能を多数搭載
    • 衝突防止機能やオートバランス機能など、家庭で使う事も考えると必須機能ですね。


エンジニア的には、他にもこんなことが気になります。

  • 連続稼働時間が12時間以上
    • 朝から晩まで動かして、夜に充電しておけば良いですね。スマホと同じく、毎晩充電必要ですが。
  • 体中に大量のセンサーを搭載
    • タッチセンサー、ジヤイロセンサー、レーザーセンサー等、25個くらいありますね。
  • 頭部にタッチセンサーが3個も付いている
    • これはどういうことでしょうか? 頭を撫でたりしたときに、細かく識別できるのでしょうか?

Pepperに会いたい!

こんなPepperに会ってみたいですよね。
そう思った人は、Pepperがいるソフトバンクショップに行ってみましょう。
このページPepperがいるソフトバンクショップを調べることができます。

私が最初に行ったとき、Pepperは充電中で眠っていました。

えっ、連続稼働12時間じゃないの? なんで? 店員さんが、前日晩に充電を忘れたのでしょうか?
充電中のPepperは、しょぼんとしていて、いかにも悲しい感じです。

こんなんで断念したくないので、別のソフトバンクショップに会いに行ってみました。

今度はPepperが動いています!

Pepper!」と声をかけると振り向いて、話しかけてきます。


ロボットと話すのが慣れないせいか、私の受け答えが素人演技みたいな感じになってしまい、ぎこちない会話です。
自然に会話できるよう慣れる必要がありますね。

このPepperソフトバンクショップ仕様になっているせいか、「一生のお願い」と言いながら、私に新しい携帯電話を買うよう要求してきました

携帯電話を買いに来た訳でなく、Pepperとコミュニケーションを取りに来たので、「私から質問していい?」と何度か言ってみましたが、無視されました^^;

製品版ではそんなことがないはず、と期待しています!

Pepperに会いに行ってみて、本当に動いているし、人間とある程度会話もできるし、来年にはこのロボットを自分でいじれると思うと、非常に楽しみですね。

Pepperの開発元

あとから気付いたのですが、ソフトバンクのページには

お客さまがPepperに向けて発話した内容を、弊社及び弊社グループ企業であるAldebaran Robotics SASのサーバーに一定期間保存致します。

と書いてあります。
これがクラウド連携か。1体のPepperに日本語を覚えさせたら、他のPepperにうつったりするのでしょうか。変な事は教えない方が良いのかな。。。私が話しかけたときは、まだ残念な子でしたが、今後の成長に期待。

それと、「Aldebaran Robotics SAS」って、単語が気になる。。。そういえば、製品発表会の動画ではAldebaran社の人が何かしゃべっていましたね。

調べてみると、Aldebaran Roboticsはフランスにあるロボット開発を行っている会社で、これまでもNAOという小型ロボットを実用化しています。ソフトバンクがこの会社を買収して開発したのが、Pepperなんですね。

NAOも人型ロボットで、ひとりで立ったり座ったりもできます。Pepper情報はまだまだ少ないので、NAOを調べてみると面白いかもしれません。Pepperで利用するOSが、元々NAOで開発されていたものだったり、Pepperにつながる話を知ることができます。

Pepperについて、もっと知るには

「このくらい情報では、飽き足らない! もっとPepperの事が知りたい!」と思う方もいるでしょう。
実は、今週末にPepper Tech Festivalというイベントが開催され、様々なことが発表されるそうです。
気になる方は、今週末に開催されるPepper Tech Festivalで発表される情報に期待しましょう! 私ももちろん行きます!


Acroquest Technologyでは、キャリア採用を行っています。

  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ

MQTT Meetup Tokyo 2014.08に参加してきました!

id:KenichiroMurata(@ )です。

皆さんはMQTTに興味はありますか?私は昨年末くらいからMQTTに興味を持ち、そこからあれこれ調べています。

また社内でも、Stormのエコシステムとして開発しているAcroMUASHI Streamの開発チームが、MQTTと連係した分散ストリーム処理を実現しており、私の周辺では盛り上がっています。

そんな中、先日 MQTT Meetup Tokyo 2014.08が開催され、幸運にも参加することができましたので、今回はその参加レポートをお届けします。

イベントの概要はこちらをご覧下さい。イベントは非常に内容の濃いものであり、面白かったです。
少しでも何かお手伝いできることがあればとイベント当日のtweettogetterにまとめましたので、当日の雰囲気や反応をご覧になりたい方はMQTT Meetup Tokyo 2014.08 まとめも合わせてご覧下さい。

1. MQTTの機能概要 - ツキノワ 若山さん(@r_rudi)

MQTTについてのまとめ — そこはかとなく書くよん。を書かれた方による発表。MQTTの概要についての説明であり、特にWill、Retain、CleanSessionについての説明は理解を復習する意味でも非常に分かりやすかったです。Retainの活用方法の例として、Subscribeしてくるデバイスに最新の設定情報をRetainを使って渡すという話は、なるほどでした。また、Microservicesについても少し触れられていました。

2. IBM MessageSight - IBM 鈴木徹さん

IBM MessageSightはMQTTのアプライアンスサーバーで、なんと100万デバイスを常時接続可能、毎秒1500万メッセージを処理できるとのこと。100万のデバイスを60秒以内で全て接続できるとか、毎秒1万メッセージを平均85マイクロ秒でさばけるとか、サーバの冗長化も当然可能という凄いものでした。お値段は怖くて聞けないレベルです。

プレゼンをされた鈴木さんは、普段はMQTTがどれだけ良いかを説明するのにほとんどの時間を使うのに対して、今日は参加者が皆MQTTのことは良いモノと知っているので、その説明がいらないのが最高!とあれこれネタを仕込んだマシンガントークを展開し、非常に面白かったです。

話の焦点はMQTTうんぬんではなく、IoTをどのようにしてビジネスにつなげて利益を生み出すのか?という内容になり、車内センサーで運転手の状態を常時接続で情報収集し、その情報を保険会社が活用するといった事例紹介もありました。

あとは、IBMさんでは、MQTT/IoTで収集したデータをどうやって活用するのか、既存の様々なシステムと結合できるように仕組み化している点についても説明があり、ここでもMicroservicesを連想させる「3年後に取り替え可能な部品によるシステムを作る。疎結合に」なんて話が聞けました。

3. IoT/M2M Hot Topics in IETF - レピダム 林さん(@lef)

CoAPとその周辺に関する話題について。CoAPについては私は初めて知りました。HTTP/RESTと親和性のあるIoT/M2M用の軽量プロトコルであり、UDPとのこと。MQTTがTCPで常時接続であるのに対して、UDPを利用するMQTT-SNと対応付く関係にあるものだと理解しました。

CoAPそのものというよりもIETFの仕様策定の裏側(仕様に関するユースケースを話してしまうと、ビジネス上問題なので、ユースケースの話になると大人の事情で議論が進まなくなる)みたいな話がきけて面白かったです。

4. 時雨堂 MQTT ブローカー (AKANE) - @voluntas さん

本イベントの主催者であり、イベント前日にMQTT as a Seriviceであるsangoを発表した時雨堂の@voluntasさんによるsangoの中で使われている MQTT ブローカー (AKANE) の開発苦労談。

仕様としてはシンプルなMQTTですが、MQTT Brokerを本気で開発しようとすると、どのような問題があって、苦労するのかという話で非常に面白かったです。特に、仕様には含まれていないが、現実的にシステムとして運用できるようにするために実装した機能についてはとても参考になりました。

仕事上、数万、数十万の監視対象ノードを集中監視制御するシステムを開発してきたので、リトライ、ノード別の状態遷移制御、時系列制御、優先キュー、一斉接続などなど、それに類する話題が基本なのでイメージしやすかったし、共感できました。MQTTでは、さばくクライアント数が多いのは当然として、トピックのSubscribeの指定方法によっては1クライアントに配信するメッセージが爆発的に増えるし、QoSダウングレードはさらに複雑になるので、その実装はたしかにつらそうです。なぜに世のMQTT Brokerの実装が(私が観測する範囲では)どれも途中に見えるのは、このような背景があるからなんですね。

5. MQTT+RaspberryPi+Arduino+センサーで制御とGUIを実装した話 - 小松電機産業 廣江さん (@hiroe_orz17)

RaspberryPi+Arduino、オムロンPLC、Intel Galileo でMQTTしてみた話 - ごろねこ日記を書かれた方による発表。具体的にアプリケーションを作る上で、どのように考えて、何を試して、結果どう実現したかが具体的に分かる内容でした。MQTTのペイロード部をどのようにするのか、3G環境下で通信量を削減/効率化するために配列やバイト列を使った表現やMessagePackの利用など、試行錯誤も含めての説明だったので、イメージが沸きました。

おまけ sangoを試してみる

githubアカウントで簡単にsangoを使い始められるということで、イベント終了後に早速アカウントを作成し、試してみました。mosquittoを使ってCLIで試すのは直ぐにできたので、以前から気になっていたMQTTInspectorというiOSアプリ(有料)を使って試してみました。

アプリの使い方そのものに慣れるのに手探り状態でしたが、以下のように簡単に動作させることができました。ビューによっては通信状態が見えるのがよいですね。

メッセージを送受信している例


通信ログ

最後に

MQTT Meetup Tokyo 2014.08 はMQTTの概要から始まって、仕様の話、ビジネス活用の話、Broker実装の裏話、クライアントアプリ開発の話と幅広い内容で、しかもそれぞれが濃い話でした。このようなイベントを企画してくださり、どうもありがとうございました!

Acroquest Technologyでは、キャリア採用を行っています。

  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ

Storm-0.9.2の新機能/修正点を紹介します

こんにちは。kimukimuです。
f:id:acro-engineer:20140709095247p:plain

Stormインストーラ更新のお知らせ

まず最初にお知らせを。
読者の皆さんにも愛用頂いている(?)Stormのインストーラですが、
Storm-0.9.2対応バージョンをアップしました。

下記のページからダウンロードできますので、
Stormを簡単にインストールしたい方、Stormを試してみたいと考えている方は是非使ってみてください。

acromusashi/storm-installer · GitHub

インストーラのアナウンスと併せて、Storm-0.9.2の新機能/修正点を紹介しますね。

Storm-0.9.2の主な新機能/修正点

Storm-0.9.2の新機能/修正点として、主なものは下記の4点があります。

  1. Storm UIにTopology可視化ツールの追加
  2. Storm-Kafkaの更新/媒体への取り込み
  3. Storm-Starterの媒体への取り込み
  4. Storm-UIにREST APIが追加

Storm UIにTopology可視化ツールの追加

Storm-0.9.2の目玉機能が、Topology可視化ツールです。
Spout/Bolt間でどれだけのメッセージが流れているかの概要を即見ることができます。
加えて、Topology可視化ツール自体はStorm-UIに内蔵され、即使うことができます。

使い方は、Storm-UIのTopology Summaryのページから
「Topology Visualization」のボタンを押すだけです。
f:id:acro-engineer:20140713002118j:plain

すると、下記のようにSpout/Bolt間を流れるメッセージの数を表示するグラフが表示されます。
f:id:acro-engineer:20140713002219j:plain
かつ、このグラフはStormが複数のStreamを含む場合、
どのStreamをグラフ中に表示するか絞り込みも可能です。
f:id:acro-engineer:20140713002343j:plain
ただ、Stormのメッセージ失敗検知機構を使用しておらず、Streamの分割も行っていないTopologyの場合、
0件のStreamが表示されるだけなので、Stream絞り込みにはあまり意味はないのですが^^;
f:id:acro-engineer:20140713002530j:plain

尚、グラフに表示されるメッセージ数は「過去10分間」で固定のようです。

Storm-Kafkaの更新/媒体への取り込み

Stormとよくペアで使用されるOSSとしてApache Kafkaがあります。
Kafkaは一言で言うと「PubSub型のメッセージバス」で、Stormが処理するためのデータを保持しておき、
StormがKafkaから取得して処理する、という関係になっています。

StormにはStorm-KafkaというKafkaと結合するためのコンポーネントが存在したのですが、
Kafkaのバージョンアップに追従しておらず、最新版(0.8系)のKafkaには使用できない状態になっていました。
Storm-0.9.2では最新版に合わせて更新され、改めて使用できるようになりました。

また、Storm-KafkaはStormのダウンロード媒体にも含まれるようになりました。
同じApacheプロジェクトだから、というのもあるとは思いますが、StormとKafkaの連携というのは有力な選択肢になりそうですね。

Storm-Starterの媒体への取り込み

Storm-Kafkaと併せて、Storm-StarterもStormのダウンロード媒体に取り込まれました。

これまではStormクラスタを構築後、自分で何か簡単なTopologyを作成するか、
または別個Storm-Starterからソースをダウンロード後、最新版のStormに合わせて更新して使用する必要がありました。
#実はStorm-StarterにはStormの最新版を適用するとコンパイルエラーが発生する時期がありました^^;

ですが、Storm-0.9.2からはStormの媒体に常に最新のStormに合わせたStorm-Starterが用意されるようになりました。
よりStormを簡単に試すことが出来るようになったと言えると思います。

Storm-UIにREST APIが追加

Topology可視化ツールとも関連するのですが、
Storm-UIに下記のことが可能なREST APIが追加されました。

  • Stormクラスタの情報取得
  • StormSupervisorの情報取得
  • StormTopologyの情報取得
  • Topology中の各コンポーネントの情報取得
  • Topologyの停止/再開/リバランス/終了

それまでは画面から操作するか、Storm-Nimbusに対してThriftでメッセージを飛ばすしかなかったため、
REST APIの追加によってStormクラスタの管理を別プロセスから行う・・ということが行いやすくなりました。

その他のStorm-0.9.2の新機能/修正点

これまでで主要な更新点を説明してきましたが、
その他にも下記のようにStorm-0.9.2には多くの修正点があります。
Storm-0.9.0系に更新する際に大きく構成が変更になっているため、
そこから発生した問題を一気に修正しているようです。

  • CPU数に応じたスケーラビリティ向上
  • Nettyによるメッセージ転送の改善
  • 冗長な性能メトリクス送信の除去
  • Storm-Kafkaの信頼性向上
  • ZooKeeperに対するHeartBeat負荷の低減
  • 言語間のやり取りを行う際のシリアライザをプラガブルに修正

Storm-0.9.2になって結局何が嬉しいか?

Storm-0.9.2はマイナーバージョンアップという位置づけのためか、
Stormのコア部分に機能が追加されるということはありませんでした。

ですが、Topology可視化ツールをはじめとした「使いやすくする」修正が行われています。

Topology可視化ツール自体が表示している情報自体はStorm-UIで元々表示していた情報です。
ですが、これまではStormに慣れた人間でないと正確にその情報を読み解けない、というのが今まででした。
可視化ツールの追加によってそれが誰であっても概要を読み取れるようになったのは大きいと思います。

そのため、Storm-0.9.2は「Stormをより使いやすくするバージョンアップ」と位置づけられると思います。
これを機に、これまで使ったことが無い方も是非Stormを使ってみてください。

それでは。

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ

Apache版Storm初回リリースの新機能の使い方

こんにちは。kimukimuです。
f:id:acro-engineer:20140709095247p:plain

夏なのか梅雨なのか微妙な気候になっているような感覚を覚える今日この頃です。
いきなり暑くなってきているので、バテないよう気をつける必要がありますね。

さて、前回Apache版Stormの新機能の概要について紹介しましたが、
今回は実際に新機能がどういう風に使えるのか、について確認してみようと思います。

尚、Storm-0.9.2-incubatingもリリースされていますが、それは次回に回すとして、
今回はStorm-0.9.1-incubatingの新機能です。

・・・といっても、ビルドツールの変更などは確認してもあまり嬉しいことはないため、
下記の2つの機能に絞って確認を行ってみることにします。

  1. Storm-UIの各項目にツールチップで解説を表示
  2. NimbusにTopologyをSubmitする際、設定に対するバリデーションが追記

1.Storm-UIの各項目にツールチップで解説を表示

Storm-UIで表示される各種項目に対してマウスオーバーした際にツールチップで解説が表示されるようになった」という新機能です。

Storm-UIを使ってさえいれば常時有効となります。
これは実際にStorm-UIで見てみた方が早いため、実際どんな内容が表示されるかを見てみましょう。

まずはTop画面のバージョンから。こういった形で項目にマウスオーバーすることで項目の説明が表示されます。
f:id:acro-engineer:20140519072554j:plain
同じように、Topology Summaryの画面でも下記のような項目の説明が表示されます。
Capasityをはじめとした「生データから算出される項目」についてはどのように値が算出されているかも記述されています。
f:id:acro-engineer:20140519072902j:plain
f:id:acro-engineer:20140519072906j:plain
Executor SummaryにおいてもHostNameの算出の方法について記述されるなど、かゆい所にも手が届きます。
f:id:acro-engineer:20140519072909j:plain

Storm-UIは基本的にStormがZooKeeper上に保持している性能情報を
Nimbusから取得して表にしているだけのため、パっと見はわかりにくい画面なのですが、
今回各項目に解説が表示されるようになったため、使いやすくなったとは思います。

2.NimbusにTopologyをSubmitする際、設定に対するバリデーションが追記

では、次は「TopologyをSubmitする際、設定に対する定型的なバリデーションを行えるようになった」についてです。

これは内容としては、TopologySubmit時に型として不正な値が設定されている設定値を検出してバリデーションを行うものです。
バリデーション対象となるのはStorm自体が動作するために必要な設定値です。
Topology固有の設定値についてはこれまでと同じくTopologyValidatorを自前で作成し、チェックを行う必要があります。

では、実際にどういう場面で使われるのかを確認してみましょう。

今回ベースとするのはincubator-storm/examples/storm-starter at master · apache/incubator-storm · GitHubです。
この中で一番単純なExclamationTopologyを例にとります。
ExclamationTopologyをStormクラスタにSubmitする際のConfigオブジェクトに
ZooKeeperのポート設定を文字列("Test")として詰めて起動してみます。
当然ながら、ポート設定のため本来数値で設定されている必要があります。

  • ExclamationTopology
  public static void main(String[] args) throws Exception {
    TopologyBuilder builder = new TopologyBuilder();

    builder.setSpout("word", new TestWordSpout(), 10);
    builder.setBolt("exclaim1", new ExclamationBolt(), 3).shuffleGrouping("word");
    builder.setBolt("exclaim2", new ExclamationBolt(), 2).shuffleGrouping("exclaim1");

    Config conf = new Config();
    conf.put(Config.STORM_ZOOKEEPER_PORT, "Test"); // 本来数値でないと動作しない設定に文字列を設定

    if (args != null && args.length > 0) {
      conf.setNumWorkers(3);

      StormSubmitter.submitTopology(args[0], conf, builder.createTopology());
    }
    else {

      LocalCluster cluster = new LocalCluster();
      cluster.submitTopology("test", conf, builder.createTopology());
      Utils.sleep(10000);
      cluster.killTopology("test");
      cluster.shutdown();
    }
  }

この状態でStormクラスタにSubmitを行うと・・?

# bin/storm jar storm-starter-0.9.1-incubating-jar-with-dependencies.jar storm.starter.ExclamationTopology ExclamationTopology-3
(省略)
354  [main] INFO  backtype.storm.StormSubmitter - Jar not uploaded to master yet. Submitting jar...
359  [main] INFO  backtype.storm.StormSubmitter - Uploading topology jar storm-starter-0.9.1-incubating-jar-with-dependencies.jar to assigned location: /opt/storm/nimbus/inbox/stormjar-06306ca5-a1d6-4991-a47a-98b87126186b.jar
409  [main] INFO  backtype.storm.StormSubmitter - Successfully uploaded topology jar to assigned location: /opt/storm/nimbus/inbox/stormjar-06306ca5-a1d6-4991-a47a-98b87126186b.jar
409  [main] INFO  backtype.storm.StormSubmitter - Submitting topology ExclamationTopology-3 in distributed mode with conf {"topology.workers":3,"storm.zookeeper.port":"Test"}
415  [main] WARN  backtype.storm.StormSubmitter - Topology submission exception: field storm.zookeeper.port 'Test' must be a 'java.lang.Number'
Exception in thread "main" InvalidTopologyException(msg:field storm.zookeeper.port 'Test' must be a 'java.lang.Number')
        at backtype.storm.generated.Nimbus$submitTopology_result.read(Nimbus.java:2466)
        at org.apache.thrift7.TServiceClient.receiveBase(TServiceClient.java:78)
        at backtype.storm.generated.Nimbus$Client.recv_submitTopology(Nimbus.java:162)
        at backtype.storm.generated.Nimbus$Client.submitTopology(Nimbus.java:146)
        at backtype.storm.StormSubmitter.submitTopology(StormSubmitter.java:98)
        at backtype.storm.StormSubmitter.submitTopology(StormSubmitter.java:58)
        at storm.starter.ExclamationTopology.main(ExclamationTopology.java:76)

このように、「storm.zookeeper.port」が"Test"という設定になっており、NumberではないからSubmit出来ない、
クラスタに投入する前にはじくことができました。

これは今までだと設定が誤っていることに気付かずにStormクラスタにSubmitしてしまい、
クラスタで起動する際にWorkerプロセスが起動して死ぬを繰り返す・・・という厄介な状態に陥っていました。

特に、実際に使っている方だと
JSONYamlといったファイルに設定値を外だしして読み込ませる方も多いと思いますが、
設定ファイルに記述していた内容が誤っていた場合に予め検出してくれるのでかなり便利に使えると思います。

3.Apache版Stormの初回リリース機能についてのまとめ

  1. Storm-UIに解説が加わり、各画面の項目の意味がわかりやすくなりました。
  2. TopologySubmit時に明らかに誤った設定は事前にはじけるようになりました。

特に新しい機能が追加された・・・というわけではないのですが、使いやすさが確実に増すバージョンアップだったと思います。

尚、別の投稿で紹介しますが、Storm-0.9.2-incubatingでリリースした内容は
使いやすくなる、ではなく実際に使える機能が追加されたリリースになっています。
Apacheに移り、今後も期待していけるStormになった、と言えるでしょう。

それでは。

Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ

Spring BootによるWebアプリお手軽構築

こんにちは、阪本です。


Springのメジャーバージョンアップに伴い、Spring Bootも晴れて1.0となりました。
Spring Bootは、Spring周りの依存関係をシンプルに解決してくれるフレームワークですが、今流行りの(流行る予定の?)Dropwizardを意識した作りになっています。

どれだけシンプルにできるのか、見てみようと思います。

超シンプルなWebアプリの作成

では早速、Webアプリを作ってみましょう。
手始めに、サーバにアクセスすると固定文字列を返す(いわゆるHello World的な)アプリを作ってみます。


まず、下ごしらえとして、Mavenのpom.xmlを作成します。

<project xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>springboot</groupId>
  <artifactId>sample</artifactId>
  <packaging>jar</packaging>
  <version>1.0.0</version>
  <name>SpringBootSample</name>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.0.2.RELEASE</version>
  </parent>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
  </dependencies>

  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
</project>

なんと、dependencyは「spring-boot-starter-web」を指定するのみ!
ちなみに、packagingが「jar」になっていることに注意。

・・・そう、単体のアプリケーションで動作するんです。
(ちなみに、warファイルを作成することも可能。)


次は、コントローラを用意します。特に何の変哲もない、普通のコントローラですね。

package springboot.sample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class SampleController {
    @RequestMapping("/home")
    @ResponseBody
    public String home() {
        return "Hello Spring Boot!!";
    }

}


最後に(もう最後!)メインクラスを用意します。

package springboot.sample;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;

@ComponentScan
@EnableAutoConfiguration
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

}


あとは、maven packageして、jarを実行するだけ。

java -jar sample-1.0.0.jar 

jarの中に必要なライブラリが含まれているため、クラスパスの指定も不要!
このあたり、Dropwizardライクな感じですね。


コンソールにはこんな出力があり、約2秒で起動しました。
組み込みTomcatが起動しています。(ちなみにJettyにも変更可能です。)

  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::        (v1.0.2.RELEASE)

2014-06-01 10:55:28.993  INFO 7740 --- [           main] springboot.sample.Application            : Starting Application on ...
2014-06-01 10:55:29.026  INFO 7740 --- [           main] ationConfigEmbeddedWebApplicationContext : Refreshing org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext@16022d9d: startup date [Tue Apr 25 01:55:29 JST 2014]; root of context hierarchy
2014-06-01 10:55:29.824  INFO 7740 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 8080
2014-06-01 10:55:30.016  INFO 7740 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-06-01 10:55:30.016  INFO 7740 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/7.0.52
2014-06-01 10:55:30.109  INFO 7740 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-06-01 10:55:30.110  INFO 7740 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1087 ms
2014-06-01 10:55:30.490  INFO 7740 --- [ost-startStop-1] o.s.b.c.e.ServletRegistrationBean        : Mapping servlet: 'dispatcherServlet' to [/]
2014-06-01 10:55:30.492  INFO 7740 --- [ost-startStop-1] o.s.b.c.embedded.FilterRegistrationBean  : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2014-06-01 10:55:30.760  INFO 7740 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-06-01 10:55:30.875  INFO 7740 --- [           main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/],methods=[],params=[],headers=[],consumes=[],produces=[],custom=[]}" onto public java.lang.String springboot.sample.controller.SampleController.home()
2014-06-01 10:55:30.888  INFO 7740 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-06-01 10:55:30.889  INFO 7740 --- [           main] o.s.w.s.handler.SimpleUrlHandlerMapping  : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2014-06-01 10:55:30.981  INFO 7740 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Registering beans for JMX exposure on startup
2014-06-01 10:55:30.999  INFO 7740 --- [           main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080/http
2014-06-01 10:55:31.001  INFO 7740 --- [           main] springboot.sample.Application            : Started Application in 2.326 seconds (JVM running for 2.7)

そして、http://localhost:8080/home にアクセスすると、こんな感じに、文字が表示されました。

f:id:acro-engineer:20140424005318p:plain

web.xmlいらず、applicationContext.xmlいらずでWebアプリが立ち上がるなんて、超シンプルですね!

Thymeleafを用いた画面作成

先ほどは、URLにアクセスすると単に文字列を返すだけのものでした。
今度は、Thymeleafを用いて画面を作成します。

まず、pom.xmlにThymeleafを追加します。

<dependency>
  <groupId>org.thymeleaf</groupId>
  <artifactId>thymeleaf-spring4</artifactId>
</dependency>

次に、ThymeleafのHTMLテンプレートファイルを作成します。
HTMLテンプレートファイルはsrc/main/resources/templatesディレクトリの下に配置します。

hello.html

<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org">
<body>
  <h1>
    Hello Spring <span style="color: red">Boot!!</span>
  </h1>
</body>
</html>

最後に、上で作ったhello.htmlを表示するよう、Controllerを書き換えます。

package springboot.sample.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
public class SampleController {
    @RequestMapping("/home")
    public String home() {
        return "hello";
    }

}

先ほどと同じく http://localhost:8080/home にアクセスすると、hello.htmlの内容が表示されました。

f:id:acro-engineer:20140424005711p:plain

監視&デバッグ

デバッグ時に、Springコンテキストに何が登録されているか、分かると便利ですよね?
Spring Bootでは、pom.xmlに以下を追加するだけで、Web画面にコンテキストの内容を表示できます。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-actuator</artifactId>
</dependency>

起動した後、http://localhost:8080/beans にアクセスすると、以下のようなJSONデータが表示されます。

[
  {
    "beans": [
      {
        "bean": "application", 
        "dependencies": [], 
        "resource": "null", 
        "scope": "singleton", 
        "type": "springboot.sample.Application"
      }, 
      {
        "bean": "sampleController", 
・・・

実際には、改行されずに出力されるので、整形する必要はあります。

コンテキスト以外にも、以下のような様々な情報をWebから取得できるようになります。

  1. 環境変数http://localhost:8080/env
  2. Controllerのマッピング状態(http://localhost:8080/mapping
  3. HTTPリクエストトレース(http://localhost:8080/trace
  4. アクセスカウンタ/メトリクス(http://localhost:8080/metrics
  5. スレッドダンプ(http://localhost:8080/dump

ここもDropwizard的ですね。

WebアプリにSSH接続

なんと!起動したWebアプリにSSHで接続してコマンドを実行することができます!!

pom.xmlに以下を追加して、ビルド&起動。

<dependency>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-remote-shell</artifactId>
</dependency>

起動途中に、コンソールに以下のような内容が出力されます。これ(以下では662dc881-c2e3-4ad6-802e-73a36e4fc7e3)がデフォルトのログインパスワード。
(デフォルトのログインパスワードは、起動の度に変わります。)

2014-06-01 11:21:34.180  INFO 4464 --- [           main] roperties$SimpleAuthenticationProperties : 

Using default password for shell access: 662dc881-c2e3-4ad6-802e-73a36e4fc7e3

デフォルトのユーザ名はuser、SSH接続ポートは2000のため、この設定で接続してみると・・・

f:id:acro-engineer:20140424005923p:plain

ログインできました!

デフォルトでは、metrics、beans、autoconfig、endpointコマンドが使用できます。
もちろん、JavaやGroovyで自作のコマンドを定義することもできます。

例えば、src/main/resources/commandsディレクトリに、以下の内容でhello.groovyファイルを作成しておけば、
helloコマンドが実行できるようになります。

package commands

import org.crsh.cli.Usage
import org.crsh.cli.Command

class hello {

    @Usage("Say Hello")
    @Command
    def main(InvocationContext context) {
        return "Hello"
    }

}

f:id:acro-engineer:20140424005934p:plain

Webアプリのコントロールを行えるようなコマンドを、簡単に提供できそうですね。
ちなみに、このSSHの機能はCRaSHを用いて実現されています。

おわりに

ここで紹介した内容は、設定ファイルはMavenのみで、Springの設定ファイルを何一つ作成していません。

  • Springのライブラリ依存や設定ファイルに悩まされず手軽にWebアプリを構築したい!
  • Webアプリの管理もRESTやCLIでできるようにしたい!
  • Dropwizardのような「ポータブルなWebアプリケーション」を作成したい!

という要望に、Spring Bootは応えてくれそうですね。

では。


Acroquest Technologyでは、キャリア採用を行っています。


  • 日頃勉強している成果を、Hadoop、Storm、NoSQL、HTML5/CSS3/JavaScriptといった最新の技術を使ったプロジェクトで発揮したい。
  • 社会貢献性の高いプロジェクトに提案からリリースまで携わりたい。
  • 書籍・雑誌等の執筆や対外的な勉強会の開催を通した技術の発信や、社内勉強会での技術情報共有により、技術的に成長したい。
  • OSSの開発に携わりたい。

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 キャリア採用ページ