Overpass QL - izudon/izudon.github.io GitHub Wiki
0. Overpass QL とは・・・
- OpenStreetMap からデータを取り出すためのクエリ(問合せ)言語。
データベースには SQL を投げて結果セットを取り出すように、
OpenStreetMap には Overpass QL を投げて結果セットを取り出す。 - OpenStreetMap に特化して開発された言語であり、
他に転用の効かないココだけの知識ではあるが、
OpenStreetMap から 120% のパワーを引き出そうという
フル活用派のアナタにはまさにうってつけの言語である。 - なお、overpass とは、陸橋、跨線橋という意味であり、
ネットワークやOSといったハードルを超えて提供しようという
作り手側の心意気が感じられるネーミングだと筆者は勝手に思っている。
1. OpenStreetMap のデータ構造
OpenStreetMap のデータは
- ノード
- ウェイ
- リレーション
の3種からなる。
説明上、よく
- ノード(点)
- ウェイ(直線)
- エリア(面)
の3種類だと説明されることがあるが、これは便宜上のものであって。 実際には「エリア(面)」は、 開始点(ノード)と終着点(ノード)が同一である 「ウェイ」の一種としてデータ化されている。
すなわち、金魚すくいのあみ(ポイ)のような形 (都営地下鉄大江戸線のような形)も、ウェイとして表現される。 生垣や柵のように面がなく外周だけのものもウェイである。
OpenStreetMap ではこれら3種のデータに「タグ」と呼ばれる
メタ情報(追加情報)をくっつけて、多様な地物を表現していく。
上述の「エリア(面)」も、
「閉じたウェイ」に「area=yes
」というタグをくっつけたものとして表現する。
何をどういうタグで表現するかというこの辺の細かい取り決めは、 OpenStreetMap の発展とともに、慣習的に固まってきた経緯があるようだ。
1.1 ノードとは
地理上の位置を示す「点」である。
すべてのノードには一意の id
(番号)が付与されている。
石碑や案内板、街灯などといった地物はそれぞれノードそれ単体で表現できる。
1.2 ウェイとは
ノードをある一定の順序に従って束ねたものである。
束ねるノードは、約 2,000個を上限とすることが推奨されている。
同じノードが複数のウェイによって使われることがありえる。 例えば、2つの道がクロスする場所(俗にいう交差点)は、 ひとつのノードを2つのウェイによって共有することで表現できる。
1.3 リレーションとは
ノード、ウェイ、またはリレーションを、1つ以上束ねたものである。
例えば、日本の国道1号線などは、途中分岐もあり、ひじょうに長く、 またウェイとしての束ねるノードに 2,000 個の推奨上限もあることから、 これを複数のウェイをまとめたものとして表現する。
あるいは、交差点における右左折の制約なども、 交差点における複数ウェイ間のリレーションとして表現している。
お分かりのように、これら ノード、ウェイ、リレーションというのは、 地物や道に対するあらゆる情報が格納できるための仕掛け、 すなわち箱、容れ物に過ぎず、 具体的に何をどのように格納するのかはこれだけではまったく自明ではない。
そのやり方はひとえに、「タグ」をどのように付与するのかという、 慣習的に決められてきたルールに従っていくこととなる。
1.4 タグとは
ノード、ウェイ、リレーションに、メタ情報を与える仕掛けである。
すべてのタグは name=value
の形をとっており、
ノード、ウェイ、リレーションにはこれを好きなだけ付加することができる。
area=yes
1.4.1 寺社仏閣や駐車場などの敷地、ため池、公園などは、
閉じたウェイに area=yes
をタグとして付加することで、
エリア(面)を表現する。
building=yes
1.4.2 住居やビルなどの建物は、閉じたウェイに building=yes
という
タグをつけることによって表現する。
この際、yes
を使わずに
building=house
とすることで家屋building=garage
とすることで車庫building=school
とすることで学校
などを表現することが、慣習的に定まってきている。
1.4.3 従って・・・
閉じてもいないウェイやノードに area=yes
building=yes
をつけることは、
従って、物理的に出来てしまうとはいえ誤りである。
ただ、この手の誤りは機械的に判定が可能なので、クライアント側で取り除いたり、 OpenStreetMap 側の日次バッチか何かでチェックするなどしているはずである (あくまで予想)。
1.4.4 Wiki が頼りになる
何をどう表現すべきかの情報源としては、 なるほど必ずしも最新のルールが反映されているとは限らないものの、 全体としては下記の Wiki がおそやくもっとも頼りになる (概ねこれに従っておけば問題はない)。
仮に間違えても、親切なベテランの方が直してくださることもよくあるので、 初めは臆せず書き込んでみることを、筆者としてはお勧めしたい。
1.5 情報源
2. Overpass QL
2.0 概要
まずはサンプルを眺めてみたい・・・。
みてお分かりの通り、各命令は ;
によって区切られている。
[out:json][timeout:25];
area[name="Bonn"];
node(area)[highway=bus_stop];
node(around:100)[amenity=cinema];
out;
2.0.1 設定
最初の1行は「設定」である。
[out=json]
は、アウトプットをJSON形式で行うことを指示している。[timeout:25]
は、処理のタイムアウト時間を25秒と指定している。
他にどんなものがあるかはドキュメントを参照のこと。
2.0.2 フィルタ
続く3行はデータの「フィルタ」である。
- 膨大な地球全体のデータの中から・・・
area[name="Bonn"];
で、name
にBonn
と設定されたエリア (閉じたウェイ)の内部の要素へと絞り込み・・・node(area)[highway=bus_stop];
で、highway
にbus_stop
と 設定された「ノード」へとさらに絞り込み・・・node(around:100)[amenity=cinema];
で、それら「ノード」から 「100メートル圏内」にある、amenity
にcinema
が設定された「ノード」 を抽出している。
- つまり、ドイツのボンにある、バス停から100メートル圏内の映画館を 探し出している。
次節でここの中身を詳しくみていく。
2.0.3 出力指示
最後の out;
は、結果出力の指示である。
出力情報にタグ情報を含めるか、経緯度情報を含めるか、id
のみか、
などをオプション指定できる(詳しくはドキュメント参照)。
2.0.4 結果セットへの演算
お分かりのように、フィルタを1文通るたびに結果セットが変化する。
- 最初
- -> 結果セットは「全データ」。
area[name="Bonn"];
- -> ドイツのボンというエリア。
node(area)[highway=bus_stop];
- -> それらのうち「バス停」を示すタグのついたノード。
node(around:100)[amenity=cinema];
- -> それらの周囲100メートル圏内で「映画館」を示すノード。
このように、各フィルタ構文は、
- 現在の結果セットに作用し、
- それをもとに演算をして別の結果セットを出力する
という効果がある。
結果セット -> フィルタ構文 -> 別の結果セット
ちなみに、ある時点での結果セットを変数に格納しておき、 別の場面で使うということも可能である(後述)。
では、どんなフィルタ構文があるのかそのいくつかをみていこう。
2.1 フィルタ構文
基本的なフィルタは
node
way
relation
またはrel
area
上記いずれかのワードで始まる。それぞれ
- ノード
- ウェイ
- リレーション
- エリア すなわち
area=yes
がタグ付けされた閉じたウェイ
を、結果セットとして返す。
2.1.1 タグフィルタ
これら基本的なフィルタには、 タグの内容で絞り込みをかけることができる。
area[name=Bonn]
- ->
name
にBonn
と設定されたエリア。
- ->
area[building]
- ->
building
タグが付与されたエリア。
- ->
node[amenity=cinema][name~"^OS"]
- -> "OS" ではじまる名前を持つ映画館のノード
見ての通り、タグフィルタは、
- 連続して書くことで AND の意味を持たせることができる。
- key だけでも(value を指定しなくても)条件として使える。
- 正規表現を使うことができる。
これ以外に、論理否定なども使うことができる。
これ以降ドキュメントを参照。
2.1.2 バウンディングボックス
() に続けて経緯度範囲を指定することで、 結果セットをその範囲内のものに限定することができる。
node[amenity=cinema]( 50.6, 7.0, 50.8, 7.3 );
終点経緯度は始点経緯度よりも必ず大きくなくてはならず、 逆転しているとエラーになる(不親切ではあるが)。
2.1.3 その他
その他、以下のような限定詞が使える。
(around:距離)
- 入力集合から一定距離内にある要素。
(around:距離,緯度,経度)
- 指定の緯度経度から一定距離内にある要素。
(poly:"緯度_1 経度_1 緯度_2 経度_2 緯度_3 経度_3 ...")
- 指定した多角形の内側にある要素。
(newer:"2012-09-14T07:00:00Z")
- 指定日時以降に追加された要素。
(changed:"2012-09-14T07:00:00Z")
- 指定日時以降に更新された要素。
(changed:"2012-09-14T07:00:00Z","2012-09-14T07:01:00Z")
- 指定日時から指定日時までの間に更新された要素。
(user:"Steve")
- 最後に手を加えたのがその人である要素。
(uid:1)
- 最後に手を加えた人のユーザIDがその番号である要素。
(area...)
例:node[amenity=cinema](area[name=Bonn]);
- 当該エリア内にある要素|エリアはフィルタ構文。
(area:2400000001)
- 当該IDをもつエリア内にある要素。
(pivot)
- 与えられたエリアの輪郭を定義する要素。
詳細はドキュメント参照。
2.2 上へ再帰(Recurse up)下へ再帰(Recurse down)
<
)とは・・・
2.2.1 上へ再起(Recurse up - 入力 セットに現れる ノード を要素とするべての ウェイ +(プラス)
- 入力 セットに現れる ノード または ウェイ を要素とするべての リレーション +(プラス)
- 結果 セットに現れる ウェイ を要素とするべての リレーション
<;
- 要するに 一部でもその ノード や ウェイ を含む ウェイ や リレーション ならば、
それらは 全部含む ことにするような操作である。
<<
2.2.2 - 上記を2段階やった結果に等しいということだと思う。
>
)とは・・・
2.2.3 下へ再起(Recurse down - 入力 セットに現れる ウェイ の要素であるべての ノード +(プラス)
- 入力 セットに現れる リレーション の要素であるべての ノード および ウェイ +(プラス)
- 結果 セットに現れる ウェイ の要素であるべての ノード
>;
- 要するに ウェイ リレーション を一段階 グループ化の解除 しつつも、
もとの ウェイ リレーション をやはり温存しておくというような操作である。
>>
2.2.4 - 上記を2段階やった結果に等しいということだと思う。すなわち、
ウェイ リレーション はすべて ノード レベルへと粉々に分解されたのちに、
最初の ウェイ リレーション 並びに、中間生成物である ウェイ リレーション をまた、
結果セットに中には温存しておくというような操作である。