2013年4月22日 (月)

Herokuのログ解析ツールを作りました。

こんにちは

Herokuのログ解析をするツールを公開しました。
紹介スライドはこちら。これ以上ドキュメント的なものを書く予定はないのであしからず。(^^;;;

(聞かれたことには答えますけど)

 

★何ゆえの公開?

FLECTは基本SIを生業とする会社なのですが、僕はその中で一人R&DチームとしてSI案件には深く入り込まずに比較的自由に色々なことをさせてもらっています。(非常に感謝しています。)

その業務のひとつとして、自社内の業務で共通的に使用できるツールあるいはライブラリの作成と言うのがあるのですが、これらは可能なかぎりソース公開した状態で作って行こうかと思っています。

そうしようと思った理由は大きく3つあります。

 

1、もはや社内ツールやライブラリは企業にとっての強みとなりえない

世は大オープンソース時代です。

ある日誰かがこんなことしたいなぁ、と思ったとして最初にやることはまず検索。そして恐ろしいことに大抵のモノは見つかります。

もちろん、SIという業種においてはそれですべてが賄えるということはまずないので、それで仕事がなくなることはないのですが、少なくともSI屋にとっては部品は作るものではなく拾うものであるというのが個人的な認識です。

という、社内での自分の立位置をいきなり全否定するような現状認識がまずありまして。。。(^^;
要するに自分の作るようなものは多分どこかで誰かが似たようなものを作っているだろうし、仮になかったとしてもすぐに同じものが作れちゃうだろうと思う訳です。

だからと言って自分の仕事には価値がないと思っているわけでは全くないので念のため。Closedでやることに意味がないと思っているだけでむしろ部品屋の需要と価値は高くなっているはずです。そして中の人がそれを作っているということは大きなアドバンテージになると思っています。(まぁ、もちろん作るモノにもよるわけですが。。。)

 

2、100%を目指さないという実験

この業界にいる人なら誰もが気が付いていることだと思いますが、8割の完成度のものを作るのは比較的簡単です。今回のログ解析ツールなどもまさに8割程度の完成度だと思います。

8:2の法則という言葉もある通り、ほとんどの場合残りの2割を埋めるために多くの時間が費やされていると思います。

逆に言えばこの2割をカットすればもっとずっとアウトプットは多くなるはずです。

業務アプリであれば、それは許されないことですがこれから作成しようと思っているものについては少なくとも当面は最後の完成度をあげていくことよりもアウトプットの量を増やすことに比重を置きたいと思っています。

ぶっちゃけた話僕にとって詰めるのが辛い最後の2割とはほぼUIです。。。(--

 

3、Herokuでお手軽アプリ

今回のログ解析ツールは

  1. git clone
  2. Herokuにpush
  3. いくつかの個人用のconfigを設定

するだけで動きます。

こうしたスタイルでのリリースはHerokuがなければあり得なかったことです。こういうアプリは面白いと思うし、もっと増えると良いなと思う訳です。

何よりすごいのはこの程度のアプリであれば無料で動かせるということですね。(^^;

 

□□□□

そんな感じで今年はちょっとアウトプットを増やそうかと思ってます。(^^v

ログ解析ツールについてはScalaのことも書きたいんですが、それはまたいずれ。

2013年4月 5日 (金)

Heroku meetup #8

こんにちは

Heroku meetup #8に行ってきました。
てか、WAZAレポとLTでしゃべってきました。(^^;

久々に人前で喋ったのとMacでプレゼンやったのが初めてだったのとでかなりテンパリましたね。(--
もうちょっと素振りしてから望むべきでした。あいすいません。m(_ _)m

僕のことはともかく内容的にはかなり面白いミートアップだったと思います。
以下内容を振り返ります。

 

★オープニング

まず最初にHerokuの相澤さんによる3つのフィーチャーピックアップがありました。

 

1、PostgreSQL 9.2のこと

ちょっと前にPostgreSQLを9.1から9.2にアップデートするエントリを書きましたが、現在はオプション付けずとも9.2になるそうです。めでたい。(^^v

実は昨日たまたま新しくHerokuPostgresを追加する機会があったんですが、これのバージョンを確認すると9.2.4になってました。(もっとも、この時は「--version=9.2」をつけて追加しましたけど)

これを書きながらPostgreSQL本家に最新版のバージョンを確認しに行ったんですが、、お、最新版のバージョンも9.2.4。。。

。。。あれ???

リリース日 2013年4月4日!!?

昨日やんけ。。。。

気になって他のアプリのPostgreSQLバージョンも確認したところ、9.2系はすべて9.2.4に、9.1系はすべて9.1.9(9.2.4と同時リリースの9.1系最新版)になっているようです。

あ~、数日前にHerokuからDBメンテナンスのアナウンスが来てたのはこれかぁ。。。
リリースアナウンスに

 

These releases fix a number of bugs in previous releases, including a serious security issue.

Users are strongly advised to upgrade as soon as possible.

 

とあるからセキュリティ上の問題で緊急に全部のDBをアップデートしたのね。。。

しかし、それにしても素早い!
逆算すると完全に本家のリリースよりも先に作業してるよ。(^^;;;

HerokuのPostgreSQLへの力の入れ具合がわかるというものです。
JavaはいまだにJava6がデフォルトなのにね。(--

 

2、2X Dynoのこと

メモリが従来の2倍(1024MB)のDynoが使えるようになるということです。

これは正直かなり嬉しい!!!

Javaでアプリを作っているとやっぱりどうしてもメモリは食うので。(R14 Memory quota exceededの警告ログが延々と出続けるのは日常茶飯事)

お値段も2倍ですが、これは多分使います。(^^v

現在ベータ版扱いだそうでまだ一般ユーザーには公開されてないとのことでしたが、僕のHerokuコンソールには普通に設定UIが表示されてますね。周囲の同僚も同様。パートナー企業だからかな?

 

3、OAuthのこと

HerokuがOAuthのサービスプロバイダになるそうです。

つまり自分の作ったアプリからHerokuアカウントで認証して許可をもらったあれやこれやの情報をゴニョゴニョするようなアプリを作れる。

.。。。と、いうことはわかるんですが、正直Herokuアカウントにひもづく情報はそれなりに機密性の高い情報ばかりなんじゃないの?という気がしていて何が認可対象になるのかイマイチぴんときてません。

例えば僕は現在社内需要からS3にあるPapertrailのアーカイブログをダウンロードして解析するアプリを作ろうかと思っていますが、こういうのはコンシューマアプリの候補になりえるのかな?

まだまだ絶賛開発中らしいので当面は静観ですかね。

 

★Treasure Data

さてお次はTreasure Dataの中川さんのセッションです。

最近なにかと話題のBigDataを扱う快進撃ベンチャー。

Herokuとの連携はprintlnでJSONを標準出力に書けば良いだけなのでとてもお手軽です。ていうかこれ以上簡単にしようがないですよね。(^^;

僕は最近評価目的で無償版を入れましたけど、中の人に「使うかどうかわからないけどとりあえずデータを突っ込んでおくという使い方はアリなの?」と尋ねたところ「よっぽど行儀の悪い使い方をしない限り全然OKです。」という回答だったのでしばらくアクセスログ的なものを突っ込んでみようかと思ってます。

ちょっとでも開発コストがかかるならこういう使い方はしないですけど、まぁprintlnだけですしね。(^^;;;

ちなみにもうじきPigにも対応するらしいです。

 

★WAZAレポ

そして次は僕も含む4人のWAZAレポート。

僕自身は向こうで演者の人達とだいたい一緒に行動していたのでうんうんという感じでしたがWAZAというイベントとHerokuという会社のことが少しは伝わったでしょうか?

皆さんと僕自身も何度も言っていましたが、一番重要なことはHerokuという会社がものすごくオープンでフレンドリーだと言うことです。ブラックボックスが少ないということは開発者にとってとてつもないメリットだと思います。

そしてもう一つ重要なことはランチの行列はなんとかすべきだということです。

 

★ライトニングトーク

鬼畜相澤の無情の3分制限をかけられたライトニングトーク(^^;;;

僕はそれ以前に初めてプロジェクタにつないだMacの画面が小さすぎて下の方が全く見えないという残念感で説明するのをあきらめたところがあるんですが。。。(--

あんなんで果たして内容伝わったかな???(^^;;;
ベースとなる技術のソースはGitHubにあって、何ができるかを解説したスライドも書いたんで興味ある方はご覧になってください。

今のところこの先どうするというあてはありません。(爆)

##追記

PostgreSQLの話はherokuのblogで公式アナウンスがでてますね。

https://blog.heroku.com/archives/2013/4/4/heroku_postgres_databases_patched

2013年3月12日 (火)

サンフランシスコに行ってきました

こんにちは。小西です。

2月28日にサンフランシスコで開催されたHerokuのイベント「WAZA」に行ってきました!

WAZA自体は1DAY EVENTだったのですが、その前後に主催であるHeroku社の相澤さんのご好意によりSalesforceやPivotal Labsなどのいくつかの企業を訪問することができ、非常に刺激的で有意義なUS出張となりました。

忙しい中出張を許可してくれた会社と企画してくれた相澤さん、そしてUSで出会ったすべての人たちに心から感謝します。

 

★WAZAとは

Herokuの年次イベントです。もうちょいHeroku発信の情報満載のイベントをイメージしていましたが、案外そうでもなくHerokuに関連する要素技術のテクニカルなセッションが多かった印象です。

ちなみにWAZAというネーミングは日本語の「技」から来ています。会場でもらったTシャツにもでかでかと「技」という漢字が(^^;
他にも入口では琴の演奏でお出迎え、オープニングでは太鼓と書道のパフォーマンスとそこかしこに和テイストがちりばめられていました。

この日本びいき(?)の理由は正直謎ですが、その理由の一つとしておそらくはRubyの開発者であるMatzことまつもとさんへのリスペクトがあるように思います。

そう、Herokuの母国語はRubyです。JavaやPythonもしゃべれるマルチリンガルではありますが、とりあえずなんか作るかーという場合は概ねRubyが使われるようです。
HerokuのGitHubをあさるとRubyのコードが山ほど見つかります。

演者はビッグネームが多かったようですがその中でも1番のビッグネームはやはりまつもとさんでしょう。Ruby 2.0の話をされましたが、この話を英語で聞けたことが逆に面白かったです。

 

★Postgres. The Bits You Haven't Found

http://postgres-bits.herokuapp.com/

さて、セッションについてですが僕が面白かったのは「Heroku Secret」と「Postgres. The Bits You Haven't Found」の二つです。まぁスライドの少ないセッションは聞きとるのが辛かったというせいもあるのですが。。。(--

Postgresのセッションの方は上記のリンク先のスライドを見ていただければだいたい内容はわかると思います。タイトル通りあまり知られていないだろう小技集です。

ArrayとRandomを組み合わせてテストデータを作成するという件などはかなり実践的だと思いました。

どうでもいいですが、スライドを公開するためだけにHerokuAppなのはなんなんでしょうね。(^^;
GitHubで絶賛ソースコードも公開中です。

 

★Heroku Secret

http://www.slideshare.net/heroku/heroku-secrets-waza-2013

もうひとつのHeroku Secretはアジェンダを見た時からこれだけは聞き逃すまいと思っていたセッション。中の人によるHerokuアーキテクチャの話です。

Herokuの機能にはHerokuで作られている部分も多くて例えばBundler-APIはWeb Dyno 6台とWorker Dyno 1台、4つのDB(Production * 1, Follow * 2, Test * 1)で動いているとか、そのビルドツールはどうなっているとかそんな話です。

あとはDatabase管理のツールとしてはDataScopeとDataClipがあるという話も。

DataClipについては以前からアナウンスされていたので知ってましたが、DataScopeって聞いたことないな。。。と思いながら検索をかけたところ。。。あったよ。。。これもソースがGitHubに。てか、オーナーのwillって前の日一緒に飲んでたやんけ(^^;

デモからSQLの発行頻度と処理時間を可視化するツールであることは想像できたので、さっくりcloneしてHerokuにpushしてみました。(^^;;;
DATABASE_URLだけ設定すれば動くかなぁと期待したんですが、画面がちっとも更新されませぬ。ざっとソースを眺めたところ。。。うーん、どうもCREATE TABLEひとつとWorkerを動かさないといけないらしい。(--

。。。Workerか。。。あ~(--。。。不採用。
必要に迫られたら解析して自分で似たようなものを作ろう。。。

ちなみにDataClipのソースは公開されていません。
ユーザーのデータベースにアクセスするコードが含まれているはずなので当たり前と言えば当たり前ですが。
こちらの方は便利に使わせていただいております。(^^;

□□□□

さて、すっかり脱線してしまいましたがここで重要なポイントはHerokuのアーキテクチャが可能な限りオープンだと言うことです。
データセンターのドキュメントを読むだけでかなりの部分のアーキテクチャが想像できますし、このように公開されているソースも多々あります。
セキュリティ上公開できないものがあるのは当然としても、アーキテクチャに関しては質問すればたいていのことは答えてくれるんじゃないですかね。これは普段サポートの人達とやりとりしていても感じることです。

こういう透明性の高いところが自分がHerokuを好きな理由だと思います。
やっぱりブラックボックスの多いものは使いたくないですしね。

 

イベント以外にもTreasure Dataの方たちとの会食など大きな刺激を受けたことはたくさんあり、それらについても書きたいのですがそれはまた次の機会に取っておきます。

2013年1月23日 (水)

HerokuのPostgreSQLをアップグレードする

こんにちは。
HerokuのPostgreSQLを9.2にアップグレードする作業を行ったのでその手順を残しておきます。

 

1、WebコンソールでアプリのオーナーアカウントのAPIキーを確認
有償Addonの追加を行うのでコマンドはアプリオーナーのアカウントで叩く必要があります。

 

2、コマンドラインでherokuアカウントの切り替え

 

set HEROKU_API_KEY=xxxxx

 

簡単なのでいつもこの方法でアカウントを切り替えてますが、ちゃんと切り替えようとするならコマンドプラグインの「heroku-accounts」を入れるのが良いらしいです。
この方法だとgitにはアクセスできないですしね。

 

3、メンテナンスモードにして外部からのアクセスを遮断

 

heroku maintenance:on --a my-app

 

4、PostgreSQLのデータバックアップ
Addonのpgbackupsを使ってデータをバックアップします。
pgbackupsは無償で毎日バックアップを取ってくれるのでPostgreSQLを使うなら必ず入れた方が良いです。

 

heroku pgbackups:capture -a my-app

バックアップを取り終わったら表示されたバックアップIDをメモしておきます。

 

5、既存のPostgreSQLを入れ替え
バックアップが終わったら既存のDBを破棄して9.2で新しいDBを作成します。

 

heroku addons:remove heroku-postgresql:crane -a my-app
heroku addons:add heroku-postgresql:crane --version=9.2 -a my-app

 

「--version=9.2」がPostgreSQLのバージョン指定です。
多分現時点ではまだ無指定の場合は9.1になると思うけど近日デフォルト9.2に変わるはずです。

DB作成時にforkオプションを指定するとを使うとDBの作成とデータの移行を同時にやってくれるはずですが、同一プランでのDBの追加ができるのかどうかがいまいち確信が持てなかったので先に既存DBを破棄してから追加しました。

DBの作成が完了するまでには数分かかるので

 

heroku pg -a my-app

 

でStatusがavailableになるのを待ちます。

 

6、データのリストアとDATABASE_URLの切り替え

 

heroku pgbackups:restore HEROKU_POSTGRESQL_XXXX_URL bxxx -a  my-app
heroku pg:promote HEROKU_POSTGRESQL_XXXX_URL -a  my-app

 

作成されたDBにバックアップをリストアします。
DATABASE_URLの切り替えは「heroku config:add」で行っても同じです。
(pg:promoteは内部的にheroku config:addを実行しているだけです。)

 

7、メンテナンスモード解除

 

heroku maintenance:off --a my-app

 

以上、動作確認して終わりです。
データ量にもよると思いますが概ね10分くらいで作業できます。

2013年1月18日 (金)

Herokuにやられた日

こんにちは。珍しくHerokuではまったのでその顛末を書いておきます。
しかも間抜けなことに同じ問題で2回はまりました。。。(--

さて、それがどういう問題だったかと言うと。。。

Procfileの行末がCRLFだとDynoが正しく起動できなくなる。

というものです。(--
これ、最初から動かなかったわけではなくて少なくとも12月の中旬ごろまでは間違いなく動いていました。
それが何かの修正のタイミングで行末がCRLFだった場合は最後のCRをコマンドの一部として実行するようになったようです。

最初から動いてなければそういうものとして納得することができるんですが、ある日突然動かなくなったので非常に焦りました。
現象の現れ方としては最初に書いたとおり2パターンありました。

 

★パターン1 - アプリが起動しない

あるアプリに1カ月ぶり位にちょっとした修正を加えてgit pushしたところいきなりアプリが起動しなくなりました。
何故かログには「NoClassDefFoundError: 」とか出力されて止まっています。
修正自体はささいなものだったので、それが原因とは考えられず最初は何が起こっているのかまったくわかりませんでした。

原因を追究するよりも先にまずはアプリを起動状態に戻さなければならなかったので修正をリバートしたものをgit pushしたんですが状況は改善しません。(--
なかば途方にくれながら今まで一度も使ったことがないコマンド「heroku releases:rollback」を使用して以前のバージョンに戻すとようやく起動するようになりました。

□□□□

話は少しそれますが、この「heroku releases:rollback」というコマンドはコンパイル済みのスラグと環境変数一式をどこかにとっておいてまるっと差し替えるコマンドのようです。
Git repository自体には手が入らないので次回にgit pushした時にはまた最新のrepositoryから新しいスラグが作成されます。(ただし環境変数はそのまま)

動作原理がわかっているといざという時に迷わず使えて便利そうではあります。抑えておいて損はないコマンドだと思います。
(途中にAddOnの追加があった場合はどうなるんだろうという疑問はありますけど。)

□□□□

さて、これでとりあえずアプリは動作するようになったわけですが、原因を調べようにもちょっとした変更をgit pushするだけでもれなくクラッシュするのでまたしても途方にくれてしまいます。(--
この時点でHerokuのサポートにあげても良かったんですが、もうちょっと自分で調べようと思い新しいHerokuアプリを作成してそっちにソース一式をpushして調査を継続することにしました。こういうことが手軽にできるのはHerokuの良いところではありますね。(と、フォローしてみる)

そんなこんなで紆余曲折、艱難辛苦の末にたどりついた原因がProcfileだったわけですが、これには本気で脱力しました。。。(--

その時のProcfileがこれ。

 

web: play run --http.port=$PORT $PLAY_OPTS <CRLF>

 

改行コードがCRLFであることと行末にスペースが入っていることがポイントです。
playコマンドの最後の引数として単独の「<CR>」が渡されていて、それがクラス名表示のないNoClassDefErrorを引き起こしていたらしい。。。。(--
マジでか!!!

HerokuがLinux上で動くプロダクトである以上、あらゆるファイルの改行コードはLFで統一すべきという指摘はもっともだと思うし、実際エディタの設定等は気をつけてはいるんですが、Procfileはすっかりechoとリダイレクトで作成する習慣がついていたので気が付かなかったんですよね。。。

先にも書きましたがこれが最初から起こっていた現象であるなら特に文句はありません。
しかし、ある日突然動かなくなったら「こんなの気づきっこねー」と愚痴のひとつも言いたくなるというものです。

結局この日はここまでで力尽きて帰りました。

★パターン2 - アプリの起動が重くなる

さて、今にして思えばこの時点ですべてのHerokuアプリのProcfileを見直しておけば良かったんですが、何しろその日はやろうと思っていたことが何一つできなかったので次の日はそれどころではありません。一応Herokuのサポートにレポートをあげたんですが、あっさりと「ごめん、直しとく」みたいな返答がきたこともあってこの問題については自分の中ですっかりかたがついてしまっていました。

そうこうしているうちに別のアプリでやけに起動に時間がかかるという問題に気が付きます。具体的には以下のような現象が発生していました。

  • git pushや環境変数の変更後ブラウザからの応答が長時間なくなる
  • ログを見るとR10(Boot timeout)がしばしば記録されている。つまりHerokuがDyno起動をリクエストした後1分間起動が完了せずに再起動を繰り返すことがある
  • たまに起動直後からR14(Memory quota exceeded)が記録されることがある。起動直後に大きなメモリを使用するような処理はないので明らかにおかしい

これも最初原因がわからなかったんですが、再起動時のログをtailで眺めていると常に「Precompiling...」というログを出力した後で一度ログの流れが止まることに気が付きました。あれ?起動時にPrecompileとかって走るんだっけ???

□□□□

で、調べてみるとPrecompileはPRODモードでかつ起動オプションに「-Dprecompiled=true」が指定されていない時に実行されることがわかりました。しかし、「-Dprecompiled=true」は環境変数のPLAY_OPTSで指定されているはず。
ということでもう一回Procfileです。

 

web: play run --http.port=$PORT $PLAY_OPTS<CRLF>

 

前のと同じに見えますか?(^^;
いえ、今回はCRLFの前にスペースがないことがポイントです。

環境変数「PLAY_OPTS」の末尾は「-Dprecompiled=true」となっていますが、これが行末のCRと結合して「-Dprecompiled=true<CR>」として引数化され、結果precompiled=trueとは解釈されないという。。。(--
またお前かよ!

実のところ2回目は問題解決にそれほど大きく時間を取られたわけではないのですが、脱力のあまりこのブログを書き始めてしまったので結局結構な時間が。。。。(--

まぁ別にいいんですけどね。(^^;;;

2012年12月18日 (火)

社内Heroku勉強会資料を公開しました

ご無沙汰です。

最近個別案件に貼りつき気味なのですっかりブログ書くのがとどこおっています。(ネタはなくはないんですが。。。)
今回もリンクのシェアだけの簡単な内容になります。(^^;;;

Heroku勉強会資料

社内勉強会向けに作成したHerokuの資料を公開したのでぜひご覧ください。
実際にHerokuで開発を行う場合に知っておいた方が良いことはだいたい書いたつもりです。

特に再起動周りは挙動をちゃんと把握しておかないとはまりがちなので厚めに書きました。

ご意見ご感想あればコメントくださいませ。間違いの指摘などツッコミ大歓迎です。(^^;;;

2012年11月 5日 (月)

HerokuのWorker再起動問題を考える

HerokuのWorker再起動問題を考える

こんにちは。

9月にこんな記事を書きました。

JavaでHerokuのWorkerを作成する

Heroku上のWebアプリをPlayframeworkで作るなら、WorkerもPlayで作るのが楽だよね!という話だったんですが。。。
実はこれ、ちょっと微妙な罠がありました。(--

 

★すべてのDynoは1日に一回再起動する

Herokuを運用しているとわりとすぐに気が付くと思いますが、WebDynoはだいたい24時間サイクルで再起動しています。
このあたりの挙動は以下のドキュメントに記載されています。

https://devcenter.heroku.com/articles/dynos#automatic-restarts

1日に一回サイクルすると書いてありますね。
僕はWebDynoについてはこの挙動はアリだと思っています。
WebDynoが仕事中であるか否かはRouterは把握しているはずなので、Routerが適切にWebリクエストをせきとめてくれるなら少なくとも原理上はリクエストの取りこぼしは発生しませんし、耐障害性を考えてもこのアーキテクチャは優れていると思うからです。

(prebootが早く標準になってほしいというのはありますけど。気になる人は「heroku labs」と叩いてみましょう。(^^v)

しかしWorkerDynoまで同じサイクルで再起動するのはどうなんでしょうね???
ちなみに再起動の方法は以下のドキュメント

https://devcenter.heroku.com/articles/ps#graceful-shutdown-with-sigterm

最初にSIGTERMを送って10秒待っても終了しなかった場合はSIGKILLで殺すっていう感じですね。
Workerが仕事中であるかどうかは外部からは知りようがないので夜間バッチなどの長時間かかるタスクを実行中であっても問答無用で再起動がかかりそうです。。。(--

 

★Workerの動作を観察する

んで、実際にWorker( on Playframework1.2.5)を数日間動かしてみて以下のような観測結果を得ました。

  • 再起動間隔は約24時間だが厳密ではなくかなり前後する
  • 予想通り長時間のJobを実行中であっても問答無用で再起動はかかる
  • SIGTERMはRuntime#addShutdownHookで捕まえることができるが、フックしたところでできることがほとんどない

さてさて困ったものです。(--
再起動間隔はざっと見た感じ24時間よりも若干長い傾向があるので仮に最初に午前中にWorkerを開始したとしても時間の経過とともに、夜間バッチの時間帯に再起動がかかるということはありえます。
ていうか、そもそも「Workerは夜間バッチの時間から遠く離れた時間に起動すること」みたいな謎の運用ルールはアウトでしょう。

つまりここまでの結論としては、Workerは

  • 実行に長時間かかる中断不能な処理
  • 処理が途中で中断された場合にやり直しのきかない処理

を扱うには不適ということになってしまいます。。。
マジでかーーー!!!(--

 

★Schedulerを併用する

さて。気を取り直して、どうにかしてこの問題に対処しなければならないわけですが、最初に考えたのはSchedulerでherokuコマンドを実行するというものです。
Jobを動かす時に「heroku ps:scale worker=1」として不要になったら「heroku ps:scale worker=0」とするという作戦です。
この方法にはWorkerのdyno時間を節約できるというメリットもあります。

Schedulerで実行できるコマンドは「heroku run bash」で確認できるのでとりあえず試してみます。

 

>heroku run bash
Running `bash` attached to terminal... up, run.1
~ $ heroku ps
bash: heroku: command not found
~ $

 

あ~。。。(--
heroku環境にherokuコマンドはないようです。。。。
時間帯によるWebDynoの増減とか割と用途はある気がするんだけどなぁ。。???(--

ちなみにJavaのHerokuAPIを入れるとそれはちゃんと動きました。
ひょっとするとSSHの鍵から入れないといけないんじゃないかと憂鬱だったけどそれは必要ないらしい。(gitは入っているので、そこで必要なんだと思う。)

でもAPIキーをどっかから取ってきて、HerokuAPIを実行するプログラムを書いて、とちょっと面倒くさい。。。(--

□□□□

次にやったのはplayコマンドをworkerとして起動していたframeworkIDを指定して実行するという方法。

 

play run --http.port=$PORT --%worker

 

当たり前だけどこっちはちゃんと動きます。
これでWorkerとして定義したJobは実行できるようになったけど、Schedulerは永続的なプロセスではないのでJobが終了したらPlayをシャットダウンするように修正しないといけません。もうこの際Jobが終了したらそこでstopしてしまえば良いでしょう。

実際にテストで使用したクラスはこれ

 

import play.jobs.Job;
import play.jobs.OnApplicationStart;
import play.Play;
import java.util.Date;

@OnApplicationStart
public class HerokuTest extends Job {
	
	public void doJob() {
		if ("worker".equals(Play.id)) {
			System.out.println("framework id: " + Play.id);
			System.out.println("Job start: " + new Date() + ", " + Play.id);
			try {
				Thread.sleep(5 * 60 * 1000);
			} catch (InterruptedException e) {
				System.out.println("Job Interrupted: " + new Date() + ", " + Play.id);
			}
			System.out.println("Job end: " + new Date() + ", " + Play.id);
			new Thread() {
				public void run() {
					Play.stop();
					System.exit(0);
				}
			}.start();
		}
	}

}

 

stopするのに新たにスレッドを作っているのはOnApplicationのJobはPlay#start内で動くのでそこを抜けてから終了したいからです。(Play#startとstopはいずれもsynchronizedメソッドなのでstartを抜けるまでstopはブロックします。)

スケジューラのドキュメントによると数分を越えるような長い処理はWorkerを使えとありますが、たいていの場合はこれで十分でしょう。
ていうかWorkerが使えないからこんなことやってるんだっちゅーの(--

 

★まとめ

herokuのWorkerは良い仕組みだと思いますが、ちょっと惜しい感じです。
多くの場合Workerでは再起動のタイミングまでコントロールしたい気がします。(HerokuAPIを使ってアプリの中から制御するということもできそうですけど)

あとSchedulerでherokuコマンドは是非使えるようになってほしい!
いつだかのミートアップであった夜間はDynoの数を減らしたいという要件はこれができれば解決という気がします。

2012年10月17日 (水)

Solr4.0のデフォルトのschema.xmlを読む

こんにちは。

前回Herokuで全文検索事情について書きましたが結局は自前でSolrのサーバを立てることになりそうです。

Herokuには前回とりあげた以外にもElasticSearchのラッパーが現在ベータ版のAddOnとしていくつかあるんですが、多分どれも似たり寄ったりです。(--

結局のところ日本人スタッフのいない環境で作成された全文検索サービスはもれなく日本では使い物にならん!という結論に達しました。(^^;;;

□□□□

そんな訳で最近よくSolrをいじっているわけですが、日本語での全文検索エンジンを構築する場合に早い段階で意思決定しなければならない事柄の一つに単語分割にN-gramと形態素解析のどちらを使用するか?という命題があります。

この両者がどういうアルゴリズムであるか?またそれぞれにどういうメリット・デメリットがあるか?という点については多くのサイトで解説されているのでそれらのサイトを参照してもらえば良いかと思います。
ここではSolrに標準でバンドルされているschema.xml(example/solr/collection1/conf/schema.xml)から、実際にどのように文章が分割されインデックスされるのかを掘り下げてみようと思います。

 

★N-gram

schema.xmlの中でN-gram(厳密には2文字分割のBi-gram)の定義は「text_cjk」という名前のfieldTypeで行われています。

以下にその定義を示します。

 

    <!-- CJK bigram (see text_ja for a Japanese configuration using morphological analysis) -->
    <fieldType name="text_cjk" class="solr.TextField" positionIncrementGap="100">
      <analyzer>
        <tokenizer class="solr.StandardTokenizerFactory" />
        <!-- normalize width before bigram, as e.g. half-width dakuten combine  -->
        <filter class="solr.CJKWidthFilterFactory" />
        <!-- for any non-CJK -->
        <filter class="solr.LowerCaseFilterFactory" />
        <filter class="solr.CJKBigramFilterFactory" />
      </analyzer>
    </fieldType>

 

定義ファイルのそれぞれの要素や属性の詳細な解説はパスします。
ここでは「tokenizer」が単語分割を行うクラスの指定、「filter」が分割された単語のフィルタリングや正規化を行うクラス、という程度の理解があれば十分です。(というか、そもそもちゃんとドキュメント読んでないので僕の理解もその程度です。。。(^^;;;)

さて、この定義を見ていくとまず先頭のtokenizer定義でStandardTokenizerFactoryという全く特殊性の感じられないTokenizerが使用されていることがわかります。
実際、このTokenizerは英文などのホワイトスペース区切りの単語分割でも使用される最も一般的なTokenizerです。日本語の文章に対してこのTokenizerを適用した場合は英文や連続するカタカナなどは1単語として認識されますが、それ以外のひらがなや漢字などはすべて1文字1単語として分割されます。

実際にBi-gramを作成しているのは一番最後に定義されているCJKBigramFilterFactoryです。(つまりFilterで単語分割位置を変更するというややトリッキーな実装になっている)
ものの本によると昔はCJKTokenizerFactoryというのがあって、いきなりN-gramを作っていたようですが多分今の構成の方が後続のFilterを適用しやすいのでこのような実装になっているのではないかと思います。

間に挟まっている2つのFilterの役割は以下です。

 

CJKWidthFilterFactory

半角カナは全角に、全角英数字は半角に正規化します。

 

LowerCaseFilterFactory

英大文字をすべて小文字に正規化します。

 

要するに半角全角の違いや大文字小文字の違いはインデックス作成の際に吸収されており、検索者は気にする必要がないということです。

 

★形態素解析(Kuromoji)

次に形態素解析の定義を示します。
コメントが多いので削ろうか迷いましたが、これだけで定義内容がわかるほどの情報量があるのでそのまま残しました。

 

    <fieldType name="text_ja" class="solr.TextField" positionIncrementGap="100" autoGeneratePhraseQueries="false">
      <analyzer>
      <!-- Kuromoji Japanese morphological analyzer/tokenizer (JapaneseTokenizer)

           Kuromoji has a search mode (default) that does segmentation useful for search.  A heuristic
           is used to segment compounds into its parts and the compound itself is kept as synonym.

           Valid values for attribute mode are:
              normal: regular segmentation
              search: segmentation useful for search with synonyms compounds (default)
            extended: same as search mode, but unigrams unknown words (experimental)

           For some applications it might be good to use search mode for indexing and normal mode for
           queries to reduce recall and prevent parts of compounds from being matched and highlighted.
           Use <analyzer type="index"> and <analyzer type="query"> for this and mode normal in query.

           Kuromoji also has a convenient user dictionary feature that allows overriding the statistical
           model with your own entries for segmentation, part-of-speech tags and readings without a need
           to specify weights.  Notice that user dictionaries have not been subject to extensive testing.

           User dictionary attributes are:
                     userDictionary: user dictionary filename
             userDictionaryEncoding: user dictionary encoding (default is UTF-8)

           See lang/userdict_ja.txt for a sample user dictionary file.

           Punctuation characters are discarded by default.  Use discardPunctuation="false" to keep them.

           See http://wiki.apache.org/solr/JapaneseLanguageSupport for more on Japanese language support.
        -->
        <tokenizer class="solr.JapaneseTokenizerFactory" mode="search" />
        <!--<tokenizer class="solr.JapaneseTokenizerFactory" mode="search" userDictionary="lang/userdict_ja.txt" />-->
        <!-- Reduces inflected verbs and adjectives to their base/dictionary forms (辞書形) -->
        <filter class="solr.JapaneseBaseFormFilterFactory" />
        <!-- Removes tokens with certain part-of-speech tags -->
        <filter class="solr.JapanesePartOfSpeechStopFilterFactory" tags="lang/stoptags_ja.txt" enablePositionIncrements="true" />
        <!-- Normalizes full-width romaji to half-width and half-width kana to full-width (Unicode NFKC subset) -->
        <filter class="solr.CJKWidthFilterFactory" />
        <!-- Removes common tokens typically not useful for search, but have a negative effect on ranking -->
        <filter class="solr.StopFilterFactory" ignoreCase="true" words="lang/stopwords_ja.txt" enablePositionIncrements="true" />
        <!-- Normalizes common katakana spelling variations by removing any last long sound character (U+30FC) -->
        <filter class="solr.JapaneseKatakanaStemFilterFactory" minimumLength="4" />
        <!-- Lower-cases romaji characters -->
        <filter class="solr.LowerCaseFilterFactory" />
      </analyzer>
    </fieldType>

 

TokenizerはKuromojiという形態素解析エンジンを利用したJapaneseTokenizerFactoryです。userDictionary属性でユーザー辞書を指定することができます。(サンプルとしてバンドルされているユーザー辞書には「朝青龍」とか定義されていてちょっと和みます。)

以下次の順序でFilterが適用されていきます。

 

JapaneseBaseFormFilterFactory

このFilterは動詞などの活用形を正規化します。
例えば(動詞と判定された)「し」を「する」に変換するみたいな。

 

JapanesePartOfSpeechStopFilterFactory

不要な品詞を削除します。
どの品詞が不要かはtags属性で指定したファイル内に記述します。
サンプルとしてバンドルされているファイルでは助詞、助動詞、接続詞、記号が削除されるようになっています。

 

CJKWidthFilterFactory

N-gramでも使用されていた半角カナと全角英数字を正規化するFilterです。

 

StopFilterFactory

words属性で指定されたファイルに記述されている単語を削除します。
サンプルとしてバンドルされているファイルでは「その」とか「そして」などのおよそ検索に使用されそうにない単語が100個程度定義されています。

 

JapaneseKatakanaStemFilterFactory

カタカナの最後の長音を削除します。ただし文字数がminimumLengthに満たないものでは削除されません。
例えば「ユーザー」は「ユーザ」に正規化されますが「コピー」はそのままです。

 

LowerCaseFilterFactory

N-gramでも使用されていた英大文字を小文字にするFilterです。

 

★考察

ここまで見てきた通りN-gramより形態素解析の方がきめ細かい設定が可能です。

ここではとりあげなかった有用そうなFilterとしてSynonymFilterという単語の同一視が可能なFilterもありますが、これもN-gramでは使用できません。

直観的には形態素解析の方が精度が高そうな気がしますが、品詞の削除などによって元の文章がインデックス作成時に破壊されているという点は大きなポイントだと思います。
例えば人名や書籍のタイトルなどを対象とする場合はN-gramの方が向いているように思います。

SolrではFieldTypeの定義によってどのように文章が分割されるのかが管理ツールで簡単に確認できます。そのため開発中には辞書や定義ファイルを変更しながらチューニングを行うことも可能ですが、その場合インデックスの再構築が必要なはずなので扱う文書量が多い場合は運用中に変更することは難しいかもしれません。

ここから先は実際に開発を始めてみないと何とも言えないですね。(^^;;;

2012年10月 4日 (木)

Herokuの全文検索事情

こんにちは。

Herokuで全文検索(当然日本語)を行う場合にどういう選択肢があるのか調査したのでそのレポートを書いてみます。

 

★評価のポイント

Herokuには複数の全文検索Addonがあり、またPostgreSQLにも全文検索の機能があるのですが今回評価のポイントとしたのは以下の2点です。

 

・日本語に対応しているか?

全文検索は英語などのヨーロッパ圏の言語と、日本語などのアジア圏の言語(CJK)では実装の難易度が大きくが異なります。

英語なんかは単語がスペースや改行などのホワイトスペースで区切られているので、単語の分割で悩む必要がないんですね。一方の日本語の文章は基本的に切れ目なく連続して記述されるのでどうにかして単語を分割しなければなりません。

この単語分割の方法には「形態素解析」と「N-gram」という2つの有力なロジックがあってそれぞれに特徴があるのですが、とりあえずそこはまぁどちらでも良いです。

問題なのは欧米圏で作成されている全文検索のサービスは往々にしてホワイトスペース区切りの英文分割にしか対応していないということです。(--
なので全文検索対応を謳っている製品であっても初手からアウトということは結構あります。

 

・セキュリティ

調査を始めてちょっとびっくりしたことなんですが、全文検索業界(?)のセキュリティ対策はとんでもなくザルです。(--

ほとんどすべてのサービスがREST形式のWebAPIで操作を行うんですが、驚いたことに何の制限もかかっていません。
つまりURLさえ知っていれば誰でもインデックスにアクセスできてしまう訳です。

検索APIがどこからでも使えるのはまぁ良いかと思えるんですが、更新APIまでアクセスフリーなのってアリっすか???

誰かが勝手にインデックスを更新したり削除したりできるサービスというのはちょっと怖くて使えないと思うんですけど。。。

 

以降この2点を中心に評価レポートを書いていきます。

 

PostgreSQLの全文検索

HerokuはPostgreSQLのバージョンアップにはかなり良いペースでついて行っていると思います。2012年10月現在HerokuのPostgreSQLのバージョンは9.1.6(9.1系の最新)です。
この9月には9.2が出たのでこれも近いうちに追随すると思われます。

なので、9.1で入ったN-gram対応の全文検索が使えるはずです。。。

。。。が!、現在この機能を日本語圏で使用する場合はソースの一部をコメントアウトしてリビルドしなければならないらしいです。(これもかなりビックリしましたが。。。)

configパラメータすら変更できないHerokuではまぁ無理ですね。。。(--

 

WebSolr

Solrベースの全文検索サービスです。
4月のHeroku Meetupの時に中の人が来て宣伝してました。(^^;

その時には「Solr3.6からKuromojiという形態素解析エンジンが使える。それを使えば日本語の形態素解析も使えるようになる。WebSolrはまだSolrのバージョンアップをしていないが近いうちにやるつもりだ」というようなことを話していたと思いますが、いまだにKuromojiは使えないようですね。。。
N-gramでの検索は問題なく通りました。

セキュリティは困ったことに検索、更新APIともにアクセスフリーです。(--
これについてはサポートフォーラムに質問があがっていて、今作っているところだという回答もありますが、どうなっていることやら。。。

なんとなくですがスタッフまで含めて数名でまわしている気配を感じるので、あんまり多くは期待できない気がします。(これは今回調査したHerokuのAddonベンダーすべてについて感じた感想でもあります。)

あとWebの管理コンソールが貧弱なのもなんとかしてほしい。
せめて検索のテストは管理コンソール上からできるようにしてほしいです。

スキーマの設定については一応Solrのschema.xmlを丸ごと貼り付けることができるのですが、今のUIのままだとKuromojiに対応してもユーザー辞書の設定やStopWordsの設定とかができない気がします。

 

Searchfy Hosted Search

Index TankというサービスをラップしたAddonです。
これもSolrのようです。

日本語対応はおそらくN-gram。管理コンソールで検索のテストもできますが、設定可能な項目はWebSolrよりも少ないですね。

そしてこれも検索、更新ともにアクセスフリーです。。。(--

どちらかというとまだWebSolrの方が良いですかね。

 

Flying Sphinx

SphinxはPythonで作られた全文検索エンジンらしいです。
これだけ実際には試しておらずドキュメントを読んだのと日本語の対応状況を検索しただけです。

日本語の対応方法はいくつかのサイトで解説されていますが、ソースを変更しないといけないのでHerokuのアドオンでは無理なんじゃないかと思っています。(N-gramには標準で対応しているかもしれませんけど。。。)

APIアクセスにはヘッダにAPIキーを含める必要がありますが、NonceやHashとの組み合わせではないので、URLさえ知っていればアクセスできるというのとあんまり変わらないような気もしています。

試さなかったのはJava用のクライアントライブラリが用意されておらず、自分でREST APIのラッパーを書くのが面倒だったからですが他に良いのがなければまた戻ってきます。

 

Amazon Cloud Search

HerokuのAddonではないですが、AWSにもCloud Search(Beta)という全文検索のサービスがあったので試してみました。

が、日本語対応されておらずあえなく終了。。。(--

APIアクセスに関してはアクセス可能なIPアドレスの範囲を制限できるのですが、Herokuから使う場合Dynoが再起動する度にIPが変わるので使えない気がします。

ちなみに検索をかけていたら自力で日本語を分割して使用するというツワモノがいました。

自力でのワード分割は考えたことありませんでしたがアリかもしれません。

 

★自力でEC2にSolrを立てる

思考実験です。

Solrのサーバーを自分で立てるのは難しくありません。
EC2に入れてWebAPIとしてアクセスできるようにするまではすぐだと思います。

この場合、日本語対応は自力で形態素解析でもN-gramでもどちらでも自由に設定できます。

Securityに関してもServletFilterでヘッダをチェックするロジックを入れれば良いだけなので多分どうにでもなる。

ただ障害に備えて冗長化構成を取ることを考えた場合にはどうするのが良いのか迷いますね。。。
マスタ1台とスレーブ2台を用意して参照系はELBを通して常にスレーブのみを参照するようにするのが楽かな?

まぁいずれにしても最後の手段ですね。

 

★PostgreSQLに自力で分割したカラムを追加

思考実験その2です。

AWSのツワモノ記事を見て思いついたんですが、クライアント側でKuromojiを使用して分割した文字列を別カラムに登録するのはアリですね。
クエリー文字列も同様にKuromoji分割すれば複数単語の組み合わせにも対応できます。

形態素解析を行うのはクライアント側のプログラムなので辞書やStopWordの設定も自由自在です。

スコアやファセットが必要ないならこれで十分な気もします。

 

★まとめ

どんなもんでしょうか?(^^;

残念ながら現状では日本語をちゃんと扱える全文検索のサービスはどれもイマイチというのが今回の結論です。

セキュリティに目を瞑ればWebSolrも悪くはないんですが、普通はアウトなんじゃないでしょうか。

正直Solrを使えばWebSolr相当のものを作るのはそれほど難しくないと思うので、日本発のAddonの候補としては悪くないと思いますよ。 > 誰?(^^;

2012年10月 2日 (火)

文字コードのお話のお話

こんにちは。

社内で勉強会をする機会があったのでその資料をSlideShareにアップしました。

http://www.slideshare.net/shunjikonishi/ss-14537848

僕自身は文字コードネタはJIS2004が出たあたりまでは、興味深く追いかけてましたがその後のあまりの混迷ぶりについていけなくなって脱落しました。(^^;;;

例えば製品やライブラリを調査する際にはよくソースコードを読んだりするわけですが、そういうのは深く調べていけばいつかは底にたどり着きます。しかし文字コードはどこまで潜っても底が見えない!そういう意味では技術者向きのネタではないような気もしています。

この資料でははしょっている部分もたくさんあるんですが、文字化けの原因を推測するという目的に対しては十分なんじゃないかと思います。
ご意見、ご感想、誤りの指摘等あれば是非コメントお寄せください。m(_ _)m

□□□□

今回久しぶりに気合を入れて文字コード関連の資料をあさりましたが、実のところそれほど目新しい発見はありませんでした。
Mac OS Xのファイル名で合成文字が普通に使われているのにびっくりしたくらい。

約5年のブランクがあるのにそれほど目新しい発見がないということは文字コード問題がようやく収束に向かいつつあるということなのかもしれません。
JISが新しい規格を提案することはおそらくもうないでしょうし、はやいところUnicode一択の世界になってほしいものです。

その一方でサロゲートペアへの対応は思ったほど進んでないとも感じました。
個人的にはこれはFEPの問題が大きい気がしています。例えばサロゲートペア説明の定番文字「魚花(ほっけ)」。(このブログでも保存できません。。。(--)

Windows7のOffice IME 2007では普通に変換候補として表示されますが、iOS6では候補に挙がってきません。要するに簡単に入力する手段がないからいつまでも普及しない
ただWindowsで入力できるのであればそろそろ「特殊な文字」という言い逃れもできないフェーズに来ていると思うんですけどね。。。。エンドユーザーに対して「できません」が、いつまで通用するのかはかなり怪しいと思っています。

メールに関してはもはや「正しいISO-2022-JP」が復権する可能性はないと思っています。「Shift_JIS」と「Windows-31J」が正しく使い分けられることも多分ないでしょう。
Webに関しては大分Unicode化が進んでいてそうしたことに煩わされる機会も減っているように思いますが、メールはiso-2022-jpで送信する慣習がなかなかすたれないですねぇ。。。(--
誰かが送信メールを各国語に自動翻訳してマルチパートで送ることができるようなメールクライアントを開発すればUnicode化が一気に進むかもしれません。(^^;;;

以上、文字コードの資料を作成してのとりとめのない感想でした。

採用情報

株式会社フレクトでは、事業拡大のため、
Salesforce/Force.comのアプリケーション
開発
HerokuやAWSなどのクラウドプラッ
トフォーム上でのWebアプリケーション開発

エンジニア、マネージャーを募集中です。

未経験でも、これからクラウドをやってみた
い方、是非ご応募下さい。

フレクト採用ページへ

会社紹介

株式会社フレクトは、
認定コンサルタント
認定上級デベロッパー
認定デベロッパー
が在籍している、
セールスフォースパートナーです。
heroku partnersにも登録されています。
herokuパートナー
株式会社フレクトのSalesforce/Force.com
導入支援サービス
弊社の認定プロフェッショナルが支援致します。
・Visualforce/Apexによるアプリ開発
・Salesforceと連携するWebアプリ開発
も承っております。
セールスフォースご検討の際は、
お気軽にお問合せください。
Powered by Six Apart