fatal error: unsupported/Eigen/MatrixFunctions: No such file or directory
OpenCVをソースからビルドしていて,以下のエラーが出た.
$ cmake .. $ make ... fatal error: unsupported/Eigen/MatrixFunctions: No such file or directory ...
原因はEigenをBitBucketから持ってきて,手動で/usr/local/include
にインストールしていたからだった.
OpenCVは内部にもつEigenをビルドに使用するようだが,パスの通った場所にあるEigenを使おうとしたことによりビルドに失敗したようだ.
OpenCVをインストールするときはEigenをインストールしていないか確認したほうがいい.
mongoのISODateのtimezone問題に対処する
mongodbのISODateはtimezoneに対応してないらしい. いろいろ検証してみて,最後はAggregation Frameworkでどうにかしてみようと思う.
準備
以下のスクリプトを動かすとサンプルデータがmongodbに入る.
データの形式は以下の通り.
日本時間で2013/01/01 00:00:00 から 2013/01/02 23:59:00 の1分おきのデータが入る.
2013/01/01 は火曜日 2013/01/02は水曜日
{ "_id" : ObjectId("52af0bc3090fdd09be0c6ff5"), "gmt_time" : ISODate("2012-12-31T15:00:00Z"), "gender" : "female", "jst_strf" : "2013/01/01 00:00:00" }
Timezone問題
mongodbのISODateは現在のところ,GMTにしか対応していない.
先ほど挿入したデータも,タイムゾーン付きでdatetimeを生成したので,jst_strf
は文字列なので日本時間で挿入されている(2013/01/01 00:00:00 ~ 2013/01/02 23:59:00)
一方で,gmt_time
はTimezone情報が捨てられてしまうのでGMTで挿入されている.(2012-12-31T15:00:00 ~ 2013-01-02T14:59:00)
このコレクションに対して,クエリをかけるときに問題が発生する.
例えば,日本時間の1月1日のデータだけを取り出したいときなどである.
以下のクエリをかけると,当然,GMTに対してクエリがかかるので,日本時間では,2013/01/01 09:01:00 ~ 2013/01/02 08:59:00の結果がかえってくる.
> db.gender.find({gmt_time:{$gt:ISODate("2013-01-01T00:00:00Z"), $lt:ISODate("2013-01-01T23:59:59Z")}}) { "_id" : ObjectId("52af0bc4090fdd09be0c7212"), "gmt_time" : ISODate("2013-01-01T00:01:00Z"), "gender" : "female", "jst_strf" : "2013/01/01 09:01:00" } ... { "_id" : ObjectId("52af0bc4090fdd09be0c77b0"), "gmt_time" : ISODate("2013-01-01T23:59:00Z"), "gender" : "male", "jst_strf" : "2013/01/02 08:59:00" }
そこで,次に考えるのは,クエリに使う時刻に,予め9時間のオフセットを引いておくことだ.
> db.gender.find({gmt_time:{$gt:ISODate("2012-12-31T15:00:00Z"), $lt:ISODate("2013-01-01T14:59:59Z")}}) { "_id" : ObjectId("52af0bc4090fdd09be0c6ff6"), "gmt_time" : ISODate("2012-12-31T15:01:00Z"), "gender" : "male", "jst_strf" : "2013/01/01 00:01:00" } ... { "_id" : ObjectId("52af0bc4090fdd09be0c7594"), "gmt_time" : ISODate("2013-01-01T14:59:00Z"), "gender" : "male", "jst_strf" : "2013/01/01 23:59:00" }
これで,本来取り出したかった2013/01/01 00:01:00 ~ 2013/01/01 23:59:00 のデータが取り出せる.
しかし,何かイケてない
いろいろと使いまわせない感じかする.
後述するアグリゲーションフレームワークを利用した場合,曜日でのクエリをかけることができるのだが,上記の方法だとTimezone問題に対応できない.
aggregation framework
mongodbにはaggregation frameworkというものが存在する.
Aggregations operations process data records and return computed results. Aggregation operations group values from multiple documents together, and can perform a variety of operations on the grouped data to return a single result.
簡単に言うと,レコードに対して処理を行い,計算結果のみを返してくれものらしい.
> db.gender.aggregate({$match:{gender:'male'}}) { "result" : [ { "_id" : ObjectId("52af0bc4090fdd09be0c6ff6"), "gmt_time" : ISODate("2012-12-31T15:01:00Z"), "gender" : "male", "jst_strf" : "2013/01/01 00:01:00" }, ... ], "ok" : 1 }
gender='male'にmatchするものを取り出すというアグリゲーションフレームワークのクエリをかけると,result
というリストに結果のドキュメントが入ってくる.
ソートをする場合は
>db.gender.aggregate({$match:{gender:'male'}}, {$sort:{gmt_time:1}})
リミットをかける場合は
> db.gender.aggregate({$match:{gender:'male'}}, {$sort:{gmt_time:1}}, {$limit:1})
ISODataに対するAggregate
Aggregation Framework Operators - Date Operators
上記のリンクにあるように,Aggregation Frameworkを利用することで,ISODateから,年や月,曜日などを数値として取り出すことができる.
> db.gender.aggregate({$project:{weekday:{$dayOfWeek:"$gmt_time"}}}) { "result" : [ { "_id" : ObjectId("52af0bc4090fdd09be0c7423"), "weekday" : 3 }, .... { "_id" : ObjectId("52af0bc5090fdd09be0c7b34"), "weekday" : 4 } ... ], "ok" : 1 }
このように,gmt_time
から曜日のみを取り出すことが可能だ.
Aggregation Frameworkは処理をつなげることができる(パイプライン処理と呼ばれている)
以下の処理は,曜日が火曜日のドキュメント群のみを取り出す処理である.
> db.gender.aggregate( {$project:{jst_strf:"$jst_strf",weekday:{$dayOfWeek:"$gmt_time"}}}, {$match: {weekday:{$gte:3, $lt:4}}} ) { "result" : [ { "_id" : ObjectId("52af0bc4090fdd09be0c7211"), "jst_strf" : "2013/01/01 09:00:00", "weekday" : 3 }, ... { "_id" : ObjectId("52af0bc4090fdd09be0c77b0"), "jst_strf" : "2013/01/02 08:59:00", "weekday" : 3 } ], "ok":1 }
これは,
jst_strf
とweekday
のみをフィールドにもつドキュメント群をつくる.($project)weekday
が3以上4未満のドキュメント群をつくる($match)
を連続して行っている.
この結果では火曜日のドキュメント群を取り出したつもりなのに,1/1と1/2のドキュメントが混じっている.
ここで,思い出してほしいのは,2013/01/02は火曜日だった.一方,weekdayが3と言うのは火曜日であることを表す.(日=1, 月=2, 火=3,...)
ズレが生じてしまっている.これはweekdayがgmt_dateから計算されているためである.(このドキュメントのISODateは2012-12-31T15:00:00であるため)
本当は月曜日のドキュメントがほしいのに火曜日のドキュメントがとれてしまっている.
対処法
対処法として,以下のリンクを教えてもらった. Timezone support in date operators at query time How to agregate by year-month-day on a different timezone
要は,最初にISODateにTimezone分だけ時間を加算してから,残りの処理を行えばいいらしい.
> db.gender.aggregate( {$project: {jst_strf:"$jst_strf", gmt_time:{$add:["$gmt_time", 9 * 60 * 60 * 1000]}}}, {$project:{jst_strf:"$jst_strf",weekday:{$dayOfWeek:"$gmt_time"}}}, {$match: {weekday:{$gte:3, $lt:4}}} ) { "result" : [ { "_id" : ObjectId("52af0bc3090fdd09be0c6ff5"), "jst_strf" : "2013/01/01 00:00:00", "weekday" : 3 }, ... { "_id" : ObjectId("52af0bc4090fdd09be0c7594"), "jst_strf" : "2013/01/01 23:59:00", "weekday" : 3 } ], "ok":1 }
これで正しくとれた!
{$project: {jst_strf:"$jst_strf", gmt_time:{$add:["$gmt_time", 9 * 60 * 60 * 1000]}}},
このように,あらかじめISODateを日本の時差の分だけずらしたあとにクエリをかけて上げればよい.
まとめ
mongoのtimezoneで困ったらAggregation Frameworkを使いましょう.
次回以降,mongoのC++ DriverでAggregation Frameworkを触ることについて書いてみようかなと思います.
Fluentd Casual Talks #3いってきた
Fluentd Casual Talks #3にいってきたので感想を残しときます.
@tagomoris さん
Norikraのfluentプラグインのお話. Norikraというのとfluentdを連携してSQLチックにフィルタリングしてゴニョゴニョできるらしい.
一定時間ごとにGroupしてcountしたり,ネストされたハッシュのSELECTとかもできるらしい.
in_norikara/out_norikara は大規模向けを意識したもので,1台でやるならout_norikra_filterでOKらしい
試してみよう.
@sonots さん
Haikanko Yohoushi ってのを作ってるらしい.うまく使えれば運用が楽になりそうかな.社内の人にも使ってもらえるかな.とか思ったり.
Denaでは最大で1秒に10万行のログがfluentdで流れるらしい!
シャドウプロキシサーバをfluentdでもやったら良い感じっていうお話だった.性能評価をちゃんとやってらっしゃった.
@stanaka さん
LTSVと2014年のウェブシステムアーキテクチャの人.すごい.
Go のgo routineよさげ
Go早そう
GoでopenCVつかいたい
@okahashi117 さん
fluentdをWindowsでも使えるようにした話.
Windowsのコマンドプロンプト久々にみた.
直接話す機会があったので話をきいたら,大企業のシステムだとか,Windowsで実装されたセンサなどの需要が結構あるらしい.なるほど.
@kzk_mover さん
TDのCTOの方
プロダクションにfluentdいれるなら,ちゃんとモニタリングしなきゃなーと痛感した(実際,昨日落ちてた)
TreasureDataでtd-agentのモニタリングサービスを始めるらしい(しかも無料!)ので使ってみたいなー
@frsyuki さん
スライド すごい人.若い.
v11で無停止再起動とかできるらしい.
v11のライブリリース.
これ読んだら幸せになれそうだった.
Flaskでltsv形式のログを出してみた.(リベンジ)
前回つくった,Flaskのltsvロガーがイケてなかったので,リベンジ.
今回は辞書を渡すようにしたので,使いやすくなったはず.
Flaskでltsv形式のログを出してみた.
前置き
最近,いろいろな問題に直面して,ログの重要性を実感しました.そのため,複数のサーバに分散したログを収集する試みを行っています.
その際使用しているのがfluentdです.
fluentdの説明は割愛しますが,以下の記事が参考になると思います.
実運用上では,アプリケーションからファイルへ出力されるログをfluentでtailして収集することが多いと思います.
その際,ログを正規表現でパースしてあげる必要があるのですが,組み込みのフォーマットであれば,正規表現を書く必要がありません.
この組み込みフォーマットには以下のものが有ります.(参考: fluentd/lib/fluent/parser.rb - Githubより)
この中でアプリケーションで利用することを考えると,json
tsv
ltsv
csv
に絞られます.
ltsv
形式は,かなり新しい形式らしく,tsv
にkeyをつけたものらしいです.
LTSV FAQ - LTSV って何? どういうところが良いの?を参考にするといいと思います.
fluentdはログをJSON形式で保持します.上記の4つの中で,key-value形式になっているものはjson
とltsv
です.
tsv
csv
はkeyを持たないため,fluentdの設定で,tailしてきた内容に対して,keyを割り当てなければなりません.
この際問題になるのが,ひとつのログファイルで一貫して同じ形式のログを出力しなければならないことです.ログの要素数を可変にしたい場合にはこれらは向きません.
残るは.json
とltsv
です.これらは.ログの効果としては同じ能力を持っていると言えます.(多分)
この際の選択基準として.
汎用性を選ぶなら
json
生ログの可読性を選ぶなら
ltsv
かなと思います.
今回は,fluentdの運用をうまくできるか不安だったので,生ログでも見やすいltsv
を選択しました.
本題
で.本題ですが,Flaskでltsvのログを出力しているサンプルが見当たらなかったので.作りました.とはいっても,通常のPython loggingと同じですね.
出力:
time:2013-12-04 01:17:34,780 level:ERROR method:hello_world message:distance value:44
fluentdに読ませつつ.要素数が可変で,可読性を取っておきたいならltsvはいいんじゃないかなと思います.
ちなみに,ltsvでログを取って,fluentd + elasticsearch + Kibana3 の運用もしているので,時間があれば書きたいなぁ.
(追記)
このコードはイケてないのでリベンジした
Boost.Logのエラー
Boost1.54でロガー機能が追加されたらしく,使ってみようとしたところ,
Undefined symbols for architecture x86_64: "boost::log::v2s_mt_posix::record_view::public_data::destroy(boost::log::v2s_mt_posix::record_view::public_data const*)", referenced from: boost::log::v2s_mt_posix::record::reset() in main.cpp.o
リンクできない...
OSは OSX10.9,boostはhomebrewで入れたboost1.54 cmakeでFindPackageしてBoostをリンクしようとしている.
ググッた結果,
に答えが書いてあった....つまり
staticライブラリをリンクしようとして見つからない!
ってことらしい.
解決方法としては,sharedライブラリをリンクする必要があるみたいで,CMakeLists.txt
に
ADD_DEFINITIONS(-DBOOST_LOG_DYN_LINK)
を追記してあげるといいらしい.
あと,つまずきそうなのは,CMakeLists.txt
のFIND_PACKAGE
にlog
を入れるのを忘れちゃった!ってとこな気がする.
忘れないようにせねば.
これで快適Boost.Log生活!