blogを書けなくて(MTが再構築できなくて)もう1ヶ月ぐらい前に作ったものになるけど、春休みにRuby on Railsのお勉強をしていて、その最終成果物としてGoogleEarth上でFlickrのGeoTag付き写真を見れるサービスを作ったのでまとめておく。

ついでに、緯度経度でFlickrの写真を検索できるAPIも公開してある。

screen-capture.png

■実装方法

1.Flickrのタグ検索で、geotagが付いている写真を定期的にクロールしてきて、写真のURL、緯度経度をRailsのDBに溜める(photo modelに溜める)

2.GETパラメータで緯度経度をRailsに渡して、photo modelを検索する

3.検索結果をGoogleEarthで表示できるように、kml出力のViewを作る

4.GoogleEarthで視点が変わる毎にサーバーに問い合わせて、返ってきたkmlを表示するkmlを作る

5.mongrelでRailsを動かして、apache2のmod_proxy_balancerでRailsのURLをサブディレクトリに見せかける

こんな感じで。一番時間がかかったのが1のクローラの実装で、これは俺がRuby初心者すぎて2日ぐらいかかった。あとは、デンマーク行きの飛行機と帰りの空港からのバスでやったので5時間ぐらい。この辺は、データを溜めて、クライアントからのリクエストに基づいてフォーマットを決めて吐き出す部分が最初からできてるRailsのおかげ。

■1.geotag付き写真クローラ

まずFlickrはタグ検索ができるけど、数値じゃなくて「〜〜を含む文字列」としてしか検索できないので、例えば「北緯35度東経135度周辺の写真が欲しい」という時は使えない。なので、あらかじめメタデータを集めておいて、数値として範囲を指定して検索できるようにしておく。

geotagは小数点ありの値(geo:lat=35.2341など)なんだけど、普通にgeo:latやgeo:lonを含む写真一覧をFlickr APIから検索しても小数点無しのタグしか手に入らない。

小数点ありのタグを手に入れるために、Net::FlickrでFlickrAPIからタグ検索して、

Net::Flickrで全public photoからタグ検索 – shokaiの日記

“geotagged”タグを含む写真をリストアップして、それから再度photo_idを使ってFlickrAPIのphotos.getInfoメソッドを使ってtagのraw attributeを見なければならなかった。

s.h.log RubyでFlickr APIのphotos.getInfoを呼ぶ

クローラ自体はRailsで実装されていなくて、ActiveRecordだけを使ってcronで1時間毎に実行されている。

s.h.log RailsなしでActiveRecordだけ使って、SQLiteを読み書きする

SQLiteのファイルがRailsと共有されているだけ。今回は、Rails側からの書き込みが無いので特に問題は起こらないだろうと判断した。

いまのところ10万枚の写真が集まった。SQLiteのファイルが欲しい人はあげます。

あと、クローラは連続でHTTPアクセスするとFlickrに悪い気がするので、適当にsleepを入れてみてるんだけど、そうすると実行に結構時間がかかる。これが、クローラを作って動かして直して作って…と繰り返す時に面倒だったが、和田さんに言われてscreenをデタッチ/アタッチするという技を覚えた。デタッチしておくと、sshを切断してもクローラが止まらなくて、アタッチしたら普通に続きからできる(もしくは結果が出てる)screenはクローラ作ってるときに重要。

■2.緯度経度をGETパラメータでRailsに渡して検索する

photos.kml?lat=35&lon=135&size=thumb

みたいな形式で、パラメータを渡してDBに溜めた写真を検索する。

KMLを全部出すと多すぎたので、緯度経度を指定してその周囲の写真だけ出す – shokaiの日記

paramsで受け取れる。パラメータ名はシンボルになっているので注意。

controllerで、ActiveRecord::Baseのfind_by_sqlメソッドで普通に検索。(この方法だと四角い。PostgreSQLやMySQLの空間型を使えば丸くできるらしいがとりあえずSQLiteでやる)

そしてmodelの配列をViewに渡してやる。

■3.検索結果をGoogleEarthで表示できるように、kml出力のViewを作る

kml形式のviewを作る。views/photos/index.html.erb を参考にして、index.kml.erbを作ればok

mime-typeにkmlを追加しておく必要があった。

flickrのgeotagついてる写真を収集してたので、kml出力するようにした – shokaiの日記

結果は巨大なkmlになるので、Rails標準搭載のWEBrickだときつい。でかいときはhttpサーバーをmongrelに換える。

MongrelでRailsをデプロイ – shokaiの日記

apache2のサブディレクトリをmongrelで起動してるrailsにプロキシする – shokaiの日記

■4.GoogleEarthで移動する毎に検索するkmlを作る

GoogleEarthの表示を作っているkmlは、静的な表示だけでなく、NetworkLinkタグで別のKMLの内容をURLを指定して読み込める。さらにViewRefleshModeをonStopにすると、画面の移動が止まった時に再読み込みできる。

再読込時に、視点の緯度経度を[lookatLat][lookatLon]で取得できるので、

lat=[lookatLat]&lon=[lookatLon]

としてNetworkLinkで読み込むkmlのURLの後ろにくっつけてやる事で、GETパラメータになる。

GoogleEarthで表示している場所の緯度経度から検索する – shokaiの日記

■5.mongrelでRailsを動かして、apache2のサブディレクトリに見えるようにする

デプロイ。

4まではMac OSX上でやって、ここからは大学院棟に置いたUbuntuに移し替えた。RailsをSQLite+Mongrel環境で動かして、URLをapacheで隠すようにすると、Railsプロジェクトのディレクトリをそのまま移し替えるだけでほぼ動くので超楽。

Flickrのgeotag写真を検索する – shokaiの日記

apache2のサブディレクトリをmongrelで起動してるrailsにプロキシする – shokaiの日記

MongrelでRailsをデプロイ – shokaiの日記

Mongrel入れる – shokaiの日記

———–

こんな感じで、クローラの実装と、バックエンドのサービスとしてAPIを吐くためのRails、というのを覚えた。

今まで戦略的に「長い時間をかけたインタラクション」をするモノや、「データを共有した複数のモノと人とのインタラクション」を作る事を避けていたんだけど(ややこしくてプロトタイピングできないものは作らない方針なので)

Rails使うとサクサクとこのぐらいまではいけるようになったので、自分の得意なフィジカルなデバイス作成と合体させて何か新しい物を作る予定。