Re:mysqlでuserテーブルにダミーデータを10万件ほど入れる方法メモ

たまたま目に入った記事で、「mysqlでuserテーブルにダミーデータを10万件ほど入れる方法メモ」というものを拝読しました。
zenn.dev

そちらでは、ストアド・プロシジャを作成して10万回のループでINSERTを実施する方法を採っていましたが、折角の機会なのでお伝えしたいテクニックがあり、これを書きしたためる次第。

プロシジャってあまり使いたくない

 「実現できない」より「実現できる」ほうが100万倍エラいので、プロシジャを使った解法にたどり着いたことは立派なのですが、「実現できる」から「もっと良く実現できる」に進むと更に楽しい世界が待っています。ということで「もっと良く」を紹介します。

私はこの手の処理にあまりプロシジャ使用を選択したくないのは:

  • 使い捨ての処理なのに、プロシジャというオブジェクトをサーバ上に生成したり、消し忘れてゴミオブジェクトとして残ったりするのがイヤ
  • そもそもプロシジャ作るのが面倒(普段あまり作らないので)。デリミタ一時的に変えるとかからして、無駄な作業をしている感がキライ
  • ぐるぐる系の処理はヤだ(INSERTを 10万回もやるなんて全然DB的発想ではない)


といった理由があります。実際、このプロシジャ版を手元で動かしたところ、4分近くかかりました。

テーブル定義とプロシジャおよび実行方法を https://zenn.dev/mesi/scraps/48b6479d21e00d から引用します:

CREATE TABLE `user` (
  `id` INT AUTO_INCREMENT PRIMARY KEY,
  `name` VARCHAR(50),
  `email` VARCHAR(100),
  `created_at` TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
DELIMITER $$

CREATE PROCEDURE InsertDummyData()
BEGIN
  DECLARE i INT DEFAULT 1;
  WHILE i <= 100000 DO
    INSERT INTO `user` (`name`, `email`)
    VALUES (CONCAT('User ', i), CONCAT('user', i, '@example.com'));
    SET i = i + 1;
  END WHILE;
END$$

DELIMITER ;
CALL InsertDummyData();

それ、CTEでできるよ!

こういう処理を行いたいときに便利なのが、CTEです。
白状すると、私もこの構文の書き方をすぐに忘れてしまうので、書く前に毎度検索しています(笑)。

set @@cte_max_recursion_depth=100000

INSERT INTO user (name, email) 
WITH RECURSIVE num(n) AS (SELECT 1 UNION ALL SELECT n+1 FROM num WHERE n<100000)
SELECT CONCAT('User ',n), concat('user',n,'pexample.com')  FROM num;

最初の set文は、cteの実行可能段数を緩和するための指定です。

笑っちゃうと思うんですけど(というか盛大に笑っちゃってほしいんですけど)、先ほど4分かかったこの処理が、どれくらいの時間でできると思います?

手元の環境では、 0.6秒程度でした。


私が若手の頃に、1時間半近くかかっていたクエリ(PL/SQL)が、ちょっと考えて処理の仕方を工夫したらヒトケタ分になったこと(その後更に改善して1分以内になったはず)という、工夫次第でダイナミックに効果が出る体験をしたことがきっかけで、DBMSの世界って面白いなと感じたので、これはそれに匹敵するくらいの差と言えるんじゃないかなと思います。

まとめ

ということで、

  • ぐるぐる系よりガッツリ系
  • CTE知ってると便利
  • 構文覚えてさらさら書けると格好良いけど私は覚えてないw

でした。


MySQL 8.4-LTSがやってきた&native_passwordに注意

お待ちかねの「MySQLのはじめての LTS」、MySQL 8.4.0 がリリースされました!

Note: If you are having trouble connecting to the upgraded MySQL 8.4.0 Server, please read the end of this blog.
(Summary of solutions for "unknown variable 'default-authentication-plugin" error, and "mysql_native_password' is not loaded" error)



status表示に、特に「LTS」をあらわすものはないようです。(variablesを確認していて「お。LTSって書いてあるじゃん!」と思ってよく見たら TLS でした。関係ない)

インストール

手元の Ubuntu 20.04の、既に MySQL 8.3.0が稼働している環境を、今回アップグレードしました。
apt update しても降ってこなかったので、リポジトリ側に 8.4-ltsが存在しているのを確認して(そう、この名前には「lts」がついているのです)、

Origin: MySQL
Label: MySQL
Codename: jammy
Architectures: i386 amd64 source
Components: mysql-apt-config mysql-8.0 mysql-8.4-lts mysql-innovation mysql-cluster-8.0 mysql-cluster-8.4-lts mysql-tools mysql-cluster-innovation mysql-tools-old mysql-tools-preview
Description: Apt repository for Oracle MySQL packages
SignWith: B7B3B788A8D3785C

手動で、/etc/apt/sources.list.d/mysql.list を書き換えちゃいました。

deb [signed-by=/usr/share/keyrings/mysql-apt-config.gpg] http://repo.mysql.com/apt/ubuntu/ jammy mysql-8.4-lts

そして、apt update / apt upgrade。

サーバが起動しない

アップグレードは完了したものの、mysqldサーバが起動しません。

2024-04-30T07:13:31.955229Z 0 [ERROR] [MY-000067] [Server] unknown variable 'default-authentication-plugin=mysql_native_password'.
2024-04-30T07:13:31.955815Z 0 [ERROR] [MY-010119] [Server] Aborting

数ある my.cnf 系設定ファイルを手繰っていき、私は /etc/mysql/mysql.conf.d/default-auth-override.cnf に、この設定があるのを見つけました。これをコメントアウト。サーバ再起動(というか起動)。

# This file is automatically generated by MySQL Maintainer Scripts
[mysqld]
default-authentication-plugin = mysql_native_password

クライアントから接続できない

サーバ起動指示はエラーなく完了したものの、こんどは mysql コマンドでの接続でエラーが発生しました。もうやだ。

ubuntu@vmubuntu:~$ mysql -uroot -p
Enter password: 
ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded

救世主登場:


いとうさんありがとう!!!!!

ということで、どこの設定ファイルでも良いのだけど、先ほど設定をコメントアウトしたファイルがちょうどいいや、と(ファイル名も default-auth なので意味は間違ってないし)そのファイルに mysql_native_password=ON の記述を追加。mysqld再起動。
再度 mysql小文字5文字クライアントから接続

ubuntu@vmubuntu:~$ mysql -uroot -p
Password:
mysql: [Warning] Using a password on the command line interface can be insecure.
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 9
Server version: 8.4.0 MySQL Community Server - GPL

Copyright (c) 2000, 2024, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> 

やったー!!

Conclusion

まとめると、

  • サーバが起動せず「unknown variable 'default-authentication-plugin=mysql_native_password'.」のエラーメッセージが表示されていたら、my.cnf系のどこかの設定ファイルに 「default-authentication-plugin = mysql_native_password」の設定があるので、コメントアウトしろ
  • その後クライアントからもつながらないと思うので、さっきコメントアウトしたファイルあたりにでも、「mysql_native_password=ON」の指定を追加しろ

ということになります。MySQL 8.4.0、いきなり動かなくて焦りました(笑)。


-

After upgrading MySQL 8.4:

  • If the server does not start on error "unknown variable 'default-authentication-plugin=mysql_native_password'.", you shoud comment out the "default-authentication-plugin = mysql_native_password" setting in my.cnf or in other cnf file.
  • After that, you will not able to connect the server by using mysql command-line client on error "ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded", then, you should add "mysql_native_password=ON" to the cnf file.
  • After rebooting mysqld, you can connect the MySQL 8.4.0 LTS! Enjoy it!!

追記

yyamasakiさんからも、この変更に関するリリースノートの記述を補足いただきました。

SQLパズル:離れ島を探せ!

SQLの未解決問題(坂井調べ)。解けたらIQ180! さぁキミはできるかな!?

・・・・とくだらないサイトの煽り文句のような出だしですが、「SQLで書けそうなのにうまく書けない」テーマがあります。ウデに自信がある人も自信がない人も、頭の体操として取り組んでいただき、教えて戴けると、わたしがとっても助かります(笑)。
書けそうなのになぁ・・・なにか私がちょっとしたところで勘違いしちゃっているだけのような気がするんだけどなぁ・・・・

追記:このエントリでは、「面を構成する辺」に注目して書いていますが、実際には(今回の目的である)MOJデータでは辺IDは共有されていないことがわかりました。そのため一番下のサンプルデータでは「面を構成する点」に話を置き換えていますが、本質的には違いはありません。

データ構造に関する説明

基本的な要素

「辺」に囲まれた「面」をあらわすデータです。面にはIDがあり、また、各辺にもそれぞれIDが付けられています。
以下の図は、面1 が、 辺101,102,103,104,105に囲まれて成り立っているものです。

データにするとこんな感じ。

面ID 辺ID
1    101
1    102
1    103
1    104
1    105
面はたくさんある

面は、辺を共有する形で複数(たくさん)存在しています。

先ほどの面1のデータに加えて、こんな感じ。

面ID 辺ID
2    104
2    106
2    107
2    108
4    105
4    110
4    111
4    112
4    109
:

(面3は図の中に辺IDをひとつ書き忘れてしまったので気にしないでください。。面3と面6で共有している線ね)

「島」の存在

さて、上の例(面1~面6までがある状態)のようにひとかたまりになった状態を「島」と呼びます。実はこのデータは、すべてがひとつの「島」になっているわけではなく、多数の「島」に分かれています。以下の図のように。

データは、これまで例示したように淡々と、面IDと辺IDのセットが格納されています。

さて問題です

ここで、出題です! 
本質的には同じ課題のような気がしますが、いくつかの設問にしてみました。すべてSQLで回答してください。

【問1】データはいくつの島から成り立っていますか(いくつの島に分かれていますか)

【問2】任意に「島ID」を決めて、面ID+島IDのリストを返してください。つまり一つの島の中にどの面が含まれているのかを知ることができる結果となります。島IDは構成する面のなかからMAXやMINなどで適当に決めたり、適当に連番にしてみたり等、なんでも構いません。

これはなに

お気づきの方もいるかもしれませんが、この設問、MOJ-XMLデータ(登記所備付地図のデータ)で遊ぼうとしたときにぶち当たってしまった課題でした。できると思っていたのになぁ(まだ言ってるw)。
実際のデータは、この「面」が数億件あります。
今回の「パズル」は課題をシンプル化しましたが、実際には各「面」にはその情報が書かれていた「ファイル」があって、そのファイルごとに「島の数」を求めたいのでした。その辺は、このパズルが解決すれば応用できることでしょう。


ということで、面白おかしく書いていますが、今日1時間くらい考えてこれを解決できなかったことが本気で悔しくてしょうがないので、解決できた方はぜひ披露してください!


サンプルデータ

実際のデータがないと萌えないよ、という人がほとんどだと思うので、用意しました(6月末までの期間限定公開)。5459件のデータです。
データに誤りがありました。というか、このエントリで説明してきた「辺IDが共有されている」は正しくなかったです(同じ辺でも別のIDが振られていた)。
実際に試して、ご指摘くださった皆さんありがとうございました。

ということで、改めてテーマを微修正します。面を構成する辺ではなく、面を構成する「点」に注目することにします。点IDは共有されていることを確認済みです。
(今回のデータでは例えば、F000000007と008で共有点が2つ、F000000006と007で共有点が2つ、などちゃんと重なっています!)


CREATE TABLE と INSERT文ですが、さくっと作成しただけで自分では動作確認していないので、誤りがあったらすいません適当に修正して使ってください(データは間違いないです→データは正しかったのだけどそもそも「辺IDが共有される」という発想自体が間違っていた...)。
surface_idが「面」のID、curve_idが「辺」のIDです。numはその面の中でのその線の順番を表すもので、今回は気にしなくて良いです。

面と点の関係にしたデータダウンロード(データセット2 :益城)ただしMAPPLEビューワの情報と変化している可能性あり
https://www.dropbox.com/scl/fi/9bce437lldnhuhm8o4z53/sql_quiz_moj_data_20240430b.txt?rlkey=6hxui0za4l67iv8iitygqyz35&dl=0

面と点の関係にしたデータダウンロード(データセット3 両国):
https://www.dropbox.com/scl/fi/fm5gl36pu1m356vhai2bx/sql_quiz_moj_data_20240430c.txt?rlkey=j0mi9kepm0lpqc7o4p7g96byn&dl=0


ダウンロードURL: https://www.dropbox.com/scl/fi/zut7jh73lnet1hmkr9uyo/sql_quiz_moj_data_20240430.txt?rlkey=dbxb6v0gwyo6itf5jx5hgdhbm&dl=0

このデータが表す地域は、以下のような島を表しています (MAPPLE法務局地図ビューワより*1)。
ただし、MAPPLEさんのビューワは現時点で 202308データのため、今回の 202404データとID等は異なっている可能性があります。

両国はたぶん変わってない。

なんだこりゃ。SQLの「IS DISTINCT FROM」演算子

発端

ふと、「IS NOT DISTINCT FROM」あるいは「IS DISTINCT FROM」という文字列が含まれるSQL文を目にしました。
SQLの基本的な構文として、

SELECT DISTINCT col1, col2 FROM t1; 

とか書くので、そのDISTINCT と FROM が、、、、とか考えていると混乱します。とりあえず「単にこういう長い名前の記号」と思っておくのがよさそう(笑)。

これはなに

Oracleから入り、その後MySQLをメインとするようになった私の通った道には、こんな構文はなかったわけです。それにしても、SQLiteでさえ(←ひどい言い草)対応しているのにMySQLにないってのは、ちょっと悔しい(笑)。

PostgreSQL 16 で動作を確認

こんなデータを作った。

\pset null (null)
create table t1 (id integer, s varchar(10));

SELECT * FROM t1;
 id |   s    
----+--------
  1 | AA
  2 | CBB
  3 | AA
  4 | CC
  5 | 
  6 | CC
  7 | 
  8 | (null)
  9 | (null)
(9 rows)

単純に結合するとこんな感じ(自分自身との結合を除外)。

db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE ta.id<>tb.id;
 id |  s  | id |  s  
----+-----+----+-----
  2 | CBB |  1 | AA
  3 | AA  |  1 | AA
  4 | CC  |  1 | AA
 :
  5 |     |  9 | 
  6 | CC  |  9 | 
  7 |     |  9 | 
  8 |     |  9 | 
(72 rows)

値が同じのだけを抽出したい場合は、(今までの私の発想だと)イコールを使う。ここに null のものは現れない。

db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE ta.s = tb.s AND ta.id<>tb.id;
 id | s  | id | s  
----+----+----+----
  1 | AA |  3 | AA
  4 | CC |  6 | CC
  5 |    |  7 | 
  3 | AA |  1 | AA
  6 | CC |  4 | CC
  7 |    |  5 | 
(6 rows)

IS NOT DISTINCT FROM を使うと、nullも「nullという値だとみなして」一致比較をしてくれる。「nullという値」というとっても気持ち悪いパワーワードですが「みなして」ということで我慢することにします:-)

db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE ta.s IS NOT DISTINCT FROM tb.s AND ta.id<>tb.id;
 id |   s    | id |   s    
----+--------+----+--------
  3 | AA     |  1 | AA
  1 | AA     |  3 | AA
  6 | CC     |  4 | CC
  7 |        |  5 | 
  4 | CC     |  6 | CC
  5 |        |  7 | 
  9 | (null) |  8 | (null)
  8 | (null) |  9 | (null)
(8 rows)

余談

本題ではないのだけど、今回試したクエリで、行きと帰りの一致データが重複して出ているのが気になりますよね。
今回は「IDが一致しないもの」ということで自分自身との結合を除外しましたが、この条件を「IDが自分よりも小さいもの」とだけ比較するようにすると片道切符になります。

db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE ta.s IS NOT DISTINCT FROM tb.s AND ta.id<tb.id;
 id |   s    | id |   s    
----+--------+----+--------
  1 | AA     |  3 | AA
  4 | CC     |  6 | CC
  5 |        |  7 | 
  8 | (null) |  9 | (null)
(4 rows)

最初からこちらでやっていたほうが、結果がシンプルになりましたね。


応用例

IS NOT DISTINCT FROM ではなく IS DISTINCT FROM を使うと、不一致のものにマッチさせることができます。
たとえば、値が'AA'のものと、これに一致しないもののIDの対応表を作りたい時に、こんなふうに。
対象としてnullも含まれるところが、新しいところです(べつに新しくないのですが、= とか <> しか知らなかった私には新しい)。

db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE ta.s='AA' AND ta.s IS DISTINCT FROM tb.s AND ta.id<tb.id;
 id | s  | id |   s    
----+----+----+--------
  1 | AA |  2 | CBB
  1 | AA |  4 | CC
  1 | AA |  5 | 
  1 | AA |  6 | CC
  1 | AA |  7 | 
  1 | AA |  8 | (null)
  1 | AA |  9 | (null)
  3 | AA |  4 | CC
  3 | AA |  5 | 
  3 | AA |  6 | CC
  3 | AA |  7 | 
  3 | AA |  8 | (null)
  3 | AA |  9 | (null)
(13 rows)

まとめ

今回の構文が長いので IS DISTINCT FROM を [コレ] と書くとすると、
A [コレ] B は、AがBと違っているときに成立(true)、
A NOT[コレ] B は、AがBと違ってないとき(笑)、、、つまり同じ時ですね、、に成立。(正確にはNOTの位置は IS NOT の場所になります)

既にSQL構文の中で使われている DISTINCT とか FROM という単語をこういう形でまったく違う用途で使うのって、仕様決めた人はセンスないよなと私は思ってしまうのですが、たぶん私など理解不能なレベルで考えぬいた末に、きっとセンスの塊の成果として決まったものだと思います(思いたい)。

軽く調べてみたのですが、 SQL-92には含まれていなくて、SQL-1999で登場した記法のようです。
近年のMySQL開発はどんどん、なるべく標準に準拠するようにとうことを心がけているように見えるので、そのうちこの構文が導入されたりするのかな。新機能好きなので楽しみに待ちたいと思います。導入されたら「知ってる!知ってる!導入前から注目していたんですよ!」と自慢できるように、このエントリを書いておきました(そんなわけじゃないw)。




参照

Twitter(X)で色々おしえてもらいました。ありがとうございました!

Snowflakeのマニュアル、わかりやすい。
https://docs.snowflake.com/ja/sql-reference/functions/is-distinct-from


追記

要するにこういうことなのか。
何か新しい事ができるようになったというよりは、一種のシンタックスシュガーと捉えても良いのかな。
(ここで「絶対に既存のデータと被らない置換文字列」を決める部分で「絶対」を保証できないので、IS DISTINCT FROM の存在意義が出てくるわけですが)

db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE COALESCE(ta.s,'*+;:')=COALESCE(tb.s,'*+;:') AND ta.id<tb.id;
 id |   s    | id |   s    
----+--------+----+--------
  1 | AA     |  3 | AA
  4 | CC     |  6 | CC
  5 |        |  7 | 
  8 | (null) |  9 | (null)
(4 rows)
db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE ta.s=tb.s AND ta.id<tb.id;
 id | s  | id | s  
----+----+----+----
  1 | AA |  3 | AA
  4 | CC |  6 | CC
  5 |    |  7 | 
(3 rows)
db=# SELECT ta.*, tb.* FROM t1 ta, t1 tb WHERE ta.s IS NOT DISTINCT FROM tb.s AND ta.id<tb.id;
 id |   s    | id |   s    
----+--------+----+--------
  1 | AA     |  3 | AA
  4 | CC     |  6 | CC
  5 |        |  7 | 
  8 | (null) |  9 | (null)
(4 rows)


ジオイド2024(試行版)が公開された!

2024年3月27日に国土地理院から『「ジオイド2024日本とその周辺」(試行版)』が公開されました。
日本における各地点の「高さ(標高)」を知る上で大きな進化であり、旧来の苦労して実施していた(らしい)基準点から繋げてきた水準測量からの開放を意味するパラダイムシフトであると感じ、大変興奮しています。
www.gsi.go.jp

なお、このエントリは私の「おべんきょう」の結果を整理するとともに、まだこの情報に触れてない人に概要が伝わったらいいなとの試みとして書いているものです。誤りや思い込みを含んでいるかもしれません。正確かつ詳細な情報は上記リンクで公開されている各種情報を参照いただけたらと思います。

前提知識:標高って何?

 あの山は標高何メートル、この場所は標高何メートルと言いますが、意外と正確に知らない人が多いのが、この「標高」というものです。

  • 標高が同じ2地点間では水は流れない
  • 標高が異なる2地点間では、水は標高が高いところから低いところに流れる

当たり前ですね。この当たり前を一旦、頭の中に置いておきましょう。

標高、というと「ゼロメートルはどこ?」という話をする必要があるのですが、これは後でお話するとして、「2地点間の高さの差」を求める方法について簡単に書くと、比較したい2地点に長い定規を立てて持ってもらって、真ん中くらいの地点から平行にそれぞれの定規の目盛りを読めば、2地点間の高さが分かります。これを繰り返していって日本中の標高が決まるのです。
この測量のスタート地点は「日本水準原点」24.3900メートル(2024年3月現在)です。

余談:海抜ゼロメートルはどこ

「海面の高さがゼロメートルです」と言っても、1日の中でも変動するし、月の中でも変化しますよね。日本では「東京湾平均海面」をゼロとすると定められています(法律上は「東京湾平均海面上二十四・三九〇〇メートル」を原点とすると定められていますが、つまり平均海面をゼロメートルとする、という意味です)。明治初期に6年位かけて観測し、決定されました。
隅田川の河口にある霊岸島で測られていたのですが、その後の都市開発で(当時は海だったのに)今は全然海じゃなくなって川の途中みたいになってしまったので、今は神奈川県の油壺で検潮しています。


前提知識: 「平ら」は平らじゃない

地球を回転楕円体としてモデル化しましょう。高さの差の測定は、先ほど「平行にして(2地点の)定規の目盛りを読」む、と書きました。実はこの「平行」というのがクセモノです。回転楕円体表面の曲面を無視して平面として扱える局所的な話として考えてみます。先ほどの「平行」とは、この平面に対して平行なのでしょうか。
いや、当たり前すぎることを質問されて意味がわからないだろうなと思います。平行なんだから平行でしょう、と。平行じゃないのは平行と言わない。・・・ですよね。  ところが違うんです。

地球というのは、場所によって重い物質や軽い物質が不均一に存在しています。そして、重い物質がある場所はより強い重力となります。私たちが「平行」だと判断する根拠は何かを考えみましょう。そう、重力ですよね。自分の右側のほうの地下に赤色物質(あるいは超小型のブラックホールのようなもの)があるとすると、そちら側に引っ張られるので、立っていても右斜め下のほうが「真下」と感じるはずです。重りを付けた紐を手に持っても右下のほうにひっぱられます。
といいつつ実際には、感覚的には「真下(と自分が感じる方向)にちゃんと重りの糸が垂れ下がってる」というだけなのでまったく違和感は感じません。単に、回転楕円対面とは平行ではない、というだけのことです。私たちは地球表面に居て、ただ重力のベクトルが向く方向を「下」だと思っているだけなのです。

前提知識:同じ標高面は回転楕円体面に対してでこぼこしている

そんなわけで、地球内部のあちこちに小さな赤色物質があると想像すると、「同じ標高を結んだ線」は回転楕円対面のように滑らかにはならずに、でこぼこしたものになります。このでこぼこの形を知るための数値が「重力」です。 実際には「右斜め下に重力が強い部分がある」という測定をするわけではなく、たくさんの「その場所」の重力を測定します。地図上にプロットすれば「自分より右側の方が重力強い場所なんだな」と分かりますよね。
日本では先ほど紹介した東京湾の平均海面を標高ゼロメートルとして、これと同じ高さを結んだ面を「ジオイド面」と呼んでいます。いわば「標高ゼロメートル面」です。回転楕円対面に対して結構デコボコしています。
「標高」というのは、回転楕円対面からの高さではなく、このジオイド面からの高さなのです。

これまでの重力の測定

あまり詳しくないので、今回の公開資料からの受け売りです。
重力を正確に測定するためには、今までは陸上の場合はその場所に行って実際に測定するしかありませんでした(海上は船で)。この正確な測定は「短波長な測定」と言うそうです。衛星でもある程度は測定できるのですが「長波長の測定」と言って、精度(有効桁数)が高くないとのこと。
どうしても山の中では観測ポイントは少なくなりますし、何度も測定に行けないのでかなり古いデータもあるのが現状でした。

今回のすごいデータ!

国土地理院では、航空機を用いて重力を測定しました。2019年から4年間に亘って、飛行距離約14万km、総飛行時間1300時間以上の測定を行ったそうです。測定の線数600本近く。これで日本周辺の重力を正確に知ることができました。
www.gsi.go.jp

測定は2023年の5月に終わったのですが、情報の整理や様々な資料を整備していたのでしょう。このたび2024年3月に公開されたのが、この測定結果を使って求めた「ジオイド面」のデータなのです。いやはや、ついに来た。網羅的に測定された重力データ(を元にしたジオイド面のデータ)。これは「高さの伊能図」と言って良いくらいの前進ですよ。すごい。しかも伊能図と違って国家機密でもなく、誰でもアクセスできるデータです。

ここ大事なので、今回の国土地理院「補足解説」資料から引用します。

今回公開されたジオイド面のデータ

GSIGEO2024beta.isg というファイルとして、北緯15度から50度、東経120度から160度の範囲のジオイド高の値が公開されています。東西は0度1分30秒ごと、南北は0度1分ごとの値です。まずは雰囲気から。

ヘッダ28行に続いて、北緯50度のジオイド高が西から東への順に並んでいます。1.5分ごとなので1行あたり約1600のデータがあります。
これが北から南へ順に各行1.0分おきの値として、2100行ちょっと続きます。大きなマトリックスデータですね。なお、EPSG:6668=JGD2011地理座標系です。
(日本国外に相当する部分の値はどこから得ているのだろうと疑問を持ちました。ご存じの方、教えてください)

任意の地点のジオイド高の求め方

緯度1分経度1.5分ごとのポイントにおけるジオイド高のデータは公開されましたが、自分の知りたいポイントがぴったり公開された座標に当てはまることは稀です。 自分の知りたいポイントのジオイド高を得るには、バイリニア補間を行います。2次元の線形補間です。
まず自分の知りたい点の近傍4点を特定し、タテ方向の線形補間、ヨコ方向の線形補間を行います。(計算式はそれなりにややこしいですが、直感的にはそういうことです)

具体的な計算式を、公開資料「ジオイド2024説明書」から引用します。


これらの計算を行うことができるWindows用とLinux用のプログラムも公開されています。 geoidcalc_win64.exe とgeoidcalc_linux_x86_64 です。
入力ファイルに緯度と経度のセットを何行でも書いておいてプログラムに喰わせると、その右側にジオイド高を追加して出力してくれるというものです。今のところ私は大量の地点のジオイド高を求めたいシーンがないのですが、必要になったときに便利に活用させてもらえそうです。(自動処理を考えるとファイルへの出力ではなく標準出力に出せるようにしてもらいたいところですが、まぁこれくらいなら使う側の工夫でもなんとか)

まとめ

こんな感じで、「かなり正確な」ジオイド高データが公開されると、衛星測位で得た楕円体高から即座にその地点の「かなり正確な」標高が計算できるようになります。測量業務的には、全国に1000カ所以上ある電子基準点を標高の既知点として使えるようになることが大きそうです。今まで東京にある水準原点からの高さを測量していたので、遠くに行けば行くほど誤差が蓄積する(と言っても一桁センチメートル内ですが)のが、重力(ジオイド高)+GNSSによる楕円体高 での算出になることで、水準原点からの距離に関係なく標高を計算できるようになったのは、大きな変化だと感じました。
改めて今回の「試行版」の公開は、「高さに関する伊能図」並の革命だと思います。

最後に現時点の電子基準点の所在地を、地理院地図より引用。全国これだけの点が高さの既知点になる!

北海道の緯度探訪(北緯45度から42度:OSC2023北海道参加に添えて)

昨年のオープンソースカンファレンス北海道(OSC 2024-do)に参加に合わせて、北海道の色々な地を巡りました。
「札幌のついでに稚内紋別襟裳岬?」 ええ、行きますよ。同じ都道府県内ですし。 ・・・嘘言いました。普通やりません。2023年はちょっと魔が差しちゃいました。そんな感じの旅程です。


その中から、北緯45度(東端西端2カ所)、北緯44度付近、北緯43度、北緯42度の地点を訪問または通過した話題を4本、リンクで紹介します。


note.com
note.com
note.com
note.com
note.com




緯度の話題を含む全北海道記録は以下のリンクからどうぞ。
note.com


OSC2023北海道の参加日記はこちらで。
sakaik.hateblo.jp

SmartHRさんがお好み焼きをご馳走してくれるツアーに参加

私の YAPC::Hiroshimaは、まだ終わっていない。

これはなに

 2月に開催された YAPC::Hiroshima で、SmartHRさんの展示ブースにて「お好み焼きのヘラ」を配布していました。
数量限定のこのヘラ。Twitterで「今から配布するよ!」の情報を得て、すっ飛んで貰いに行きました(笑)。ただのヘラじゃありません。SmartHRさんのロゴが入っています! 裏面にはソースで有名なおたふくのロゴも。 ・・・・いや、それも大事なんですが、それと同じくらい大切なのがヘラと一緒に入っている紙です。「お好み焼きを(東京で)ご馳走するよ!券」。 
そんなわけで本日開催されたのが、オフィス見学ツアー&お好み焼き食べ放題ツアー(食べ放題とは行っていないぞこら)でした。

オフィス見学ツアー

 まずは、ビルの17階にあるSmartHRさんのオフィス見学ツアー。もちろん執務室には入ることはできないのですが、とても広い共用スペース。このエリアは写真撮っていいですよ、と言ってもらっていたのですが、どうしても人が入ってしまうので、撮影も遠慮がちに。

天井の明かりが会社のロゴだったのが格好良かったです。

あと、伝説の「インターネットの椅子」(名前あってましたっけ?)

部活動が幅広く行われているということで、囲碁部、将棋部、バド部、スプラ部etc 同じ趣味を持つ人どうしで楽しんでおられるようです。職団戦とかに出られたりするんでしょうか。

いざ焼き焼きに!

見学の後は、お好み焼き屋さんに!
お店の調理も大変そうで、メインディッシュ(?)が出てくるのが遅めだったのですが、ブログではそんなの関係なくまずはすごそうな写真から、でーん、でーん。

昔のPCの話から、イベント運営の難しさやリスク、カンファレンス類へのスポンサーすることの話題など、幅広く盛り上がりました。
IT屋さんって、自分自身で経験できることなんて限られているので、他の多くの経験をしている人との会話を通して更に幅広い情報に触れることができるものです。例えば YAPC::Hiroshima のようなカンファレンスに参加することとか、その延長で今回みたいにお好み焼きを一緒に食べることとか。 そういう活動や行動を後押ししてくれる会社の仕組みがあるなら、それを使わない手はないわけですよ。面倒くさかったり不安だったり怖かったりするかもしれませんが、社外の人と会う機会をつかみ取って欲しいなぁ(そして社外の人と話をするにはあまりにも自分はプロじゃないと気づいちゃうかもしれないけど、それも成長のチャンス)などと、休日にカンファレンスに参加しても代休とかそんな仕組みがない私は思ったのでありました。 イベントや勉強会などがある時「ついて行っていいですか?」のヒトコトを言い出せるか、そんなことがその後の人生を大きく変えたりすることもあるかもしれませんね。(誰に向かって語りかけているんだw まぁ察してください)

隣のテーブルには知り合いが

 横並びだったので気づかなかったのですが、すぐ隣のテーブルに知人がいたことに途中で気づきました。この2テーブル+カウンターくらいの小さいお店なのに、なんたる偶然。
お互い顔を見合わせて「あれっ!?○○さん!」と言い合って笑う感じが、ここ何年も経験していなかった感覚でした(笑)。 PyCon JP 2024 の共同座長様でした。
こんなことあるんですね。

楽しいときは過ぎ往く

 話題があっちこっちに行きながら、つまり みんなの話題の豊富さ幅広さを表しているわけですが、気づけば良い時間。 ボリューミーな「広島の」お好み焼き(要するに焼きそば入り)を食べて満足の時間でした。実は私、今回のYAPCでの広島でお好み焼きを食べていないのです。前夜祭は頭痛でホテルで休んだ後ラーメン食べに行っただけだし、当日は日中から懇親会まで会場に釘付け、懇親会後はすぐに福山に移動してしまったので。。 そんなわけで、本日お好み焼きを食べたことで私の YAPC::Hiroshima もようやく完結したのでありました。

SmartHR さんも最近いろいろなイベントに協賛/支援等していただいてありがとうございます。いくつかのイベントで活躍を拝見していて、すぐに「このイベントに参加したから幾らの効果」と出るものでないのは当然なのですが、確実に知名度や良い印象が拡がって言っているな、と積み重ねの大きさを感じさせてもらっています。 今後もよろしくお願いします!