MySQLで学ぶGIS入門 20

「Shapefile」で公開されているオープンデータをMySQLに登録してみよう

第20回の今回は、「Shapefile」形式で公開されているオープンデータをMySQLに登録する方法と、「Shapefile」の構成や課題について解説します。

坂井 恵 (さかい けい)

6:30

はじめに

前回はGeoJSONとして公開されているデータをMySQLに登録する方法を紹介しました。今回は引き続き、Shapefileとして公開されているデータをMySQLに登録して活用する方法を紹介します。

今回も、国土交通省の「国土数値情報ダウンロードサイト」からデータをダウンロードして使用します。

データの取得

今回は、POINT型データとして国土数値情報ダウンロードサイトに公開されているデータをダウンロードしてMySQLに登録してみることにします。

前回同様に国土数値情報ダウンロードサイトにアクセスして、「3.地域 - 施設 - 学校(ポイント)」と辿ったダウンロードページへ移動します。この時、ライセンスが「CC_BY_4.0」であることも確認しておきましょう。

全国データはデータサイズが大きくなるので、今回も1つの県を例にして登録作業を体験してみることにしましょう。千葉県のデータを選択してダウンロードします。「P29-23_12_GML.zip」が手元にダウンロードされます。

ファイル内容の確認

ダウンロードしたファイルを展開すると、以下のようなファイルが得られます。

【Zipファイル内のファイル一覧(括弧内はおおよそのサイズ)】

  • KS-META-P29-23_12.xml(11KB)
  • P29-23_12.xml(2.1MB)
  • P29-23_12.geojson(775KB)
  • P29-23_12.cpg(4B)
  • P29-23_12.dbf(1.7MB)
  • P29-23_12.prj(145B)
  • P29-23_12.shp(60KB)
  • P29-23_12.shx(17KB)

「KS-META-P29-23_12.xml」はデータに関する様々な説明が書かれたXMLファイルです。それ以外の「P29-23_12」で始まるファイル名のものがデータの実態です。

前回のおさらいになりますが、このZIPファイルには同じデータが複数のフォーマットで格納されています。拡張子が.xml のファイルがGML形式のデータであり、拡張子が.geojsonのファイルがGeoJSON形式のデータです。それ以外のファイルが、今回採り上げる Shapefile形式を構成するファイル群です。

Shapefileの構成

Shapefileは1つのデータセットを表すために複数のファイルを使用します。まず、それぞれのファイルの役割を解説します。

P29-23_12.shp

ジオメトリデータ本体です。POINTやLINESTRING、POLYGONなどの各種地物の座標情報が格納されるファイルです。今回は学校のポイントデータなので、POINTの座標情報が格納されています。バイナリ形式なので、人間の目で直接読むにはかなりのコツが要ります。

P29-23_12.shx

.shpファイルへのインデックス情報が格納されているファイルです。

P29-23_12.dbf

属性情報が格納されているファイルです。今回のファイルでは、学校名や種別コードなどの情報が入っています。dBase形式なので本来はExcelで内容を確認できるはずなのですが、このファイルはUTF-8で格納されており、Excel側が強制的にShift_JIS(CP932)として解釈して開こうとするため、文字化けしてしまいます。

P29-23_12.cpg

このデータの文字コードを記述したテキストファイルです。後ほど内容を確認してみましょう。

P29-23_12.prj

座標系の定義をWKT形式で記述したテキストファイルです。こちらも、後ほど内容を確認してみます。

Shapefileの構成ファイルの中身を見てみよう

先ほど紹介したShapefile構成ファイルのうち、中身がテキストのファイルを確認してみましょう。

まず、.cpgファイルです。この拡張子は「コードページ(Code PaGe)」の略称だそうです。

$ cat P29-23_12.cpg
UTF8

このファイルの文字コードがUTF-8であることが記されています。ファイル一覧を見た時にこのファイルが 4バイトだけの小さいファイルということは分かっていましたが、このコード情報が入っているのですね。

次に、.prjファイルです。こちらは座標系の情報が記述されています。今回のファイルでは、このShapefileの地理情報がJGD2011であることと、その回転楕円体の形状や本初子午線の情報などが記述されています。MySQLの information_schema.st_spatial_reference_systems テーブルに登録されているものと似たような情報ですね。

$ cat P29-23_12.prj
GEOGCS["GCS_JGD_2011",DATUM["D_JGD_2011",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]]

登録前にこのデータの概要を確認しよう

MySQLに登録する前に、このShapefileのデータの概要を確認してみましょう。前回、GeoJSONファイルで確認したのと同様にogrinfoコマンドを使います。

$ ogrinfo -al -so P29-23_12.shp
INFO: Open of `P29-23_12.shp'
      using driver `ESRI Shapefile' successful.

Layer name: P29-23_12
Metadata:
  DBF_DATE_LAST_UPDATE=2024-03-07
Geometry: Point
Feature Count: 2154
Extent: (139.787172, 34.909794) - (140.859890, 36.088041)
Layer SRS WKT:
GEOGCRS["JGD2011",
    DATUM["Japanese Geodetic Datum 2011",
        ELLIPSOID["GRS 1980",6378137,298.257222101,
            LENGTHUNIT["metre",1]]],
    PRIMEM["Greenwich",0,
        ANGLEUNIT["degree",0.0174532925199433]],
    CS[ellipsoidal,2],
        AXIS["geodetic latitude (Lat)",north,
            ORDER[1],
            ANGLEUNIT["degree",0.0174532925199433]],
        AXIS["geodetic longitude (Lon)",east,
            ORDER[2],
            ANGLEUNIT["degree",0.0174532925199433]],
    USAGE[
        SCOPE["Horizontal component of 3D system."],
        AREA["Japan - onshore and offshore."],
        BBOX[17.09,122.38,46.05,157.65]],
    ID["EPSG",6668]]
Data axis to CRS axis mapping: 2,1
P29_001: String (5.0)
P29_002: String (15.0)
P29_003: String (5.0)
P29_004: String (254.0)
P29_005: String (254.0)
P29_006: String (1.0)
P29_007: String (1.0)
P29_008: String (2.0)
P29_009: String (254.0)

出力結果からは、

  • Point型データであること
  • 件数は2154件であること
  • データの範囲が(139.787172, 34.909794) - (140.859890, 36.088041)内に納まっていること
  • 座標系は JGD2011であること
  • P29_001、P29_002...など9個の属性情報カラムがあること、およびそれぞれの型とサイズ

などを読み取ることができます。

ShapefileをMySQLに登録する

では、この ShapefileをMySQLに登録してみましょう。ogr2ogrコマンドは非常に親切設計になっており、実は前回紹介した GeoJSONファイルを登録する時と使用するコマンドやオプションはまったく同じです。入力ファイルとして与えたファイル名が .geojsonであればGeoJSONとして処理してくれて、.shpであればShapefileとして処理してくれるのです。

ogr2ogr -f "MySQL" \
  "MySQL:thinkit,host=localhost,user=root,password=MyPassWorD" \
  P29-23_12.shp \
  -nln chiba_school \
  -progress

これは、localhostのthinkitデータベースにrootユーザ、パスワードMyPassWorDで接続するコマンドの例です。登録先のテーブルとしてはchiba_schoolテーブルを新規に作成するよう指定しています。入力ファイルとしてP29-23_12.shpを指定しています。Shapefileは複数のファイルで構成されますが、.shpファイルを指定すればogr2ogrが他の構成ファイルも適切に読み込んで処理してくれます。

今回のデータはUTF-8で格納されていましたが、ShapefileはShift JISで公開されているデータも多くあります。その場合は、-oo ENCODING=CP932 オプションを追加することで文字化けせずに取り込むことができます。

登録結果の確認

ogr2ogrコマンドでMySQLに登録できたら、実際に今回登録したchiba_schoolテーブルの内容を確認してみましょう。まず、テーブル構造は以下のようになっています。ogrinfoコマンドで確認した列名が存在していることと、SHAPEという名前のGEOMETRY列が存在していることが分かります。

mysql> DESC chiba_school;
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| OGR_FID | int          | NO   | PRI | NULL    | auto_increment |
| SHAPE   | geometry     | NO   | MUL | NULL    |                |
| p29_001 | varchar(5)   | YES  |     | NULL    |                |
| p29_002 | varchar(15)  | YES  |     | NULL    |                |
| p29_003 | varchar(5)   | YES  |     | NULL    |                |
| p29_004 | varchar(254) | YES  |     | NULL    |                |
| p29_005 | varchar(254) | YES  |     | NULL    |                |
| p29_006 | varchar(1)   | YES  |     | NULL    |                |
| p29_007 | varchar(1)   | YES  |     | NULL    |                |
| p29_008 | varchar(2)   | YES  |     | NULL    |                |
| p29_009 | varchar(254) | YES  |     | NULL    |                |
+---------+--------------+------+-----+---------+----------------+
11 rows in set (0.001 sec)

データの内容も確認してみましょう。SHAPE列が非常に長くなるため、表示対象としないように他の列名を羅列してSELECT文を発行しています(住所および施設名称は筆者がマスクしました)。

mysql> SELECT OGR_FID,p29_001,p29_002,p29_003,p29_004,p29_005,p29_006,p29_007,p29_008,p29_009
   ->   FROM chiba_school LIMIT 5;
+---------+---------+---------------+---------+----------------------+--------------------+---------+---------+---------+---------+
| OGR_FID | p29_001 | p29_002       | p29_003 | p29_004              | p29_005            | p29_006 | p29_007 | p29_008 | p29_009 |
+---------+---------+---------------+---------+----------------------+--------------------+---------+---------+---------+---------+
|       1 | 12205   | A112210000099 | 16011   | 館山市立北●幼稚園   | 千葉県館山市XXXXX  | 3       | 0       | 00      | NULL    |
|       2 | 12205   | A112210000124 | 16011   | 館山市立西●幼稚園   | 千葉県館山市XXXXX  | 3       | 0       | 00      | NULL    |
|       3 | 12205   | A112210000142 | 16011   | 館山市立豊●幼稚園   | 千葉県館山市XXXXX  | 3       | 0       | 00      | NULL    |
|       4 | 12210   | A112210000231 | 16011   | 茂原市立新●原幼稚園 | 千葉県茂原市XXXXX  | 3       | 0       | 00      | NULL    |
|       5 | 12213   | A112210000302 | 16011   | 東金市立城●幼稚園   | 千葉県東金市XXXXX  | 3       | 0       | 00      | NULL    |
+---------+---------+---------------+---------+----------------------+------------------------+---------+---------+---------+---------+
5 rows in set (0.000 sec)

SHAPE列についても、登録されたデータを確認してみます。どの行でも構いませんが、ここではOGR_FID(登録時の連番)が123のデータを例に、ST_AsText()関数でそのデータがPOINTデータであること、またST_SRID()関数で測地系が正しくJGD2011(6668)であることを確認してみました。

mysql> SELECT ST_AsText(SHAPE) g, ST_SRID(SHAPE) srid FROM chiba_school WHERE OGR_FID=123;
+------------------------------------------+------+
| g                                        | srid |
+------------------------------------------+------+
| POINT(35.3732606002438 139.969336057803) | 6668 |
+------------------------------------------+------+
1 row in set (0.000 sec)

今回登録したデータについてはもっと紹介したいこともあるのですが、長くなったので、次回にLINESTRINGのデータを登録するのと併せて取り上げたいと思います。

【コラム】Shapefileは嫌われ者?

地理情報界隈をウォッチしていると、「シェープファイル(Shapefile)つらい」という言説を目にします。「撲滅運動」という激しい言葉に触れることもあるかもしれません。Shapefileはなぜこんなに嫌われているのでしょうか。

長らくShapefileは地理情報データをやりとりするための事実上の標準として、多くの人に便利に使われてきました。歴史があるとは、つまり「古い」ということでもあります。現在のデータ取り扱いの中では不便に感じる点も増えてきたわけです。以下のような点がよく指摘されています。

1つのデータセットなのにファイルがバラバラ

とにかくファイルが分かれていることが嫌われポイントの最大派閥と言えるでしょう。筆者が目にする範囲では、業務で相手から .shp ファイルだけ送りつけられて困った(属性情報の.dbfファイルもなければ作業を進められない)ということを発端とする感情的な批判が大勢であるように感じます。

「わかりにくさ」という点では課題ですが、正しく「複数のファイルでワンセット」ということが周知されれば良いだけの話でもあり、本質的な問題ではありません。とは言え、実際の業務で「Shapefileのせいで困った」という体験ナンバーワンであることは間違いないでしょう。

斯く言う筆者も、例えば今回紹介したようなデータ47都道府県分を1つのフォルダにまとめて置くときなど、複数ファイルに分かれていることで不足ファイルのあるなしの確認が手間だなぁと感じたこともあり、1セットのデータは1つのファイルで表現されたほうが扱いやすいのは確かですね。

属性名の長さの制限

.dbfファイルに保存されるデータ構造では、列名(属性名)に10バイトまでしか使用できません。これは dBaseに由来する制限です。このため、列名として例えば "Prefecture" はギリギリ使えますが、"Prefecture_name"や "Prefecture_code"のような名前さえ長さ制限にひっかかってしまい使えないのが実情です。

今回のデータでも列名が "P29_006" のようにコンパクトに収まる名前にしているのはShapefileで扱えるようにするためという意味もあるのではないかと想像しています。

ファイルサイズの壁

Shapefileを構成する各ファイルサイズには、2GBの上限があります。あまり2GBを越えるファイルを扱いたいとも思いませんが、大きめのデータを取り扱う場合にはこの制限が厄介者になることがあるようです。

各種情報の表現方法が標準仕様に含まれない

本連載ではShapefileの構成ファイルとして紹介しましたが、実は.cpgや .prjファイルは必須とはされていません。つまりShapefileには文字コードや座標系に関する情報が含まれないことがあります。これは正しいデータ解釈のためには非常に困ったことです。

NULLを表現できない

もちろん空欄やゼロは表現できますが、何もない状態であるNULLを表すことができません。

このような「古さ」があるが故に、現在ではShapefileを忌避する人が増えていると言えそうです。

ただ、「Shapefileをやめよう/やめたい」という声の多くには「代わりにこのフォーマットを使おう」という提案がなく、「Shapefile以外なら何でも良いよ」という愚痴とも提案ともつかないものも少なくありません。

新たなデファクトスタンダードとなるフォーマットが定まるにはまだ時間がかかりそうで、国土数値情報のように複数のフォーマットでデータが提供される状況は当分続くでしょう。利用者としては、利用可能なフォーマットでデータを公開してくれていることに感謝するばかりです。

この記事をシェアしてください

人気記事トップ10

人気記事ランキングをもっと見る

企画広告も役立つ情報バッチリ! Sponsored