ぐるなび位置情報をMongoDBに保存


久しぶりに会社のブログを書きます。
1年ぶりになるでしょうか。。

最近はMongoDBに興味があって触っています。
MongoDBの紹介兼ねてインストールと、簡単なプログラムを書きました。

MongoDBはトランザクション、テーブルjoin、auto incrementを使えませんが、高速でスケーラビリティな点が注目されているDBです。
MongoDBはJSON形式でデータを扱い、JavaScriptの記述でデータを操作します。

では早速インストール。
ubuntu 10.10だと以下でインストール出来ます。

// 参考: http://www.mongodb.org/display/DOCS/Ubuntu+and+Debian+packages
$ sudo apt-add-repository 'deb http://downloads.mongodb.org/distros/ubuntu 10.10 10gen'
$ sudo apt-key adv --keyserver keyserver.ubuntu.com --recv 7F0CEB10
$ sudo aptitude install mongodb-stable

$ mongo --version
MongoDB shell version: 1.6.4

// 自動起動設定
$ runlevel
N 2
$ sudo sysv-rc-conf

早速位置情報からやってみます。
位置情報はMongoDBのv1.3.3から対応しています。
次の操作は、DBに位置情報を登録し、位置情報として扱うようにIndexを貼り、データの取得を実行します。

$ mongo
> db.map.insert( { loc: {lat:35.705969 , lng: 139.74884} } );
> db.map.ensureIndex( { loc : "2d" } )
> db.map.find( { loc : { $near : [35.705969,139.74884] } } ).limit(20)

次に、PHPでぐるなびの位置情報を収集して、MongoDBに格納する処理。
先にPHPにmongodbのライブラリを導入。

$ sudo pecl install mongo
$ sudo vi /etc/php5/conf.d/mongodb.ini
extention=mongo.so

Services_Gnaviのライブラリは http://lab.totoro.ws/gnavi/ のサイトからダウンロードしました。
– gnavi.php

<?php
require('Services/Gnavi.php');

// -- 設定 --
$access_key = 'ぐるなびアクセスキー';
$rows = 999;
$mongo = new Mongo("localhost:27017");
$db = $mongo->selectDB( "MyDB" );
$col = $db->selectCollection( "gnavi" );
// -- 設定 --

$gnavi = new Services_Gnavi($access_key);

$gnavi->searchSubcategory();
$cate = $gnavi->getResult();
$_cate = $cate['category_s'];

foreach(range(1,47) as $num){
$pref = sprintf("PREF%02d",$num);
$opt = array('pref'=> $pref, 'hit_per_page' => $rows,'offset_page' => 1, 'coordinates_mode' => 2);
print $pref . "n";
foreach($_cate as $r){
$opt['category_s'] = $r['category_s_code'];
$res = getGnavi($gnavi,$opt);
print " " . $opt['category_s'];
if ($res['total_hit_count'] == 1) $res['rest'] = array($res['rest']);
save($col,$res['rest']);
}
print "n";
}
print "Endn";

function save($col,$res){
if (!$res) return;
$fmt = 'name,name_kana,address,tel,pr,code,category';
$fmt = split(',',$fmt);
foreach($res as $row){
$doc = array();
foreach($fmt as $key){
$doc[$key] = $row[$key];
}
// 位置情報
$doc['loc'] = array('lat' => (double)$row['latitude'],'lng'=> (double)$row['longitude']);
$col->insert( $doc );
}
}

function getGnavi($gnavi,$opt){
$gnavi->searchRestaurant($opt);
return $gnavi->getResult();
}

以上でぐるなびの情報がMongoDBに格納できました。

次に、実際にPHPから取得します。
位置情報のパラメーターは以下になります。
$near 現在地から近い位置情報を検索
$box 長方形の範囲内の位置情報を検索
$center 中心から半径の距離に含まれる位置情報を検索

– maps.php

<?php
$mongo = new Mongo("localhost:27017");
$db = $mongo->selectDB( "MyDB" );
$col = $db->selectCollection( "gnavi" );
//$query['loc']['$near'] = array(35.705969,139.74884); // 東京
//$query['loc']['$near'] = array(43.068887774169625, 141.3720703125); // 北海道
$query['loc']['$near'] = array(35.47856499535729, 134.241943359375); // 鳥取
$cursor = $col->find($query)->limit(20);

while( $cursor->hasNext() ) {
var_dump( $cursor->getNext() );
}

とても簡単な記述で、位置情報の取得が出来ました。
コードが簡潔に書けると嬉しくなります。

以上です。

○後日談
ぐるなびの小業態は複数選択可能なパラメータだったので店舗情報が重複していた。
MongoDBには重複した情報をINDEX設定時に削除出来るので、以下の作法で解消。


> db.gnavi.count();
122726
> db.gnavi.dropIndexes();
> db.gnavi.ensureIndex( { name: 1 , address: 1 } , { unique: true, dropDups: true } );
> db.gnavi.count();
58448
> db.gnavi.dropIndexes();
> db.gnavi.ensureIndex( { loc: "2d" } );

  1. No comments yet.
(will not be published)

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)