2020.07.28
MySQLでGeometry型を使ってみた話
こんにちは、印刷のラクスルでサーバエンジニアをやっている石川です。
私の所属するエリアマーケティングのチームでは、ラクスルで提供している印刷のサービスに加えて印刷物を配布するサービスを提供しています。
印刷のラクスルでは様々な印刷物を購入することができますが、印刷後のチラシをお客様のご指定のエリアに配布をするというところが、エリアマーケティングのチームで担当しているシステムで一番独特な部分です。
そんな私たちのサービスで、ポリゴンの刷新プロジェクトを先日リリースしましたのでその取り組みを何回かに分けてご紹介します。
- 1回目:MySQLでGeometry型を使ってみた話
- 2回目:Geometry型をRailsアプリケーションで扱う話
- 3回目:Railsで緯度経度の距離計算を実装した話
本日は1回目、MySQLでGeometry型を使ってみた話です!
何が問題になっていたか
私たちの提供しているサービスでは、ECサイトから①何を印刷するか、②どこに配布するか、③どうやって配布するかをお客様に指定を指定していただく必要があり、②を指定する手法として以下のように地図画面からエリアを選択していただいています。
ポスティングのシステムでは、この一つ一つのマス目(以下ポリゴンと呼びます)が町丁目(xxx町1丁目、の単位)となっています。このポリゴンデータには2010年の国勢調査のデータが使われており、この数年更新されておらず、実態とずれている場所があるという課題がありました。
また、既存のデータ構造だとポリゴンの外側のアウトライン(下図参照)の緯度経度の点の集合をblob型で保存しているだけだったので、下の図のようにドーナツ型のポリゴンの場合、内側のアウトラインデータは保存できないという課題がありました。
ポリゴンを最新化するぞ!
そこで今回私たちはこのポリゴンを現時点での最新版である2015年の国勢調査のデータに刷新するプロジェクトを立ち上げました。
今回のプロジェクトでは、大まかに以下のようなことをやります。
- 2010年版の町丁目ポリゴンを2015年版に刷新をする
- テーブルの設計を見直し、ドーナツ型のポリゴンも保存できるようにする
Geometry型を試す
テーブルの設計から見直すことにした私たちは、ポリゴンのデータをどうやって保存すべきかを検討することにしました。
どんな形でデータを保存するべきか
これまでのテーブルではポリゴンデータはポリゴンのアウトラインを構成する、緯度経度の点の配列データをblob型に保存したものでした。
私たちのサービスではMySQLのInnoDBを利用しています。MySQL5.6までのInnoDBはGeometry型をサポートしていませんでしたが、MySQL5.7からはGeometry型が使えるようになっているではありませんか!せっかくなのでGeometry型を検討してみることに。
テーブルの定義
こんな形のテーブルを定義します。
ポリゴンを保存するためのpolygonカラムと、緯度経度から距離検索(次回以降に詳しく紹介します)を行うためのポリゴンの中心点(lat, lng)カラムを定義しています。
CREATE TABLE `polygons` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `polygon` geometry NOT NULL, `lat` float NOT NULL, `lng` float NOT NULL, PRIMARY KEY (`id`), KEY `index_town_polygons_on_lat_and_lng` (`lat`,`lng`), ) ENGINE=InnoDB AUTO_INCREMENT=230285 DEFAULT CHARSET=utf8mb4;
polygonは、ポリゴンの幾何オブジェクトを保存するWKT(Well-Known Text)形式のカラムで、以下のようなデータが保存されます。
POLYGON((0 0,10 0,10 10,0 10,0 0))
Polygonクラスについて
MysqlのGeometry型は、空間データ(緯度経度や住所など地理的位置を手がかりに、位置に関する情報を持ったデータ)を表現するためのデータ型で、保存する幾何オブジェクトの特性によって、扱えるオブジェクトには様々な種類があります。
今回は地図のポリゴンデータを扱いたいので、Polygon形式のデータをGeometryに格納します。
Polygon形式と言っても、データの構造としては以下のように非常にシンプルな形になっており
- 連続した点の集合でポリゴンのアウトライン表す(点は直線補完される)
- 1つのPolygonでは複数のアウトラインを表すことができ、一番外側のアウトラインをExteriorRing, ExteriorRingの内部に含まれるアウトラインをInteriorRingを呼ぶ(ドーナツの内側の部分)
- 1つのPolygonには複数のInteriorRingを含めることができる(これにより、複数の穴があるようなポリゴンが1つのカラムで表現可能!)
例えば、ドーナツ型のポリゴンを表現するにはこのような形でGeometry型にデータを保存すればOKです。
POLYGON((0 0,10 0,10 10,0 10,0 0),(5 5,7 5,7 7,5 7, 5 5))
さらに、MySQLではPolygonのプロパティー関数として以下の機能を提供してくれます。
- ExteriorRingを抽出する
- N番目のInteriorRingを抽出する
- InteriorRingの数をカウントする
- ポリゴンの面積を算出する
まとめ
今回の記事では、GeometryのPolygonオブジェクトについて紹介しました。
Geometry型を採用することで、ドーナツ型のポリゴンデータが1つのカラムで表現できるようになりました。
次回以降の記事もお楽しみに!
MySQLでGeometry型を使ってみた話
Featured posts
in #Technology