総務省のデータを使って、緯度経度から市区町村の何丁目までを取り出す

きっかけはこの記事です。
http://qiita.com/masuidrive/items/21a282c7bf54fd6a4985

----

>ここ数年、位置情報を使ったアプリ・サービスが増えましたが、GPSから取得出来る緯度経度だけではデータとして使いにくい事があります。
>
>GoogleのGeocodingサービスなどで、緯度経度から住所への変換ができますが、件数や速度の問題があります。
>
>そこで、国土交通省のデータを元に、緯度経度から住所への変換を行ってみましょう。

今回は、総務省のデータを元に、緯度経度から住所への変換を行ってみましょう。

## 政府統計の総合窓口
- http://www.e-stat.go.jp/SG1/estat/eStatTopPortal.do

ダウンロード先の道順を説明すべきなのですが、実は道順を忘れました・・・。
私は以下をブックマークしています。
http://e-stat.go.jp/SG2/eStatGIS/page/download.html

#Step1：統計調査（集計）を選択
平成22年度国勢調査（小地域）を選択しましょう。

#Step2：統計表を選択（複数選択可能）
右側に何やら項目がいっぱい出てきたと思います。
適当に男女別人口総数及び世帯総数とかを選んでください。
※欲しいデータは小地域のポリゴン情報なので、そのエリアの統計情報はなんでもいいのです。

選んだら「統計表各種データダウンロードへ」のボタンをポチっとしてください。
統計表各種データダウンロードというページが表示されると思います。

#Step3：地域選択
取得したい地域を選びます。
リストボックスですが複数選択が可能です。
仮に北海道札幌市中央区を選択してみましょう。

#Step4：データダウンロード
ダウンロード可能なデータのリンクが表示されます。
統計データとして、選択した札幌市中央区の「男女別人口総数及び世帯総数」がダウンロード可能です。
でも、今回欲しいのは境界データとなります。
どの形式で欲しいかは皆様のお好みですが、今回は「世界測地系緯度経度・G-XML形式」のものをダウンロードしてみましょう。
クリックすると「A002005212010DDXWC01101.zip」というデータがダウンロード出来るはずです。
zipを解凍すると中に「h22ka01101.xml」というデータが入っているはずです。
※ファイル名はダウンロードする形式、地域で変わります。

ちなみに、うまくダウンロードできないっていう方は、ブラウザでJavaScriptが利用可能になっているかを確認してください。それでもうまくいかないときはブラウザを変えてみたりしてみましょう。
※一時期、Chromeでうまくダウンロードできないことがありました。

時々、ダウンロードまでちょっと待たされる時もあります。
あせらず待ちましょう。

## MongoDBのセットアップ
さて、ダウンロードしたデータを何に格納するかという事なんですが、
今回はMongoDBを選択します。自分が使っているからという理由だけです。

セットアップ方法は、環境によっても違うので割愛します。
探せばいっぱい出てくるので許してください・・・。

ここで重要なのは、v2.4以降を使う事です。

なぜv2.4以降なのか？
それは、$geoIntersectsという新しいオペレーターが追加されているからです。

MongoDBは早い時期から地理空間インデックスをサポートしていますが、
近い点を探したり、矩形内の点を探したりといったことが中心でした。

$geoIntersectsを使うと、点と交差しているオブジェクトを検索可能となります。
要するに、座標を指定すると、その座標を含んでいる矩形を検索する事が可能になります。
つまり、ある緯度経度から住所を検索する事が出来るという事です。

今回は2.4.4を使用しました。

## データの取り込み
今回はPHPを使ってみます。MongoDBが使えるPHP環境を各自ご用意ください。
MongoDBドライバーあたりでつまづく事があるかもしれません。
でも大丈夫。世界中の人たちが一度は通った道です。（要するに検索してください。事例はいっぱいあります。）

個人的にCakePHPを勉強中なので、コンソールから呼び出せるシェルを作ってみました。
今回はCakePHPバージョン2.3.6を使用しました。

コードは以下に置いてあります。
https://github.com/hamichamp/cakephp-mongodb-areashell-register

こんな感じで使います。

```
cd /path/to/cakephp/app
Console/cake area register h22ka01101.xml
```


実行するとこんなデータがMongoDBに登録されます。

```
db.areas.findOne();

{
  "_id": ObjectId("51ccfb4daeff866427000000"),
  "KEN_NAME": "北海道",
  "GST_NAME": "札幌市",
  "CSS_NAME": "中央区",
  "MOJI": "北二十二条西",
  "geo": {
    "type": "Polygon",
    "coordinates": [
      [
        [ 141.32808442756, 43.086489717686 ],
        [ 141.32849826202, 43.086189931106 ],
        [ 141.32888347461, 43.085910941125 ],
        [ 141.32928102957, 43.085634088697 ],
        [ 141.3299137151,  43.085193570141 ],
        [ 141.32991340185, 43.085188855547 ],
        [ 141.32990537189, 43.085045811125 ],
        [ 141.32988194884, 43.084629834813 ],
        [ 141.32913822969, 43.084553030273 ],
        [ 141.32864072166, 43.084501904683 ],
        [ 141.32812962799, 43.084454605932 ],
        [ 141.3276909357,  43.084397339069 ],
        [ 141.32715673633, 43.084336135481 ],
        [ 141.32710470274, 43.08479820257  ],
        [ 141.32708042035, 43.085111816898 ],
        [ 141.32708857833, 43.085169201229 ],
        [ 141.32714414276, 43.08527092383  ],
        [ 141.32741124595, 43.085605243866 ],
        [ 141.32742722034, 43.085627737437 ],
        [ 141.32782427229, 43.086145890449 ],
        [ 141.32788514741, 43.086226345645 ],
        [ 141.32808442756, 43.086489717686 ]
      ]
    ]
  },
  "modified": ISODate("2013-06-28T02:56:13.0Z"),
  "created": ISODate("2013-06-28T02:56:13.0Z")
}
```

##地理空間インデックスを作成する
ある地点を指定するとそれを含むエリアを返してくれるように、地理空間インデックスを作成しましょう。

インデックスの作成には以下のコマンドを実行します。

```
db.areas.ensureIndex({ geo: "2dsphere" } )
```

##検索してみよう
正しくインデックスが作成されていれば、緯度経度からエリアを検索する事が可能なはずです。
早速試してみましょう。

今回登録したエリアは北海道札幌市中央区です。
試しに**札幌時計台ビル**の位置を指定して、どんなエリアが返ってくるのかを確認します。
ちなみに、札幌時計台ビルの住所は**北海道札幌市中央区北１条西２丁目**です。

まず、GoogleMapで位置を確認します。
https://maps.google.co.jp/maps?q=43.06311+141.35348
緯度経度としては北緯43.06311、東経141.35348の位置っぽいですね。

では、MongoDBでその位置を指定して検索してみましょう。
検索コマンドはこんな感じです。

```
db.areas.find({geo:{ "$geoIntersects": { "$geometry": { "type": "Point", "coordinates": [ 141.35347, 43.06311 ]}} }} );
```

結果はこうなりました。

```
{
  "_id" : ObjectId("51ccfb66aeff866427000113"),
  "KEN_NAME" : "北海道",
  "GST_NAME" : "札幌市",
  "CSS_NAME" : "中央区",
  "MOJI" : "北一条西２丁目",
  "geo" : {
    "type" : "Polygon",
    "coordinates" : [
      [
        [ 141.352972957864, 43.0634023736146 ],
        [ 141.353744729415, 43.0635133528866 ],
        [ 141.354578860156, 43.0636236896466 ],
        [ 141.354826623582, 43.0624630766765 ],
        [ 141.354993733154, 43.0618615167524 ],
        [ 141.353423531985, 43.0616286708429 ],
        [ 141.353254226241, 43.0622482860281 ],
        [ 141.353130068628, 43.0628367470057 ],
        [ 141.352972957864, 43.0634023736146 ]
      ]
    ]
  },
  "modified" : ISODate("2013-06-28T02:56:38Z"),
  "created" : ISODate("2013-06-28T02:56:38Z")
}
```

ちゃんと**北海道札幌市中央区北１条西２丁目**を返してくれましたね！

いかがだったでしょうか。
意外と簡単にできますので、よかったら試してみてくださいね。

実は、データをダウンロードするのが、一番手間がかかります・・・。