プログラマーのメモ書き

伊勢在住のプログラマーが気になることを気ままにメモったブログです

OverpassAPI の QL でいろいろと試してみました (2/2)

Overpass API でいろいろ試した続きです(基本的な部分は前の記事をご参考にしてください)。

OpenStreeMap の要素としては node, way, relation の3つらしいんですが、 OverpassAPI では area という要素があります。個人的には、この area というものの実態がつかめず、苦労しました。

ということで、この記事では area について思ったことをまとめておきます。

area について

まず、 area というのは、 OpenStreetmap の要素では『ない』というのが大前提としてあります。じゃあ、areaってどうやって決めてるの?

となりますが、こちらの説明にあるように、一定の条件を満たす範囲をエリアとして定義しているとのことです。で、これは、 Overpass API サーバー上でバッチジョブのように動作して、 area を生成しているとのことです。

誤解をおそれずにまとめると、 area というのは、下記のような条件のどれかを満たす way または relation に対して作成される、というもののようです。

  • relation : タグ admin_level の指定あり かつ タグ name の指定あり
  • relation : タグ type が multipolygon かつ タグ name の指定あり
  • relation : タグ postal_code の指定あり
  • relation : タグ addr:postcode の指定あり
  • way : タグ area が yes かつ タグ name の指定あり

それぞれのタグの意味を調べるとこんな感じかと思います。

  • admin_level というタグは自治体などの境界を表現する際に使われているようです。国や県、市町村などで異なるレベルを表現しているようです。
  • multipolygon はそのまま理解すると多角形なんですが、ここでは、内部に穴が開いているような領域を表現する際に使うもののようです。単なる多角形なら閉じた way (始点と終点が同じ node である way )でも表現できますからね。
  • postal_code と addr:postcode は同じ郵便番号を持つ地域を意味しているんだろうと思います。
  • タグ area は何らかの領域を表しているようです。

area 要素を導入した目的は、ある一定の領域を簡便に取り扱うために導入されたんですよね、きっと。自治体の境界とか、複雑な領域を扱うには、こういうものがあるほうが便利ですよね、そりゃ。チュートリアルの area のページに詳しく書かれていますので一読するといいかと思います。

また、こちらの説明だと area 要素のタグは、元になった relation や way のタグをそのまま使っているとあります。

概要がわかったところで、 area をあれこれ触ってみます。

参考

area についてはなかなか理解できなくて、下記などの説明も参考にしました。

個人的には map_to_area の説明を読んだときに、 way または relation に対応して area 要素が作られている、というのをはっきりと認識できて、理解が進みました。

area クエリ

area がどんなものかつかめたら、早速 Overpass API で扱ってみます。まずは、 area を指定して、それを対象にデータを取得してみます。

エリア『伊勢市』に含まれる node を返します(データ量が多いので、実行時にはご注意ください)。

area["name" = "伊勢市"];
node(area);
out;

area クエリは area["name" = "伊勢市"] の部分になります。条件に該当する area を返してきます。

でも、実は、上記の結果は area クエリだけではなく、 area フィルタも通した両方の結果になっています。なので、 area フィルタについてもいろいろと試します。

area フィルタについて

上記の例で node(area) の部分が、 area フィルタで、 area クエリで取得した area を対象に、その area に含まれる node を返すというものになります。

node(area) だけだと、デフォルトの入力集合(デフォルトセット)に含まれる area が対象になるとのことです。 node(area.a) のような表記だと、 a という入力集合に含まれる area が対象になるようです。

他の例も見てみます。

エリア『伊勢市』に含まれる、 way を返します(データ量が多いので、実行時にはご注意ください)。 なお、出力形式として out だけだと、 way を構成する node の緯度経度情報が出力されず描画できないので、 geom を付けています。

area["name" = "伊勢市"];
way(area);
out geom;

Wiki のエリアによるフィルターの説明では

ノードの場合は、エリアの内部または境界線上にあるものが検索されます。ウェイの場合は、少なくとも 1 点 (線分上の点も可) がエリアの内部 (境界線を含まない) にあるものが検索されます。エリア境界線上に終端があるだけで、エリアと交わらないようなウェイは、検索されません。リレーションの場合は、そのメンバーのいずれかがエリア内部 (境界線上を含まない) にあるものが検索されます。

とあります。上記の例を見ても、このとおりに area 内に node を持つ way を選択している様子(伊勢市外に道路が伸びている様子)が見てとれますね。

ついでに rel でも試してみます。

area["name" = "伊勢市"];
rel(area);
out geom;

伊勢市にメンバーがあるものが選択されているっぽいですね。

ちなみに、 area クエリが無い状態で、 area フィルタを使うと

node(area);
out;

下記のように、取得したデータがない応答がかえってきてました。

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API 0.7.59 e21c39fe">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2022-12-14T10:04:24Z" areas="2022-12-14T07:49:33Z"/>


</osm>

pivot フィルタ

area クエリで取得した area の輪郭が欲しいときは pivot フィルタというのを使うといいみたいです。

area["name" = "伊勢市"];
rel(pivot);
out geom;

area の元になったリレーションの情報を得ることができるようです。

ちなみに、

area["name" = "伊勢市"];
node(pivot);
out geom;

でも同じ結果を得ることができました。

Wiki の説明だと pivot は way と rel に使うとあるんですが、 node に使ってもエラーにはならずにうまいことやってくれてるようです(が、予期せぬ結果になるかもしれないので避けたほうがいいんでしょうね)。

area クエリで何が返ってくるのか?

最初に示した例は、 area クエリで選択した結果が、デフォルトセットに含まれて、その area に対して、 area フィルタを適用して、 node を表示させたものでした。

じゃあ、 area クエリだけなら、何が返ってくるのかが気になります。

area["name" = "伊勢市"];
out;

とすると、Overpass turbo では表示されない(表示できない)ので、画面上部の選択ボタンで『データ』を選び、データとして表示させて、area クエリで返ってくるものを確認します。

上記の場合は、

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API 0.7.59 e21c39fe">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2022-12-14T10:18:22Z" areas="2022-12-14T07:49:33Z"/>

  <area id="3604538518">
    <tag k="addr:country" v="JP"/>
    <tag k="admin_level" v="7"/>
    <tag k="boundary" v="administrative"/>
    <tag k="is_in:continent" v="Asia"/>
    <tag k="is_in:country" v="Japan"/>
    <tag k="is_in:country_code" v="JP"/>
    <tag k="is_in:iso_3166_2" v="JP-24"/>
    <tag k="is_in:prefecture" v="三重県"/>
    <tag k="is_in:province" v="Mie Prefecture"/>
    <tag k="name" v="伊勢市"/>
    <tag k="name:ar" v="إيسه"/>
    <tag k="name:en" v="Ise"/>
    <tag k="name:fa" v="ایسه، میه"/>
    <tag k="name:ja" v="伊勢市"/>
    <tag k="name:ja_kana" v="いせし"/>
    <tag k="name:ja_rm" v="Ise-Shi"/>
    <tag k="name:ko" v="이세시"/>
    <tag k="name:ru" v="Исе"/>
    <tag k="name:tg" v="Исе"/>
    <tag k="name:uk" v="Ісе"/>
    <tag k="name:zh" v="伊勢市"/>
    <tag k="name:zh-Hans" v="伊势市"/>
    <tag k="name:zh-Hant" v="伊勢市"/>
    <tag k="population" v="127071"/>
    <tag k="postal_code" v="516-0037"/>
    <tag k="source" v="KSJ2/N03"/>
    <tag k="source:population" v="http://www.pref.mie.lg.jp/DATABOX/23355003425.htm"/>
    <tag k="type" v="boundary"/>
    <tag k="website" v="https://www.city.ise.mie.jp/"/>
    <tag k="wikidata" v="Q328067"/>
    <tag k="wikipedia:ja" v="伊勢市"/>
  </area>

</osm>

のような、 area タグとそれに関する情報が返ってきました。これだけだと、緯度経度の情報を含んでいないので、表示できないのもその通りですね。

area の ID について

上記の area ID を確認すると 36xxxxxxxx と 36 で始まっています。こちらの説明によると、これは area の元になったリレーションのIDに対して、 3600000000 を付加したものとのことです。なので、

rel(id:0004538518);
out geom;

とすると、先ほどと同じ境界線を表示することができます。

area クエリ(つづき)

クエリは、完全一致だけでなく正規表現も使えます。そこで、 area クエリで正規表現を使ってみます。

area["name" ~ "伊勢市"];
out;

結果は

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API 0.7.59 e21c39fe">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2022-12-14T10:30:39Z" areas="2022-12-14T07:49:33Z"/>

  <way id="182504191">
    <nd ref="1928645808"/>
    <nd ref="1928645781"/>
    <nd ref="1928645782"/>
    <nd ref="1928645778"/>
    <nd ref="1928645779"/>
    <nd ref="1928645809"/>
    <nd ref="1928645808"/>
    <tag k="building" v="train_station"/>
    <tag k="name" v="伊勢市駅"/>
(中略)
  </way>
  <area id="3604538518">
    <tag k="addr:country" v="JP"/>
    <tag k="admin_level" v="7"/>
(中略)
  </area>

</osm>

のようになってました。今度は、 area タグのほかに way も出力されています。

どうも、Wiki の説明などでは、 area クエリは area を返すとありますが、条件に一致した閉じた way も返しているようです。

is_in クエリ

指定された緯度経度を含むエリアおよび閉じた way を返すとのことです(リンク先の日本語ページには『閉じた way』の表記がありませんが、英語版のページを見ると書かれてます)。

引数として、伊勢市駅付近の緯度経度を指定してみます。

is_in(34.4909706, 136.7097211);
out meta geom;

駅近辺の way が表示されています。

でも、『データ表示』で確認すると、 area として

  • 日本
  • 本州
  • 近畿地方
  • 三重県
  • 伊勢市
  • 東海道
  • 伊勢国

という名前を持つ area が返ってきているのがわかります。

is_in は入力集合を指定することもでき、その場合は入力集合のノードを含むエリアおよび閉じた way を返すようです。

まとめ

Overpass API の機能のうち、 area をいろいろと触ってみました。

最初は area がどんなものかつかめずに戸惑いましたが、 OpenStreetMap では、 way や relation を使って一定の領域(エリア)を工夫して表現しているものを、 area タグという表現を導入することで、便利に扱おうとしていることがよくわかりました。地域を絞り込んで検討したい時などには便利に使えそうです。

にしても、日本語の情報がもっと欲しいものです。

OverpassAPI の QL でいろいろと試してみました (1/2)

以前に少し試した OverpassAPI ですが、ちょっとやってみたいことができたので、改めて OpenStreetMap からのデータの取り出し方を復習してみました。

とその前に。

Overpass API のチュートリアルを見つけたので、まずは下記を試してみるのもおすすめです。

Overpass Tutorial

このチュートリアルも含めて、いろいろとやってみて、気になった点をまとめておきます。

クエリと結果セット

Overpass API のクエリって、結果をある集合に書き込みます。

[bbox: 34.46326, 136.66065, 34.56397, 136.80004];
node["name"];
out;

この場合は、デフォルトの結果集合に書き込んでいます。結果集合に名前を付けて、明示的に操作することもできます。

[bbox: 34.46326, 136.66065, 34.56397, 136.80004];
node["name"] -> .ise;
.ise out;

デフォルトの結果集合を明示的に操作したい場合は、アンダースコア(_)で表現します。

[bbox: 34.46326, 136.66065, 34.56397, 136.80004];
node["name"] -> ._;
._ out;

最初の例と同じことになります。

複数のクエリ

Overpass API では複数のクエリを書くこともできます。 で、クエリ毎に結果集合を切り替えることができるので、あとから、個別に処理することもできます。

[bbox: 34.46326, 136.66065, 34.56397, 136.80004];
node["name" = "伊勢市役所"] -> .ise;
node["name" ~ "伊勢支店"] -> .s;
(
  .ise;
  .s;
);
out;

丸かっこは、前の Overpass API の記事でやった、和集合をつくるやつです。 伊勢市役所が1点と金融機関の支店が2点見つかっています。

出力先が、同じ結果セットであれば、2つ目のクエリが入力集合を取らない場合は、前の結果が上書きされます。

[bbox: 34.46326, 136.66065, 34.56397, 136.80004];
node["name" ~ "伊勢支店"] -> .s;
node["natural"] -> .s;
.s out;

こんな感じで、 natural タグが定義されている結果に上書きされています。ということは、これをデフォルトの結果セットで試すと、2つ目のクエリの結果だけが得られることになります。

以前の記事で、絞り込みを試したときに、ちょっと感じた違和感がこれで明らかになりました。つまり、2つ目のクエリが、結果集合を上書きしていたため、絞り込みになっていなかったということですね。

複数の out ステートメント

上記では、複数のクエリを書くことができるとしましたが、もっというと、クエリだけではなく複数のステートメントを書くことができます。

ということで、 out ステートメントを複数を複数使うこともできます。

[bbox: 34.46326, 136.66065, 34.56397, 136.80004];
node["name" = "伊勢市役所"];
out;

node["name" ~ "伊勢支店"];
out;

画面上で『データ』を選択すると、一つの XML にまとまっているので、結果を一つにまとめるのは、 Overpass API でよしなにやってくれてるんでしょうね(apiを直接呼び出しても同じく1つのXMLが返ってきてました)。

way について

Overpass turbo でwayだけを表示するには

way({{bbox}})["highway"];
out geom;

または

way({{bbox}})["highway"];
(._;>;);
out skel;

のようにします。さきほどまでの伊勢市全体だとデータ量が多すぎるため、表示していた画面の範囲に限定しました(緯度経度の範囲だと、南、西、北、東の並びで 34.48677, 136.7046, 34.49306, 136.71331 でした)。

両者の違いは、戻ってきたデータの形式の違いです。 前者は、

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API 0.7.59 e21c39fe">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2022-12-19T07:32:05Z"/>

  <way id="23429311">
    <bounds minlat="34.4904910" minlon="136.7079073" maxlat="34.4914138" maxlon="136.7087511"/>
    <nd ref="1303266857" lat="34.4904910" lon="136.7079073"/>
(中略)
  <way id="50049599">
    <bounds minlat="34.4660951" minlon="136.7062005" maxlat="34.4880673" maxlon="136.7215013"/>
    <nd ref="253746243" lat="34.4660951" lon="136.7215013"/>
    <nd ref="1815327956" lat="34.4661111" lon="136.7212954"/>
(中略)
    <tag k="source" v="Bing 2007;GSImaps/std"/>
    <tag k="surface" v="paved"/>
  </way>
(後略)

のように、wayの要素内にnd要素があり、これに緯度経度の情報が付加されています。

一方、後者の場合は、

<?xml version="1.0" encoding="UTF-8"?>
<osm version="0.6" generator="Overpass API 0.7.59 e21c39fe">
<note>The data included in this document is from www.openstreetmap.org. The data is made available under ODbL.</note>
<meta osm_base="2022-12-19T07:27:07Z"/>

  <node id="253746243" lat="34.4660951" lon="136.7215013"/>
  <node id="253746281" lat="34.4771808" lon="136.7095462"/>
(中略)
  <way id="50049599">
    <nd ref="253746243"/>
    <nd ref="1815327956"/>
(中略)
  </way>
(後略)

のように、 way 要素内にある nd 要素には node 要素のIDのみが記されており、対応するid属性を持つnode要素に緯度経度が記されています。

node もまとめて表示されるケース

ちなみに、

way({{bbox}})["highway"];
out;

とすると、

のような警告が表示されます。これは、通常 out (out body) だと、way を構成する node の情報として id は含まれますが、その node の緯度経度がないため、描画できないためです。

なので、『クエリの修復』を行うと

way({{bbox}})["highway"];
/*added by auto repair*/
(._;>;);
/*end of auto repair*/
out;

のようになります。もちろん、これでもよいのですが、この場合、node によっては交差点や信号なども表示されることがあります。

再帰

さきほどの例は、こうも書けます。

way({{bbox}})["highway"];
//(._;>;);
(._;node(w););
out;

node(w) は入力集合の way に対する node を返すというフィルタ)だそうです。

さきほどの > (再帰下降クエリ))との違いは、再帰下降クエリの場合は、入力集合にリレーションがある場合、そのリレーションのメンバーである way や node も出力する、ということのようです。

なので、上記の例では同じ結果になりましたが、入力集合によっては異なる結果になりそうです。

ちなみに、再帰下降クエリと >> (再帰下降リレーションクエリ))の違いは、リレーションのメンバーにリレーションが含まれた場合に、さらにそのリレーションのメンバーも含めるかどうか、ということのようです。

再帰フィルタや再帰クエリはいろいろなバリエーションがあるようなので、詳しくはマニュアルをご覧ください。

まとめ

いろいろと試していくと、だんだんとやり方が見えてきました。

ですが、上記の基本的な部分のほかに、頭を悩ませたものに、 area があります。長くなるので、そちらはまた別の記事にまとめたいと思います。

Rainloop 1.17.0 にアップデートしました(Rainloop 開発停止?)

昨年末以来, Rainloop の開発が滞っているようです。もともと、あんまり活発に開発されている印象がなかったのですが、特に問題もなかったので、利用していました。

が、ふと思い立って、webサイトを見ると、有料版がなくなってます。

あれれ?と思って調べてみると、どうも、2022年の9月ごろに、有料版を取りやめて、既存の Community Edition を Legacy Edition として、提供する形になったようです(このタイミングでライセンスも AGPL v3 から MIT に替わっています)。

Wayback Machine で調べてみると、ちょうどそのころに、有料版の記載もなくなったようです。

Wayback Machine

また、 GitHub にも 2022/9/1 のコミットを受けて、 1.17.0 が Legacy Edition としてリリースされています。

Rainloop 自体はまだ生きてるようですが、こちらの issue の印象だとこの先はあんまり期待できそうもありません。ちょうど、2021年末に見つかったセキュリティ関係への対応で、応答がないということで、結構話題になっていました。

さて、どうするかな?

いろいろと代替できるものはありますし、

https://alternativeto.net/software/rainloop/

Rainloop の後継をうたう、 SnappyMail とかもあります。

このまま使い続けるのも不安なのですが、とはいえ、次に何を使うのかを選定するのも時間がかかるので、取り急ぎ 1.17.0 へアップデートしておきます。

一応 1.17.0 は上記のセキュリティ問題へも対応済みのようですし、これで当座をしのぐことにします。

アップデート

アップデートは、過去の記事で書いた際と同じ方法でできます。ダウンロードのURLとして下記に切り替えるだけです。

ubuntu@ip-172-30-0-235:~$ wget https://github.com/RainLoop/rainloop-webmail/releases/download/v1.17.0/rainloop-legacy-1.17.0.zip

特に問題なく、アップデートできました。

まとめ

OSS は便利なのですが、こういう開発停止(もしくは停滞)というのが難しいところですね。もちろん、後継のプロジェクトもあるので、それまで利用していたものがまったく使えなくなるわけでもないんですがね。

この冬休みは、 Rainloop の後継探しになりそうな予感です。