Taste of Tech Topics

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

Elastic{ON} 2016レポート What's Cookin' in Kibana #elasticon

続いては、Kibanaのプロダクトセッション。
キーノートでも一番プッシュされていたのはKibanaでしたし、Elasticスタックの中でいま一番ホットな感じがします。

f:id:acro-engineer:20160218185253j:plain:w480

そんなKibanaのこれまでと、これからです。

Hack the Kibana!

Kibanaが可視化のためのWebアプリであることは既に皆さんご存じのことと思いますので割愛して、Kibanaアプリの作り方からです。

ところで、なんだかKibanaアプリなのかKibanaプラグインなのか、割と表記揺れしててはっきりしないのですが、
基本的には同じモノを指しているんだろうなというのが今の感覚です。

さて、KibanaアプリはAngular + node.jsの組み合わせで作られており、自分で開発することも可能です。
アプリのひな形を作るYeoman Generatorが用意されており、それを使った作り方が紹介されました。

f:id:acro-engineer:20160218185235j:plain:w480

一番大事なところだけ抜粋すると、

yo kibana-plugin 

ということで、yoしましょう。

セッション中には、Hot Keyを作るサンプルが紹介されました。

f:id:acro-engineer:20160218185221j:plain:w480

サンプルは、この辺りを見ると良いとのことです。
https://github.com/simianhacker/kibana-hacks
https://github.com/rashidkpc/kibana-hacks


また、3日目の金曜日には、Kibanaプラグインを作ることに主眼を置いたセッションが行われるとのことなので、
割とガチでKibanaアプリを作らなくてはならない状況の僕としては、そちらも参加しようと思います。

What's new in Kibana 5.0?

続いてKibana 5.0の新機能。
Kibana 5.0は、とにかく見た目がシンプルになって、無駄な余白がなくなったことが大きいです。

f:id:acro-engineer:20160218185025j:plain:w480
そうなんです、Kibanaを業務で使い始めると、たくさんグラフを置いたダッシュボードなどを作りたくなり、そうすると余白が邪魔だなと思うようになるんです。
そういう点で、5.0の新しいUIはとても良い印象です。


しかもKibana 5.0は4.x系と完全な後方互換を保つとのこと。マジか。
Elasticスタックはとにかく後方互換を切り捨てることでスピーディーに進化してきている印象でしたが、
ここに来てさすがに「切り捨て過ぎ」の声も大きくなってきたのでしょうか。

とにかくこれも重要なポイントです。


また、KibanaはAppliation Orientedな構成になります。Marvel、Sense、Timelionなどなど、
いずれもKibana本体ではなく、プラグインであるKibanaアプリとして提供されています。

f:id:acro-engineer:20160218185055j:plain:w480
元々、プラグインは非推奨だと言われていた3.x系の頃から、4.x系ではプラグインを正式に作れるようになり、
5.x系ではアプリが中心と謳われるようになったうえ後方互換を保つなど、かなりの力の入れようです。


ということで、全体を通じてKibanaアプリに主眼を置いたような内容でした。
ちょうど僕も業務でKibanaアプリを開発しようとしている所で、バージョンアップ追従が大変なことを懸念していたのですが、
昨今の様子を見ていると、割とそこは気を遣ってもらえるのかな・・・と思えるようになりました。

まぁそう思ってたら、いきなりハシゴが外されちゃうのが、Elasticのスリリングなところですけどね!

Elastic{ON} 2016レポート What's Evolving in Elasticsearch #elasticon

キーノートの次は、Elasticsearch本体のプロダクト紹介セッションに参加しました。

最近のElasticsearch 2.xは?

最近のElasticsearch 2.x系では、ユーザビリティの改善、Javaヒープ使用量の削減、セキュリティの強化、テストの強化などが行われています。
特にElasticsearch 2.0で、doc valuesというオプションがデフォルトで有効になったおかげで、
ヒープ使用量がグッと下がり、それなりに少ないメモリでも機嫌よく動いてくれるようになったと実感しています。

たぶんもう1.x系には戻れないですね。

f:id:acro-engineer:20160218181304j:plain:w480


また、2.2ではプロファイルAPIという機能が追加されました。
これはちょうどSQLの実行計画を取得するようなもので、Elasticsearchに対するクエリが、
どのようなLuceneクエリに分解されて、
それぞれのLuceneクエリの処理に掛かった時間や取得したデータ件数などを確認できるようになる機能です。

パフォーマンス改善で利用できるのはもちろんのこと、Elasticsearchのクエリに不慣れなうちは、
自分が書いたクエリが期待通りのクエリに分解されるかどうかを確認するという用途でも使えます。
ほら、Elasticsearchのクエリの文法とかよく分からないから、最初はOR検索をうまくできなかったりするじゃないですか。
(主に僕がそうだったんですが。)

そういう人にも便利なので、プロファイルAPIはぜひ使ってみてください。
検索クエリに "profile": true とつけるだけで実行できます。

新機能その1、加工や更新のためのAPI

これから追加される新機能の目玉の一つが、Ingest Node。
データの加工やフィルタリングなど、LogstashのFilterプラグインで実現していた機能をElasticsearch自身が持つというものです。

f:id:acro-engineer:20160218181521j:plain:w480

たとえばApacheやnginxのアクセスログを分解して、それぞれのフィールドに格納するだとか、
IPアドレスから位置情報を取得するとか、そのような加工をElasticsearchで行うことができるようになる、というものです。

これまでは、データ加工を行いたければLogstashを挟む必要がありましたが、その必要なくなるということですね。

これはデータの流れなどが変わる要因になる、大きな機能追加と言えます。


続いて大きな変更になるのが、Re-Index API

f:id:acro-engineer:20160218181328j:plain:w480
次のようなクエリを発行することで、old_indexに対して検索を掛けて、一致したドキュメントだけをnew_indexにコピーすることができます。

POST _reindex
{
  "src": {
    "index": "old_index",
	"query": {
	  "match": {
	    "user": "twitter"
	  }
	}
  },
  "dest": {
    "index": "new_index"
  }
}

たとえばHTTPサーバのアクセスログを全部投入したうえで、
検索APIへのアクセスだけを別indexに入れて細かく検索条件を分析するだとか、
ログインしたユーザとそうでないユーザでindexを分けて異なる分析をする、
ということができるようになります。


同じような形で、もう一つ追加されるのが、Update by Query API
これはindexに対して検索を掛けて、一致したドキュメントを、指定した条件で更新するというものです。



Ingest Node、Re-Index、Update By Queryを組み合わせれば、とにかくいったんElasticsearchにデータを投げ込んでおいて、
後で加工しながらindexを分ける、ということができるようになりそうです。

この辺りは実際にどういう形になるのかもう少し先にならないと分からないのですが、
何にせよElasticsearchにログを流し込むアーキテクチャをよりシンプルにできるものだと思います。

新機能その2、Java Http Client。

もう一つ、目が離せないのがJavaのHTTP Client。

Elasticsearchは標準で9200番ポートと9300番ポートの2つを利用しており、
9200番ポートがHTTP用(RESTクライアント用)、9300番ポートがクラスタ間通信の独自プロトコル用で使われていました。
それでcurlコマンドやSenseなどからは9200番ポートを使い、Javaのクライアントは9300番ポートを使っています。

9300番ポートの方がHTTPのオーバーヘッドがない分、パフォーマンスが良いと思うのですが(計測したことはないです)、
その反面、9300番ポートを使うJava APIのライブラリには、Elasticsearchサーバで必要なクラス群が含まれていました。

だって、元々クラスタ間通信のためのポートですからね。


今回、Java用に9200番ポートを使ったHTTP Clientができるおかげで、フットプリントの小さなJARライブラリができることになります。

f:id:acro-engineer:20160218181425j:plain:w480

また、Java APIは頻繁に(バージョンアップのたびに)APIが変わっていたのですが、HTTP APIは比較的安定していました。
特にJava APIを使う外部ツールを作っていた場合には、バージョンアップに追従するのが大変だったことも、一つの問題になっていました。

そういう点でも、HTTP APIJavaでも使えるようになる恩恵は大きいと言えますね。

まぁこれだけ説明してきましたが、本音で言えば「やっとかよ、最初から作っとけよ!」なんですけどね!(笑)

その他は・・・

あとはk-dimensional treeを使ったPoint field encodingを数値型や日付型に対して行うことで、
データサイズの削減や検索パフォーマンスの向上、ヒープサイズの削減などが行われます。

f:id:acro-engineer:20160218181353j:plain:w480
この辺りあまり詳しくないので仕組みはよく分かりません、すみません。


そんなElasticsearch 5.0のalpha版は、まもなくダウンロード可能になるとのこと。

f:id:acro-engineer:20160218181632j:plain:w480

とにかく、早く試してみよう!

Elastic{ON} 2016 キーノートレポート Elastic goes 5.0! #elasticon

いよいよ始まりました、Elastic{ON} 2016 サンフランシスコ。キーノートセッションで開幕です。

f:id:acro-engineer:20160218163338p:plain:w600

イベント会場には「Elastic Cloud」や「X-Pack」という聞き慣れないプロダクトの垂れ幕が出ていたので、これらがいったい何なのか、始まる前からワクワクです。
f:id:acro-engineer:20160218163044p:plain:w300
f:id:acro-engineer:20160218163048p:plain:w300

Elastic stack goes 5.0

まず最初の大きなアナウンスは、Elasticのプロダクト群がバージョン統一されること。
現行では、Elasticsearch 2.2 + Logstash 2.2 + Kibana 4.4 + Beats 1.1という感じでバージョンの付け方がバラバラでしたが、次のメジャーバージョンは「5.0」として全プロダクトのバージョンが統一されます。
f:id:acro-engineer:20160218163555j:plain:w480


これに合わせて、各プロダクトのロゴも一新。これまでデザインがバラバラで、何種類かあったりなかったりの製品ロゴも、同じテイストで統一されました。

元々はこんな感じのロゴ多すぎ問題がありましたが。
f:id:acro-engineer:20160218163432j:plain:w480

こんな風にすっきりします。
f:id:acro-engineer:20160218163632j:plain:w480

また、Elasticsearch + Logstash + Kibanaを合わせてELKスタックと呼んだり、そこに後からBeatsを加えてELKBやKELBと呼んだりしていましたが、これからはElastic stackという呼び方に変わります。
f:id:acro-engineer:20160218163713j:plain:w480
ELK B(ee)のアイコンは初めて見ましたが、これで見納めになりました。


5.0系では、Kibanaが独自のタイルの上にヒートマップを作る機能や、タグクラウド機能の追加。
f:id:acro-engineer:20160218164015j:plain:w400
f:id:acro-engineer:20160218164021j:plain:w400

Logstashのさらなる性能改善。
f:id:acro-engineer:20160218164051j:plain:w400

Metricbeatによるモニタリングの統一。
f:id:acro-engineer:20160218164102j:plain:w400

などなどが発表されました。
これらはこの後の各セッションでも詳細が紹介されるはずです。

Packs and X-Packs comes

続いて、Packsの紹介です。
Elasticスタックのプラグイン群をひとまとめにしたもので、プラグインの導入を容易にする狙いがあるようです。
f:id:acro-engineer:20160218164219j:plain:w480

これまでは、たとえばMarvelというモニタリングプラグインを導入するには、ElasticsearchにMarvel AgentとLicenceプラグインを入れて、KibanaにMarvelプラグインを入れて、、、という感じで、それぞれのプロダクトにそれぞれのプラグインをインストールする必要がありました。

Packsはこれを容易にするもので、単一のzipファイルに全プラグインを入れて、これを一気にインストールできるようにする、というものです。


そんなPacksの一つの形が、X-Pack。
Shield、Watchr、Marvelなどの商用プラグイン群を一つにまとめたもの。このX-Packには、さらにPDFレポート作成機能や、グラフAPI(いわゆる有限グラフの方)なども含まれます。
f:id:acro-engineer:20160218164244j:plain:w480

PDFレポートはガチに仕事で必要になるやつですし、グラフAPIも注目度は高いです。
f:id:acro-engineer:20160218164454j:plain:w480
こんなグラフが拡大/縮小しながらグリグリ動くんですよ!

ただこれらは商用サポートが必要になる(はずです)ので、興味を持った方はぜひ導入をご検討のうえ、販売代理店である弊社にご連絡いただければ僕が大いに喜びます。わーい。

Found is now Cloud

ElasticsearchをSaaSとして提供する、Foundというサービスがあります。
Foundという名前の割に見つけるのが難しい(hard to find)サービスなのですが、これの名前が変わります。

変わった名前は、Elastic Cloud、通称Cloud。
f:id:acro-engineer:20160218164739j:plain:w480
残念ながら見つけにくさに変わりはありませんでした。
むしろ検索してもAWSのサイトにしか行けなくなる気がしてなりません。

たまたま最近Foundのトライアルに申し込んだところでしたので、早速Cloudにログインしてみたところ、サイトが刷新されており、テイストが5.0系のものになりました。ただ、いまのところ機能的には既存のFoundと同じでした。


そして、このCloudを自前でホスティングできるようになるサービスが、Elastic Cloud Enterprise。
AWSやAzuleにインストールして、クラスタを作って管理することができるようになるプロダクトです。
f:id:acro-engineer:20160218164933j:plain:w480

私の仕事上の経験でも、ひとたびElasticsearchを使い始めると、他の部門から「こんな可視化ができないか」「うちもやりたい」などと声が掛かるようになります。これまでは、同じElasticsearchに相乗りさせたり、それぞれごとにサーバを立てて管理したりしていたのですが、Elastic Cloud Enterpriseは、そういう用途で使えるものになりそうです。

ライセンス費用が気になるところなので、継続的にウォッチしたいと思います。

最後に、IBMのデモ

最後に、プラチナスポンサーのIBMによる、IBMでのElasticsearchの利用について。
アプリケーションのログをいったんKafkaに入れて、そこからLogstashを経由して、データストレージとElasticsearchに転送しているようです。
f:id:acro-engineer:20160218165133j:plain:w480

このような規模が大きいElasticsearchの事例など聞くにつれ、間に挟むログストリームのハブというか、中間バッファは、Kafkaで決まりという感じがしますね。
名前的に過負荷にも強そうですしね。ズコー。


という感じでオチもついたところで、キーノートセッションのレポートは以上としたいと思います。
この後も、楽しそうなセッションが目白押しですよ!

See you!

Elastic{ON} 2016のため、サンフランシスコにやってきた! #elasticon

おはようございます @cero_t です!
やってきましたサンフランシスコ、今回の目的はいつものJavaOneではなくElastic{ON}です。

f:id:acro-engineer:20160218053113j:plain:w480

行きの飛行機はボーイング787、経由地のロサンゼルスは気温30℃越えと、なんかバカンスに来たとしか思えないような様子ですが、安心してください、仕事しますよ!


さて、
本日2/17(水)から3日間かけて行われるElastic{ON}では、Elasticsearchのテクニカルな情報や、ユースケースなどが発表されます。
Elasticsearchはバージョンアップも頻繁ですし、GitHub上で開発状況やissueもよく見えているので、それなりに今後どうなるかを把握しているつもりではあるのですが、サプライズ情報だったり、Deep Diveな内容に期待をしています。

場所はPier48。桟橋の上でイベントって 何を考えてるのか どういう様子なのか分からないので、その辺りも楽しみです。


なお現在は、イベント前のプレトレーニングを実施中。
ELKのスタートアップハンズオンと、1000台越えのスケーリングに関するセッションの2択。同僚が後者を受講中ですので、あとでフィードバックしてもらおうと思います!

ところでElastic{ON}、なんか良い感じの朝食やエスプレッソマシンが用意されています。
elastic最高かよ。
f:id:acro-engineer:20160218030538j:plain:w320

そんなわけでこれから3日間、このイベントのレポートをしていきたいと思います。
Stay elastic, see you!

レポート一覧

3日目

Elastic{ON} 2016レポート AMA = Ask Me Anything! #elasticon - Taste of Tech Topics
Elastic{ON} 2016レポート いよいよクロージング! #elasticon - Taste of Tech Topics

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


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

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 
データ分析で国内に新規市場を生み出す新サービス開発者WANTED! - Acroquest Technology株式会社の新卒・インターンシップ - Wantedlywww.wantedly.com

思い切ってelasticのTimelionを取り入れてみた

こんにちは。
先日「elasticの新プロダクト「Beats」シリーズに震える!」
を投稿したPlNOKlOです!

AcroquestではENdoSnipeBVDというサービスで経営の可視化を行っており、
私も2年目ながら可視化のお手伝いをさせてもらっています。

今回、とあるお客様から、
稼働率を表現したい」という要望をいただきました。

見たいグラフを打ち合わせした結果、
線グラフエリアグラフを同時に表示する必要がでてきました。

ですがご存知の通り、Kibanaでは
線グラフなら線グラフ、エリアグラフならエリアグラフと、
一つのグラフしか出力できないんです。

ではどうするか・・・

JavaOne2015に登壇し、
私のボスでもある、
@cero_t さんに相談したところ、
「試しにTimelion使ってみたら?」
とアドバイスをもらいました。



Timelion・・・?
Timelionとはなんぞや??

調べたところ、Timelionは「タイムライン」と読み、
完全に独立したデータソースを1つのインターフェイスに集約します。
このインターフェイスは、データの取得、時系列の結合、変換、視覚化を
まとめたシンプルな1行の式言語で駆動します。
Timelionの式はすべてデータソース関数で始まり、
例えば、.elasticsearch(*)(短縮形は.es(*))のように表記します。
1つの図に2つのグラフを組み合わせる場合は、グラフをカンマで区切ることで表示できるようなんです。


ほう。
なるほど。
Timelionは独自の関数を用いることで、
グラフを組み合わせて表示できるものなんですね。


それでは早速触ってみましょう!


Timelionで触ってみた


今回稼働率ということで、
昨年の稼働時間を比較するグラフを作成します。

昨年の稼働時間が20%増えた時間を赤のエリアグラフ、
10%増えた部分を黄色のエリアグラフ、
10%減った部分を青色のエリアグラフ、
そして今年の稼働時間を緑の線グラフとして
表示してみましょう。


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


Timelionはこういった感じです。
上にあるウインドウで関数を書いてグラフを作成します。

使用できる関数はヘルプから見ることができます。


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


デフォルトで書いてある「.es(*)」は
elasticsearchのインスタンスからデータを取得するという関数です。

ではまずは今年の稼働時間の線グラフを作成してみましょう。
es関数の中で使用できるのはこちらです。


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


"index"でindexを指定し、
"q"でQueryを指定し、
"metric"で縦軸の計算方法を指定し、
"timefield"で横軸の時間を指定し、
esの後に"color"関数を加えることで色を指定することができるようですね。

これらを用いて書いたのがこちら。

.es(index='dailymonitoring', q='line:"今年実際値"', metric='sum:hour', timefield='date').color(green)

表示してみると・・・


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


おおおおおおおおおおおおおおおおおおおおお!!!!!!!!!
簡単ですね!簡単すぎて吼えてしまいますね!!
この調子で次は赤のエリアグラフを出してみましょう!!


それでは同じ要領で.esを書いてみると、

.es(index='dailymonitoring', q='line:"20%増"', metric='sum:hour', timefield='date').color(red)

このようになります。

しかしこのままでは折れ線のままになってしまいます。
なので、ヘルプを見てみましょう。

グラフの形を指定する関数は
".lines"と".bars"の二つが用意されています。



・・・・ん?あれ??
エリアは???



・・・NOOOOOOOOOOOOOOOOOOOOOOOOOOOOO!!!


そう!そうなんです!
エリアグラフを表現できる関数がないんです!!
思わず夜空にライオンのごとく雄叫びです!!
夜空ノムコウ!らいおんハート!!



「Timelionはまだ開発中だからな・・・」
「諦めよう・・・」
なんて弱気な私が囁いてきました。

だがそこに割って入ったのが強気な私!

諦めないで!」と、囁いてきたのは、そうです。
強気な私というか、あれですね。
石鹸のCMの時の真矢みきさんですね。
私の心の中にいる真矢みきさんでした。


元気が出てきました。
私には宝塚出身のスターがバックについていてくれると思うと
心強くなってきました!
きっと夜空に吼えたのも心の中の真矢みきさんです!
深夜を迎えておりますがこの勢いに乗って他の関数も見てみましょう!!


es関数をもう一度見てみましょう。

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

やはりこの中にはありませんね。

では、エリアグラフは折れ線の下を塗っているグラフなので、
次はlines関数を見てみましょう。

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

お。

fill : Number between 0 and 10. Use for making area charts

これ怪しいですね。使ってみましょう!

.es(index='dailymonitoring', q='line:"20%増"', metric='sum:hour', timefield='date').lines(fill=10).color(red)

こちらを表示すると・・・


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


おーー!!!!
できました!!!!!

それではすべての線を合わせてみると・・・


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


ぅおおおおおおおおおおおおおおおおおおお!!!!!!!!!!!!!!!!!
完成しました!!!
全ては真矢みきさんのおかげです!!!!!


というわけでTimelionだけに吼えまくりでしたが、
エリアグラフと線グラフは、
両方ともlines関数を駆使して出力することで
表示できました!



裏トーク

実は裏では他にもいろいろ試して苦労したことがあるんです。

例えば、グラフのタイトルを出したくても出せなかったり、
Timelionで作成したグラフの説明をするために、
Kibanaのdashboardでvisualizationと一緒に出そうとしても出せなかったり、
表示する期間を保存したくても保存できなかったりと、
なかなかやりたいことができず苦戦しました。

ということで、
Timelionの発展期待しております!(笑)


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


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

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
データ分析で国内に新規市場を生み出す新サービス開発者WANTED! - Acroquest Technology株式会社の新卒・インターンシップ - Wantedlywww.wantedly.com

Elasticsearchを使うときの注意点を社内で発表しました。

こんにちは、fujiiです。


最近、社内でもElasticsearchを使う機会も増えてきてました。

インストールも簡単ですし、
ちょっと設定するだけでログの解析も手軽にできるので、
便利だと思って使い始めるのですが、

・必要以上に負荷のかかる設定になっている。
・システムダウンしたときの復旧を考慮していなかった。
・初期構築などで大量にデータを入れようとしたら、一部データが入っていなかった。

と、後から反省することも多くあります。
(私も最初は知らないことが多く、反省点ばかりでした)


そのため、Elasticsearchを初めて使うときの注意点をまとめ、
社内で講習会を開きました。



以下に公開しました。
実際に案件で利用しようと思った時にパフォーマンスなどで迷うこともありますので、
そんな時の一つの参考になればと思います。

www.slideshare.net


社内向けの資料なので、分かりづらいところは、ご容赦ください(^^;


参考:Elasticsearchインデクシングパフォーマンスのための考慮事項 - Qiita



なお当社では、Elasticsearchの構築サービスと、Elasticsearchの無料入門セミナーを行っています。

詳細は、こちらのURLまで!
http://www.acroquest.co.jp/elastic/


それでは。

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


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

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 データ分析で国内に新規市場を生み出す新サービス開発者WANTED! - Acroquest Technology株式会社の新卒・インターンシップ - Wantedly

Springfox+Swagger+Bootprintによる即席REST API仕様書作成 ~制約編~

こんにちは、阪本です。

以前、「Springfox+Swagger+Bootprintによる即席REST API仕様書作成」というエントリーを書きましたが、今回はパラメータの制約をドキュメントに反映する方法について確認してみます。
なお、今回はSpringfoxのバージョンを2.3.1にしています。

@ApiModelPropertyによる制約の指定

まずは、Swagger Annotationを使ってパラメータの制約や説明の追加を行ってみます。

前回使用したEmployeeクラスに、@ApiModelPropertyアノテーションを追加します。

package swagger.entity;

import java.util.Date;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;

import io.swagger.annotations.ApiModelProperty;

public class Employee {
    private Integer id;
    private String  name;
    private Date    birthday;

    @ApiModelProperty(value = "Employee ID.", allowableValues = "range[1, 100]")
    @Range(min = 1, max = 100)
    public Integer getId() {
        return this.id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    @ApiModelProperty(value = "Employee's name.", required = true, allowableValues = "range[0, 32]")
    @NotEmpty
    @Size(max = 32)
    public String getName() {
        return this.name;
    }

    public void setName(String name) {
        this.name = name;
    }

    @ApiModelProperty(value = "Employee's birthday with ISO 8601 format.", required = true)
    @NotNull
    public Date getBirthday() {
        return this.birthday;
    }

    public void setBirthday(Date birthday) {
        this.birthday = birthday;
    }
}

value属性にプロパティの説明、requiredに必須かどうか、allowableValuesに値の範囲を指定します。他にも、例を指定したりプロパティ名を変更したりもできますが、ここでは割愛します。

上のようにEmployeeクラスを記述してSpringBootアプリケーションを起動すると、次のようにSwagger UIに反映されます。

http://localhost:8080/swagger-ui.html
f:id:acro-engineer:20160113022055p:plain

画面右側のModel部分に情報が反映されていることがわかります。idプロパティのinteger部分にカーソルを合わせると、allowableValuesに指定した範囲も見えます。
ちなみに、日付フォーマット等の、必須・範囲以外の制約については、value属性に説明として記述する必要があります(専用の属性がありません)。

バリデーション用のアノテーションから制約条件を取得する

上で説明した方法では、JSR-303のアノテーション(@NotNullや@Size等)の情報を取ってきているのではなく、あくまで@ApiModelPropertyの値を取ってきてドキュメントを生成しているに過ぎません。
プログラムで動作するバリデーション用アノテーションとドキュメント用アノテーションを両方記述するのは、手間なのとズレが発生するのとで、避けたいところです。
ということで、バリデーション用のアノテーション(JSR-303等)から制約条件を取得できるように修正を加えます。

残念ながら、現時点(2016年1月)の最新バージョンであるSpringfox 2.3やSwagger 1.5では実現できないため、自前でコードを書く必要があります。
具体的には、ModelPropertyBuilderPluginインタフェースを実装したクラスを作成します。@Componentを付けて、SpringBootのComponentScan対象にしておきます。

package swagger;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;

import org.hibernate.validator.constraints.NotEmpty;
import org.hibernate.validator.constraints.Range;
import org.springframework.stereotype.Component;

import com.fasterxml.jackson.databind.introspect.AnnotatedMethod;
import com.fasterxml.jackson.databind.introspect.BeanPropertyDefinition;
import com.google.common.base.Optional;

import springfox.documentation.builders.ModelPropertyBuilder;
import springfox.documentation.service.AllowableRangeValues;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spi.schema.ModelPropertyBuilderPlugin;
import springfox.documentation.spi.schema.contexts.ModelPropertyContext;

@Component
public class Jsr303ModelPropertyBuilderPlugin implements ModelPropertyBuilderPlugin {

    @Override
    public boolean supports(DocumentationType delimiter) {
        return true;
    }

    @Override
    public void apply(ModelPropertyContext context) {
        ModelPropertyBuilder builder = context.getBuilder();

        // プロパティのgetterを取得する
        Optional<BeanPropertyDefinition> beanPropDef = context.getBeanPropertyDefinition();
        BeanPropertyDefinition beanDef = beanPropDef.get();
        AnnotatedMethod method = beanDef.getGetter();
        if (method == null) {
            return;
        }

        // 必須・非必須を取得する
        NotNull notNull = method.getAnnotation(NotNull.class);
        NotEmpty notEmpty = method.getAnnotation(NotEmpty.class);
        if (notNull != null || notEmpty != null) {
            builder.required(true);
        }

        // 範囲制約を取得する
        Range range = method.getAnnotation(Range.class);
        if (range != null) {
            builder.allowableValues(new AllowableRangeValues(
                    Long.toString(range.min()), Long.toString(range.max())));
        }
        Size size = method.getAnnotation(Size.class);
        if (size != null) {
            builder.allowableValues(new AllowableRangeValues(
                    Long.toString(size.min()), Long.toString(size.max())));
        }
    }
}

Jsr303ModelPropertyBuilderPluginクラスのapplyメソッドで、各プロパティのgetterについているアノテーションを取得し、その内容に応じてModelPropertyBuilderに制約条件を設定しています。
#「Jsr303」というクラス名にしていますが、Hibernate Validatorのアノテーションも処理対象に加えています^^;

上記クラスを作成しておけば、次のように、Employeeクラスの@ApiModelPropertyから制約に関連する属性(requiredとallowableValues)を削除し、冗長な記述を排除できます。
(getterのみ抜粋して記載)

@ApiModelProperty(value = "Employee ID.")
@Range(min = 1, max = 100)
public Integer getId() {
    return this.id;
}

@ApiModelProperty(value = "Employee's name.")
@NotEmpty
@Size(max = 32)
public String getName() {
    return this.name;
}

@ApiModelProperty(value = "Employee's birthday with ISO 8601 format.")
@NotNull
public Date getBirthday() {
    return this.birthday;
}

これらを実施した上で再度SpringBootアプリケーションを起動すると、先ほどと同じSwagger UIページが生成されます。
必要に応じて対応アノテーションを増やす必要はありますが、冗長な記述は排除できました。

bootprint-swaggerで静的ドキュメント生成!

ということで、前回同様、bootprint-swaggerでHTMLのAPI仕様書を生成してみます。

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

なかなか難しい表現が出てきました・・・(汗)
{ x ∈ Z | 1 ≤ x ≤ 100 } のZは、代数学で言うところの「整数の集合」を表しています。
あと、nameのところは (up to chars) と出力され、具体的な文字列長が出てきませんでした。
ちょっとイマイチ感がありますね。。

Bootprint側のカスタマイズは調べてみようと思います。

それでは。

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


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

 
少しでも上記に興味を持たれた方は、是非以下のページをご覧ください。
 競合は海外・外資!国内に新規市場を生み出す新サービス開発者WANTED! - Acroquest Technology株式会社の求人 - Wantedly