ことのおこり
地理情報機能(Spatial / GIS)に関心を持つMySQLユーザにとって、PostGISと比べての関数の少なさは最早深いコンプレックスと言っても良いものでしょう。実際に一つ一つ見てみると、そんなに使う関数ばかりでもないのですが、ここぞという時に「PostGISなら関数一発なんだけどな」と言われるシーンも少なくないので、やはり関数が充実しているのは利用者体験に大きく寄与しているのは間違いありません。
そんな思いから、昨年末にお試しでひとつ、MySQLへ新たなSpatial関数を追加してコントリビュートを出してみました。
当初よりバージョンリリースの狭間であることなど、タイミングが悪いなぁとは思っていましたが、想像以上にそれ以外の事情も含め、タイミングが最悪だったようで、提出から2ヶ月経った今も全く音沙汰なく完全スルーされた状態です。もしかしたらバグレポートやコントリビュートも3ヶ月に一度だけ見て更新するのかもしれません:-) ([要出典][ガセネタ注意])
そんな折に開催された日本MySQLユーザ会会の後の交流会で、「プラグインにしたら?」というアイデアをいただきました。
mysql.connpass.com
プラグインにすれば、取り込んでもらうのを待つ必要もないしコントリビュートするよりも開発は気楽です。実際に作ってみると様々な壁があることもわかったのですが(後述)、それでも様々なGIS機能をMySQLで、たとえお試しレベルであってもすぐに公開して動かしてもらえることの魅力は大きいものです。
MySQL Spatial Functions Plugin
そんなわけで作りました! このプラグインを入れるだけで、一気にMySQLのSpatial関数が増えます!
github.com
まずは以下の関数に対応しました。概ね、Boost::Geometryライブラリを活用すると実装できるものを中心に選定し、実装しました。
| 関数名 | 説明 |
|---|---|
| STX_perimeter(geom) | Polygon/MultiPolygon の周長 |
| STX_coveredby(g1, g2) | g1 が g2 に覆われているか判定 |
| STX_covers(g1, g2) | g1 が g2 を覆っているか判定 |
| STX_dwithin(g1, g2, dist) | 2つのジオメトリ間の距離が閾値以内か判定 |
| STX_azimuth(p1, p2) | p1 から p2 への方位角(ラジアン、北から時計回り) |
| STX_project(point, dist, azimuth) | 指定距離・方位角で点を投影 |
| STX_linelocatepoint(line, point) | ライン上の最近接点の位置(0.0〜1.0) |
| STX_linesubstring(line, start, end) | ラインの一部を抽出 |
| STX_angle(p1, p2, p3) | p2 における p1-p2-p3 の角度 |
| STX_translate(geom, dx, dy) | ジオメトリを平行移動 |
| STX_scale(geom, sx, sy) | ジオメトリを拡大・縮小 |
| STX_rotate(geom, angle [, center]) | ジオメトリを回転(原点または指定中心) |
| STX_reverse(geom) | 頂点の順序を反転 |
| STX_pointonsurface(geom) | ポリゴン内部の点を返す |
| STX_closestpoint(point, geom) | ジオメトリ上の最近接点を返す |
| STX_relate(g1, g2) | DE-9IM 関係行列を返す |
| STX_relatematch(g1, g2, pattern) | DE-9IM パターンマッチ判定 |
名前がSTX_ で始まるのは、本来はST_ にしたかったのですが、今後、MySQL本体に同じ名前の関数ができたときにバッティングしないようにと(つまり本体で実装されることを期待して)ちょっぴり遠慮して "X" を付けました。なんならオプションで ST_ を有効化するみたいなこともできるかな。
動作環境、動作方法
Ubuntu 24.04 上のMySQL 9.6 でのみ動作確認をしています。 配布バイナリのままでは8.0や8.4では動かないと思います。 ビルド環境を整えれば 8.4 などでも動作するはずです。ビルド環境の整備方法は、(ビルドしたい人もいないだろうと予想)あまり丁寧にまとめていないので、要望があれば優先度上げて説明します。
動作させるには、Ubuntu24.04でMySQL9.6を動かしている環境にて、 mysql-spatial-plugin/plugins/spatial_plugin/ にある spatial_plugin.so を MySQL のプラグインフォルダにコピーして、
INSTALL PLUGIN spatial_plugin SONAME 'spatial_plugin.so';
するだけで、上表の関数が使えるようになります。
種明かし&現時点のステータス
実装された関数の数を見て、その数に驚いてくださった方もいると思います。こんなに沢山の関数を一気に!?と。
種明かしをすると、みんなAIです。不足している関数のリストを作って、その中でBoost Geometryを活用することで実装可能なものやそうでないものなどをAIと相談し(優先順位を決めたのは私)、コードを書いてもらい、私がいくつかのパターンについてテストをして(現実的なパターンを洗い出してのテストはAIは苦手だった)、要件を更に詳細に伝えて直してもらう、といったことを繰り返しました。
私が判断をする際にも、判断に必要な情報を要求すれば探してきて説明してくれるなど、AIなしでは為し得なかったプロジェクトです。Claude Codeさんに感謝。私の手によるテストはまだ網羅的にすべてはできていません。少し動かしてみて良さげなので、一旦公開してみたというステータスです。そのためバージョン番号も0.0.1 という、将来への期待が膨らむ数値を割り当てました。
Plugin(UDF)の制約
実装してみてわかったのですが、UDFにはいくつかの制約があります。今回のプロジェクトを進めるにあたって最大の制約となったのは、戻り値の型です。UDFでは STRING/REAL/INT/DECIMAL の値しか戻すことができず、今回作った関数では(数値を返すのはなくジオメトリを返す必要があるものについて)STRING型(バイナリもここに含まれる)を返しています。 内容は正しく「ジオメトリのMySQL内部バイナリ型(=SRID情報+WKB)」を返しているので、各種後続処理にそのまま使う事はできるのですが、例えば DBeaverなどでは返り値がGEOMETRY系の型であることを以て地図表示してくれる仕組みになっているため、このままでは地図に表示してもらえない、といった弊害があります。まぁこればかりはMySQLのUDFインタフェースが対応してくれないと無理なので、型が大切な時には当面はCASTするとかして対応するしかないですね。
その他思ってたのと違ったこと
プラグインの soファイル(バイナリ)をひとつ作成すれば MySQL 8.0/ 8.4, その後の Innovation などで利用できると思い込んでいました。冷静に考えれば当然なのですが、実際やってみると、そもそもソースコードのヘッダファイルや設定ファイルなどを参照してビルドしているので、各バージョンごとにビルドしなきゃいけないんですね。。(最新のInnovationがいいと思っていたのですが)寿命的なものを考えると 今後はLTSをターゲットとしてビルドするほうがいいのかもなーと思いました。 実験的な試みなので、本番で使いたいなんて人もいないだろうし、まぁ自分のやりたいようにやればいいかな。
今後
Boost以外のライブラリを活用して拡張できるものいくつかあるので対応していきたいのと、懸案である様々なフォーマットの入出力に挑戦してみたいと考えています。データの入力(取込)に関しては、具体的に「あのデータを取り込みたい」というモチベーションから開始しないとテストも大変になりそうなので、様々な公開データのフォーマットの情報をお待ちしています。
あとは今のところ、いくつかの関数以外は簡単なテストしかしていないので、どこかのタイミングでしっかりと関数一つ一つ動作確認していかないといけませんね。ただし方向としては、品質が低くとも、まずは欲しい機能の風呂敷を一旦広げることを優先したいという思いのほうが強いです。
さいごに
AIすごい。「やりたいことを持っている人」が、自分でそれを(今までの何十分の一の時間で)実現できてしまいます。一方でシステムについての基本的な知識を持たない場合は、出来上がったものの検証方法を知らない(=AIの良いなりを受け入れるしかない)ことで、完成度の低いものになりがちだなというシーンにも何度か遭遇しました。自信たっぷりにAIが言ってきたことでも「いやそれ違うよね」と言ってあげることで正しい情報にたどり着いてくれることも多く、現時点ではプロとアマの違いが出る道具かな? と感じました。まあ、すぐにその差が縮まる気もしますが。
今回はあえて「動作が正しいならばそれで良い」という方針で、自分でほとんど行動コードに手を入れることはありませんでした(必ず指示して修正してもらう方針)。一応ある程度のコードを書けるスキルは持っているつもりの立場としては、どこかムズ痒いところもあるのですが、これってもしかして大きめの会社で偉くなって、コードを全然書かせてもらえなくなった人の心境に近いのかも、なんてことを思いました。ただし、部下はとびきり優秀というところが救いです。そう考えるとこれはこれで新しい時代のやり方なのかなと思います。まぁ色々試みていきます。
ということでMySQLの本体にない機能で楽しみたい人、地理情報データに興味があってでもMySQLの関数の少なさにがっかりしている人、ぜひ触ってみてください。

