MySQLで学ぶGIS入門 21

鉄道の路線と駅のオープンデータをMySQLに登録してみよう

第21回の今回は、鉄道路線・駅のオープンデータをMySQLへ登録する手順と、ShapefileとGeoJSONの違いなど、関連トピックについて解説します。

坂井 恵 (さかい けい)

6:30

はじめに

今回は、前回まで行ってきた国土数値情報のデータをMySQLに登録する総仕上げとして、LINESTRINGデータの登録を行います。また、そのほかデータ登録に関係するいくつかのトピックを紹介します。

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

データの取得

これまで、POLYGONデータ(行政区域)、POINTデータ(学校)のデータをMySQLに登録してきました。今回は、今後の連載の中でも使うために、総仕上げとしてLINESTRINGのデータを登録してみましょう。

国土数値情報ダウンロードサイトにアクセスして「4.交通 - 交通- 鉄道(ライン)」データをダウンロードします。ダウンロードの際にライセンスも確認しておきましょう。ライセンスは「CC_BY_4.0」ですね。

なお、このデータは前回までに登録した行政区域や学校データとは異なり、都道府県ごとに分かれていないので、「全国」データを使用します。

ダウンロードした「N02-24_GML.zip」ファイルを展開すると、サブフォルダとして「Shift-JIS」「UTF-8」という2つのフォルダが作成されます。今回は UTF-8フォルダのファイルを使うことにしましょう。

UTF-8フォルダ内には、xml形式のファイル(GML)、GeoJSON形式のファイル、Shapefileを構成する複数のファイル群、そして線路に関する情報(RailroadSection)と駅に関する情報(Station)があります。

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

  • N02-24.xml(31.7MB)
  • N02-24_RailroadSection.dbf(11.2MB)
  • N02-24_RailroadSection.geojson(14.3MB)
  • N02-24_RailroadSection.prj(145B)
  • N02-24_RailroadSection.shp(7.7MB)
  • N02-24_RailroadSection.shx(176KB)
  • N02-24_Station.dbf(13MB)
  • N02-24_Station.geojson(3.3MB)
  • N02-24_Station.prj(145B)
  • N02-24_Station.shp(971KB)
  • N02-24_Station.shx(82KB)

データ内容の確認

このファイルの内容を確認していきましょう。まずは RailroadSection データから。おなじみのogrinfoコマンドを使います。

$ ogrinfo -al -so N02-24_RailroadSection.shp
INFO: Open of `N02-24_RailroadSection.shp'
      using driver `ESRI Shapefile' successful.

Layer name: N02-24_RailroadSection
Metadata:
  DBF_DATE_LAST_UPDATE=2025-06-20
Geometry: Line String
Feature Count: 21932
Extent: (127.652280, 26.193150) - (145.598010, 45.416880)
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
N02_001: String (2.0)
N02_002: String (1.0)
N02_003: String (254.0)
N02_004: String (254.0)

同様に、Stationデータも確認してみます。

$ ogrinfo -al -so N02-24_Station.shp
INFO: Open of `N02-24_Station.shp'
      using driver `ESRI Shapefile' successful.

Layer name: N02-24_Station
Metadata:
  DBF_DATE_LAST_UPDATE=2025-06-20
Geometry: Line String
Feature Count: 10235
Extent: (127.652280, 26.193190) - (145.597430, 45.416880)
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
N02_001: String (2.0)
N02_002: String (1.0)
N02_003: String (254.0)
N02_004: String (254.0)
N02_005: String (254.0)
N02_005c: String (254.0)
N02_005g: String (254.0)

それぞれのデータ件数、使用されている座標系、ジオメトリのタイプ、属性情報として、どのようなカラムがあるか(無味乾燥な名前ですが)などの情報を読み取れましたか。

データ登録

RailroadSection、StationそれぞれのデータをMySQLに登録します。Shapefileの場合は 拡張子が .shp のファイルを指定するのでしたね。

ogr2ogr -f "MySQL" \
  "MySQL:thinkit,host=localhost,user=root,password=MySQL8.4" \
  N02-24_RailroadSection.shp \
  -nln railroad \
  -progress
ogr2ogr -f "MySQL" \
  "MySQL:thinkit,host=localhost,user=root,password=MySQL8.4" \
  N02-24_Station.shp \
  -nln station \
  -progress

登録処理が完了したら、MySQLに接続してテーブルリストを確認してみましょう。これまでの連載で登録したデータと合わせて、以下のようなテーブルが存在することを確認できます。

mysql> SHOW TABLES;
+-------------------+
| Tables_in_thinkit |
+-------------------+
| chiba_city        |
| chiba_school      |
| railroad          |
| station           |
+-------------------+

今回登録したrailroadテーブルとstationテーブルそれぞれに、ジオメトリ型ごとに何件のデータが登録されているか確認してみます。

mysql> SELECT COUNT(*), ST_GeometryType(SHAPE) FROM railroad GROUP BY ST_GeometryType(SHAPE);
+----------+------------------------+
| COUNT(*) | ST_GeometryType(SHAPE) |
+----------+------------------------+
|    21932 | LINESTRING             |
+----------+------------------------+
1 row in set (0.050 sec)

mysql> SELECT COUNT(*), ST_GeometryType(SHAPE) FROM station GROUP BY ST_GeometryType(SHAPE);
+----------+------------------------+
| COUNT(*) | ST_GeometryType(SHAPE) |
+----------+------------------------+
|    10235 | LINESTRING             |
+----------+------------------------+
1 row in set (0.024 sec)

どちらもLINESTRING型で、それぞれ約2万件と約1万件のデータが登録されていることが確認できました。

各テーブル構造も、ogrinfoで確認したものと同じように作成されています。

mysql> desc railroad;
+---------+--------------+------+-----+---------+----------------+
| Field   | Type         | Null | Key | Default | Extra          |
+---------+--------------+------+-----+---------+----------------+
| OGR_FID | int          | NO   | PRI | NULL    | auto_increment |
| SHAPE   | geometry     | NO   | MUL | NULL    |                |
| n02_001 | varchar(2)   | YES  |     | NULL    |                |
| n02_002 | varchar(1)   | YES  |     | NULL    |                |
| n02_003 | varchar(254) | YES  |     | NULL    |                |
| n02_004 | varchar(254) | YES  |     | NULL    |                |
+---------+--------------+------+-----+---------+----------------+
6 rows in set (0.001 sec)

mysql> desc station;
+----------+--------------+------+-----+---------+----------------+
| Field    | Type         | Null | Key | Default | Extra          |
+----------+--------------+------+-----+---------+----------------+
| OGR_FID  | int          | NO   | PRI | NULL    | auto_increment |
| SHAPE    | geometry     | NO   | MUL | NULL    |                |
| n02_001  | varchar(2)   | YES  |     | NULL    |                |
| n02_002  | varchar(1)   | YES  |     | NULL    |                |
| n02_003  | varchar(254) | YES  |     | NULL    |                |
| n02_004  | varchar(254) | YES  |     | NULL    |                |
| n02_005  | varchar(254) | YES  |     | NULL    |                |
| n02_005c | varchar(254) | YES  |     | NULL    |                |
| n02_005g | varchar(254) | YES  |     | NULL    |                |
+----------+--------------+------+-----+---------+----------------+
9 rows in set (0.001 sec)

データ内容の例も紹介しておきます。

mysql> SELECT n02_001, n02_002, n02_003, n02_004
    ->   FROM railroad LIMIT 5;
+---------+---------+--------------------------------+--------------------------------------------+
| n02_001 | n02_002 | n02_003                        | n02_004                                    |
+---------+---------+--------------------------------+--------------------------------------------+
| 23      | 5       | 沖縄都市モノレール線           | 沖縄都市モノレール                         |
| 12      | 5       | いわて銀河鉄道線               | アイジーアールいわて銀河鉄道               |
| 12      | 5       | いわて銀河鉄道線               | アイジーアールいわて銀河鉄道               |
| 12      | 5       | いわて銀河鉄道線               | アイジーアールいわて銀河鉄道               |
| 12      | 5       | いわて銀河鉄道線               | アイジーアールいわて銀河鉄道               |
+---------+---------+--------------------------------+--------------------------------------------+
5 rows in set (0.000 sec)

mysql> SELECT n02_001, n02_002, n02_003, n02_004
    ->   FROM station LIMIT 5;
+---------+---------+--------------------------------+-----------------------------+
| n02_001 | n02_002 | n02_003                        | n02_004                     |
+---------+---------+--------------------------------+-----------------------------+
| 11      | 2       | 指宿枕崎線                     | 九州旅客鉄道                |
| 23      | 5       | 沖縄都市モノレール線           | 沖縄都市モノレール          |
| 24      | 5       | 東京臨海新交通臨海線           | ゆりかもめ                  |
| 24      | 5       | 東京臨海新交通臨海線           | ゆりかもめ                  |
| 24      | 5       | 東京臨海新交通臨海線           | ゆりかもめ                  |
+---------+---------+--------------------------------+-----------------------------+
5 rows in set (0.000 sec)

国土数値情報では周辺情報も大切

ここまで、ShapefileやGeoJSONなどのデータをMySQLに登録する方法を紹介してきました。しかし国土数値情報のデータを本格的に活用するには、これだけでは足りません。

下図は前回登録した学校データのダウンロードページにある「属性情報」の解説欄です。前回の記事にてogr2ogrで実行したMySQLへの登録処理により、これらの情報がMySQLのテーブルとしても登録されています。

この中で注目するのは「学校分類(P29_003)」や「管理者コード(P29_006)」などの列です。実際の列には「16007」とか「1」とか「01」などのコード値が入っていて、これだけでは何がなんだか意味が分かりません。これらの意味を記しているのが、一番右にある「属性の型」という欄です。この欄のリンク先に、それらの数字が何を意味しているのかの情報が記されています。

学校データの場合、以下のような情報が提供されています。実際の運用でデータを使用する場合は、コードの意味が暗黙知になってしまわないよう、これらのコード情報も別途テーブルで管理するようにすると良いでしょう。

(国土数値情報ダウンロードサイトの学校データを元に筆者が加工)

ShapefileとGeoJSONの違い

前々回には行政区域データをGeoJSONで、前回は学校データをShapefileでMySQLに登録しました。実はこの2つには微妙な違いがあります。まずは、それぞれをMySQLに登録したテーブル定義を見てみましょう。

【行政区域データ(GeoJSONから登録)】

mysql> SHOW CREATE TABLE chiba_city\G
*************************** 1. row ***************************
       Table: chiba_city
Create Table: CREATE TABLE `chiba_city` (
  `OGR_FID` int NOT NULL AUTO_INCREMENT,
  `SHAPE` geometry NOT NULL /*!80003 SRID 6668 */,
  `n03_001` text,
  `n03_002` text,
  `n03_003` text,
  `n03_004` text,
  `n03_005` text,
  `n03_007` text,
  UNIQUE KEY `OGR_FID` (`OGR_FID`),
  SPATIAL KEY `SHAPE` (`SHAPE`)
) ENGINE=InnoDB AUTO_INCREMENT=2309 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.000 sec)

【学校データ(Shapefileから登録)】

mysql> SHOW CREATE TABLE chiba_school\G
*************************** 1. row ***************************
       Table: chiba_school
Create Table: CREATE TABLE `chiba_school` (
  `OGR_FID` int NOT NULL AUTO_INCREMENT,
  `SHAPE` geometry NOT NULL /*!80003 SRID 6668 */,
  `p29_001` varchar(5) DEFAULT NULL,
  `p29_002` varchar(15) DEFAULT NULL,
  `p29_003` varchar(5) DEFAULT NULL,
  `p29_004` varchar(254) DEFAULT NULL,
  `p29_005` varchar(254) DEFAULT NULL,
  `p29_006` varchar(1) DEFAULT NULL,
  `p29_007` varchar(1) DEFAULT NULL,
  `p29_008` varchar(2) DEFAULT NULL,
  `p29_009` varchar(254) DEFAULT NULL,
  UNIQUE KEY `OGR_FID` (`OGR_FID`),
  SPATIAL KEY `SHAPE` (`SHAPE`)
) ENGINE=InnoDB AUTO_INCREMENT=2155 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci
1 row in set (0.000 sec)

各カラムのデータ型にある大きな違いに気づいたでしょうか。そうです。文字列データについて、GeoJSONから登録したテーブルではtext型の列になっているのに対し、Shapefileから登録したテーブルでは varchar型になっていますね。これは、Shapefileの属性情報は各列のサイズ情報を持っているのに対して、GeoJSONはそういった情報を持っていないことに由来します。

テーブルを作成する際に「文字列だから何でもかんでもtext型」というのはRDBMSの扱い方としてはいささか雑と言わざるを得ませんから、こういった違いも「ShapefileをやめてGeoJSONにしよう」と簡単には言えない要因の1つになっているのではないかと感じます。

【コラム】GML形式のファイルは取り扱いが難しい

国土数値情報のダウンロードサイトでは、多くのデータでGML形式(JPGIS2014に準拠した符号化)に対応したファイルが提供されています。本連載を執筆するにあたって、この形式のファイルをMySQLに取り込むことも試みたのですが、残念ながら私は成功するに至りませんでした。

原因としては、この形式のファイルはより厳格な定義に基づいて記述するために、多くの .xsd ファイルを参照します。この参照は多段にわたっており、ogr2ogrコマンドではそれらを適切に追跡しながらGMLファイルを開くことが(簡単な指定では)できなかった、という状態です。

国土数値情報では、多くのデータについてGeoJSONやShapefileの形式でも配布しているので、これらの形式のファイルを使用して登録するのが良いであろうというのが現時点での私の見解です。様々なデータフォーマットで公開してくれていることに感謝です。

最後に1つ、小ネタで「MySQLへのデータ登録シリーズ」の回の締めとしましょう。ファイル名やURL、あるいはXMLの中身を見た人はXMLの項目接頭辞などで「ksj」という文字を目にしたことがあると思います。これが何なのか、気になりませんでしたか。

実はこれ、「国土数値情報(Kokudo Suchi Joho)」の略なのです。まるで、M-1でのたくろうさんのネタ「京都産業大学(KSD)」みたいですね。

人気記事トップ10

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

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