MapReduce的ベクトルタイル作成(地価公示)Pt. 1
UNIXのsortを使って、TileStacheよりも原理的に早く、ベクトルタイルを作成する。狙うは、国土数値情報(地価公示)。小分けにして記録していく。これはその1回目。
原理
mapの出力でありsortの対象のデータは、古き良き「行指向」データである。形式は次の通り。
[z,x,y,payload].join("¥t"), "¥n"
reduceの結果として作成するデータはGeoJSONを想定するので、payloadは、GeoJSONのfeatureに対応するデータとする。タイル作成の処理コマンドは次のようにしていく。
$ ruby map.rb | sort | ruby reduce.rb
データ入手
国土数値情報 地価公示データの詳細からデータを入手する。平成25年度全国データを選択。3.54MB。展開すると、L01-13.shpが入手できる。
map.rb
map.rbを次のように作成した
require 'find' require 'json' require 'rubygems' require 'geo_ruby' require 'geo_ruby/shp' include GeoRuby::Shp4r module Math def self.sec(x) 1.0 / cos(x) end end def process(r, z) n = 2 ** z lon_deg = r.geometry.x lat_rad = r.geometry.y * 2 * Math::PI / 360 x = n * ((lon_deg + 180) / 360) y = n * (1 - (Math::log(Math::tan(lat_rad) + Math::sec(lat_rad)) / Math::PI)) / 2 prop = {} r.data.attributes.each {|k, v| prop[k] = case v when 'true' true when 'false' false else s = v.encode('UTF-8', 'CP932') /^\d*$/.match(s) ? s.to_i : s end } f = {:type => 'Feature', :geometry => {:type => 'Point', :coordinates => [r.geometry.x, r.geometry.y]}, :properties => prop} print [z, x.to_i, y.to_i, JSON.dump(f)].join("\t"), "\n" end ShpFile.open('L01-13.shp') {|shp| shp.each {|r| 18.upto(18) {|z| process(r, z)} } }
実行例
$ ruby map.rb 18 221474 112784 {"type":"Feature","geometry":{"type":"Point","coordinates":[124.149335,24.346996],"properties":{"L01_001":5,"L01_002":2,"L01_003":5,"L01_004":2,"L01_005":"西暦 2013","L01_006":62800,"L01_007":1,"L01_008":false,"L01_009":false,"L01_010":false,"L01_011":false,"L01_012":false,"L01_013":false,"L01_014":false,"L01_015":false,"L01_016":false,"L01_017":47207,"L01_018":"石垣","L01_019":"沖縄県 石垣市新栄町70番12","L01_020":208,"L01_021":"住宅,店舗","L01_022":0,"L01_023":"RC2","L01_024":true,"L01_025":false,"L01_026":true,"L01_027":"美崎町バスターミナル","L01_028":1200,"L01_029":"近商,都市","L01_030":80,"L01_031":200}}} 18 221480 112785 {"type":"Feature","geometry":{"type":"Point","coordinates":[124.157169,24.345613],"properties":{"L01_001":0,"L01_002":2,"L01_003":0,"L01_004":2,"L01_005":"西暦 2013","L01_006":38800,"L01_007":1,"L01_008":false,"L01_009":false,"L01_010":false,"L01_011":false,"L01_012":false,"L01_013":false,"L01_014":false,"L01_015":false,"L01_016":false,"L01_017":47207,"L01_018":"石垣","L01_019":"沖縄県 石垣市字新川喜田盛14番1","L01_020":283,"L01_021":"住宅","L01_022":0,"L01_023":"RC1","L01_024":true,"L01_025":false,"L01_026":true,"L01_027":"美崎町バスターミナル","L01_028":800,"L01_029":"1住居,都市","L01_030":60,"L01_031":200}}} ...
次回
次回は、上記の結果を sort でフィルタしたものを処理させる reduce.rb を解説する。