概要
データ解析をやっていると、「いつ・誰が・何をした」っていう調査は比較的容易に実現できるものだと実感していますが、「どこで」というキーワードを使った解析は意外に難しい気がしています。
スマートフォンからはGPSを使えばそれなりに取れます(やったことはないけど)。
PCのブラウザからとなると、ユーザから申告してもらうか、IPアドレスからおおよその位置を割り出すしかありません。
今回は、IPアドレスと位置情報を結びつける、データ解析用マッピングテーブルをどうにかして作った話です。
なぜ必要か
データ解析するひとの手元には、どんな形であれログがあると思います。多くはApacheとかNginxとかWebアプリケーションのミドルウェアが出力しているアクセスログだと思います。
これに位置情報があらかじめ付与されている場合は、もうその情報を使えばいいと思います。
fluent-plugin-geoip https://github.com/y-ken/fluent-plugin-geoip 使ってもいいと思います。アクセスログがデカくなっていきそうだけど。
今回は、「(位置情報の付与されていない)アクセスログ」と、以下で作成する「データ解析用マッピングテーブル」をJOINして、新しい解析手法を生み出すことにあります。
例えば、
-
- ○○県の20代の男性は、他県に比べて有料会員になりやすい
- △△市に住んでいるユーザは、特定コンテンツに異様に興味を持っている
- □□町に住んでいる女性に、今コレが売れている
などなど。
IPから位置情報を取得するAPIのサーベイ
「IPアドレス 緯度経度 API」とかでググればたくさん出てきます。
- IPinfoDB http://ipinfodb.com/
- geoPlugin http://www.geoplugin.com/
- どこどこ.jp http://www.docodoco.jp/
抱えている問題
freegeoip
freegeoipもIPアドレスから位置情報を取得できるAPIの一つです。
http://freegeoip.net/
無料だし、CSV/JSON/XML形式出力にも対応してる。ただし10000req/hour。
freegeoipの良さはここではないです。
↑のURLの"Limits"に書いてある通り、このシステム、自前のサーバにビルドできるんです。やり放題。
freegeoipのビルド
必要なものはGo/Python/Sqlite/Git。あと少しばかりのやる気と、30分くらいの時間が必要です。
手順も簡単
-
- go get
- go build
- updatedb (pythonで書かれたDB更新用実行ファイル)
- freegeoip (goで書かれたアプリケーション実行ファイル)
これだけ。というかREADMEに全部書いてあるので、その通りにやればよいです。かんたん。
API構築後に発生する課題
API用に割けるWebサーバが潤沢にあるとか、リクエスト投げる回数がそんなでもない、って場合は、上のビルドが終わったらAPIたたけばいいと思います。
そういうわけにいかない人もいるでしょう(というかそういう人ばっかりだと思います)
じゃあfreegeoipのDBにリクエスト投げりゃいいじゃんと思う方もいらっしゃるでしょうが、freegeoipのDBはそう簡単にSELECTクエリ投げられるようにできてないのです。
freegeoipのDBのカラクリ
freegeoipには4つのテーブルがあって、それをJOINすることでIPアドレスと位置情報をマッピングすることができます。詳しいスキーマ構成はDESCRIBEしてください。
このDBは全IPアドレス(約43億)が対象となっているはずなのに、モバイルにも搭載可能なサイズで、しかもSqliteで作られている。
あらかじめデータがグループ化された状態で格納されているからです。
例えば、ロングIPアドレスで 1728421888 から 1728422911 までの場合、だいたい以下の情報が1レコードに含まれています。
-
- 範囲: 1728421888 - 1728422911
- 国: Japan
- 地域: Tokyo
- 町: Ginza
- 緯度: 35.6667
- 経度: 139.7667
この結果、すべてのテーブルをJOINしてDUMPしても、たかだか6万レコードくらいの規模にしかなりません。
MapReduceを使った、IpToGeolocationテーブルの作成
↑のDUMPデータから、シングルプロセスのプログラムにより、ひたすらIPアドレスに対する位置情報のマッピングを行うのは、比較的容易です。
範囲をひたすらforループで展開していけばできます。
今回はデータ解析をしたい(もしくはしている)方が対象なので、大なり小なりの分散処理基盤が手元にある前提で、今回はHadoopに力を借りるとします。
MapReduceを使ってテーブルを作成するのは効率的です。
https://github.com/boscoworks/IpToGeolocation
MapReduceを実行したときのノウハウ
要求されるクラスタ構成
VM7台で構成された技術検証用Hadoopクラスタで試しに実行したら、5台がOSフリーズしてLost Task Trackerになりました。
1Reducerに割り当てられるデータはそんなでもないし、膨大な中間データが生成されるわけでもないので、単純にマシンスペックが要求される仕組みになっていると思います(台数は言えませんがオンプレで構成したクラスタでは順調に動いた)
MapReduceの仕様
1Mapper-65536Reducerの構成で動きます。結果的にデータ量としては6万もいりませんでしたが、やはり1Reducerに割り当てられるデータ量にはかなりのムラがあり、先に述べたLost TT事件にビビったのもあって、慎重に作った感じです。
IPアドレスはドット区切りで4つのデータに分かれていますが、Reducerには上位2階層のIPアドレスごとにデータを割り当てています。なので最大65536(256*256)Reducer。
Reducerでは下位2階層をforループで処理します。この二つの仕様により、1Reducerには最大65536レコードがinputされ、最大65536レコードがoutputされます。
成果
上記のMapReduceは、今僕が使えるクラスタで実行したところ、約20分で処理をしました。
みなさんのお手元のクラスタ構成によっては前後すると思いますが、10分を切るような高性能クラスタをお持ちの方は、積極的にお話を聞かせてください。
レコード的には約6億レコードくらいが生成されました。日によって前後すると思いますが、1億レベルでずれることはないと思います。
で、これは結局多いのか少ないのか・・・・。
更新頻度
MaxMindという会社が管理していて、だいたい1週間に1度は更新されているようです。
IPアドレスに対する情報は日々変化するので、その時々によっての位置情報をトレースしたい場合は、定期的にIpToGeolocationを生成するバッチを作って、cronとかで回せばいいと思います。