Amazon Athenaで地理空間データのクエリをしてみた(地理空間関係関数)

2022.01.10

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは、CX事業本部 IoT事業部の若槻です。

Amazon Athenaでは、Prestoエンジンが使われているため、地理空間関数(Geospatial Functions)をサポートしており、地理空間データのクエリが可能です。

今回は、Amazon Athenaで使用できる地理空間関数のうち、地理空間関係関数の動作をいくつか確認してみました。

地理空間関係関数とは

地理空間関係関数(Geospatial Relationship Functions)とは、地理空間関数の1種で、2つの異なるジオメトリ間の関係をboolean型で取得することができます。

地理空間関係関数には次のような種類があります。

  • ST_Contains(geometry, geometry)
  • ST_Crosses(geometry, geometry)
  • ST_Disjoint(geometry, geometry)
  • ST_Equals(geometry, geometry)
  • ST_Intersects(geometry, geometry)
  • ST_Overlaps(geometry, geometry)
  • ST_Relate(geometry, geometry, varchar)
  • ST_Touches(geometry, geometry)
  • ST_Within(geometry, geometry)

今回は、これらのうち始めの3つを試してみたいと思います。

やってみた

前提として、エンジンバージョン2を使用します。

ST_Contains(geometry, geometry)

ST_Contains(geometry, geometry)は、左ジオメトリに右ジオメトリが含まれている場合に限りTRUEを返します。

ポリゴンとポリゴンを指定した場合

まずはポリゴンとポリゴンを指定してみます。POLYGONは、一連の座標を直線で接続した幾何学図形(ポリゴン)を定義します。

SELECT ST_Contains('POLYGON((0 2,1 1,0 -1,0 2))', 'POLYGON((-1 3,2 1,0 -3,-1 3))')

右のポリゴンが左のポリゴンに含まれていないため、クエリ実行結果はfalseとなります。

両ポリゴンの位置関係を図示すると次のようになります。不慣れですがSVGで描いてみました。右のポリゴン(青色)が左のポリゴン(黒色)を含んでいますね。

<svg viewBox="-3 -4 10 10" xmlns="http://www.w3.org/2000/svg">

  <polygon points="0 2,1 1,0 -1,0 2"
    fill="none" stroke="black" stroke-width="0.05"
  />

  <polygon points="-1 3,2 1,0 -3,-1 3"
  fill="none" stroke="blue" stroke-width="0.05"
/>
</svg>

よってポリゴンの指定を左右反対にするとクエリ実行結果はtrueとなります。

SELECT ST_Contains('POLYGON((-1 3,2 1,0 -3,-1 3))', 'POLYGON((0 2,1 1,0 -1,0 2))')

ポリゴンとポイントを指定した場合

次にポリゴンとポイントを指定してみます。

SELECT ST_Contains('POLYGON((0 2,1 1,0 -1,0 2))', ST_Point(0, 0))

左のポリゴンに右のポイントが含まれていないためfalseとなります。

位置関係を図示すると次のようになります。ポイント(赤色)がポリゴン(青色)の線上に位置しているため含まれない判定となっているようです。

<svg viewBox="-2 -2 10 10" xmlns="http://www.w3.org/2000/svg">

  <polygon
    points="0 2,1 1,0 -1,0 2"
    fill="none" stroke="blue" stroke-width="0.05"
  />

  <circle cx="0" cy="0" r="0.1" fill="#e00" />

</svg>

ポイントの位置をポリゴンに含まれるようにずらすと、クエリ実行結果はtrueとなりました。

SELECT ST_Contains('POLYGON((0 2,1 1,0 -1,0 2))', ST_Point(0.5, 1))

ずらした後の位置関係を図示すると次のようになります。

<svg viewBox="-2 -2 10 10" xmlns="http://www.w3.org/2000/svg">

  <polygon
    points="0 2,1 1,0 -1,0 2"
    fill="none" stroke="blue" stroke-width="0.05"
  />

  <circle cx="0.5" cy="1" r="0.1" fill="#e00" />

</svg>

ST_Crosses(geometry, geometry)

ST_Crosses(geometry, geometry)は、左ジオメトリと右ジオメトリがクロスする場合に限りTRUEを返します。

ここではラインを2つ指定します。ST_Lineで指定した座標でラインを表現します。

SELECT ST_Crosses(ST_Line('linestring(1 1, 2 2 )'), ST_Line('linestring(0 1, 2 2)'))

クロスしていないためクエリ実行結果はfalseとなりました。

上記の位置関係を図示すると次のようになります。ラインが接してはいますがこれではクロス判定とならないようです。

<svg viewBox="-0.5 0.5 5 5" xmlns="http://www.w3.org/2000/svg">

  <polyline
    points="1 1, 2 2"
    fill="none" stroke="black"
    stroke-width="0.05"
  />

  <polyline
    points="0 1, 2 2"
    fill="none" stroke="blue"
    stroke-width="0.05"
  />

</svg>

クロスするように右ジオメトリ(黒色)の座標を変更してみます。

SELECT ST_Crosses(ST_Line('linestring(10 10, 0 20)'), ST_Line('linestring(0 10, 20 20)'))

trueとなりました。

変更後の位置関係を図示すると次のようになります。ラインがちゃんとクロスしています。

<svg viewBox="-0.5 0.5 5 5" xmlns="http://www.w3.org/2000/svg">

  <polyline
    points="1 1, 0 2"
    fill="none" stroke="black"
    stroke-width="0.05"
  />

  <polyline
    points="0 1, 2 2"
    fill="none" stroke="blue"
    stroke-width="0.05"
  />

</svg>

ST_Disjoint(geometry, geometry)

ST_Disjoint(geometry, geometry)は、左ジオメトリと右ジオメトリが共通部分が空(クロスしていない)の場合に限りTRUEを返します。

SELECT ST_Disjoint(ST_Line('linestring(0 0, 0 1)'), ST_Line('linestring(1 1, 1 0)'))

指定したライン同士がクロスしていないためクエリ実行結果はtrueとなりました。

上記の位置関係を図示すると次のようになります。ラインが平行になっておりクロスしていません。

<svg viewBox="-0.5 -0.5 5 5" xmlns="http://www.w3.org/2000/svg">

  <polyline
    points="0 0, 0 1"
    fill="none" stroke="black"
    stroke-width="0.05"
  />

  <polyline
    points="1 1, 1 0"
    fill="none" stroke="blue"
    stroke-width="0.05"
  />

</svg>

クロスするように右ジオメトリ(黒色)の座標を変更してみます。

SELECT ST_Disjoint(ST_Line('linestring(0 0.5, 2 0.5)'), ST_Line('linestring(1 1, 1 0)'))

するとクエリ実行結果はfalseとなりました。

変更後の位置関係を図示すると次のようになります。ラインがクロスしています。

<svg viewBox="-0.5 -0.5 5 5" xmlns="http://www.w3.org/2000/svg">

  <polyline
    points="0 0.5, 2 0.5"
    fill="none" stroke="black"
    stroke-width="0.05"
  />

  <polyline
    points="1 1, 1 0"
    fill="none" stroke="blue"
    stroke-width="0.05"
  />

</svg>

おわりに

Amazon Athenaで使用できる地理空間関数のうち、地理空間関係関数の動作をいくつか確認してみました。

今まではAthenaでデータをクエリするとなると、データのフィルターやジョインなどの操作がほとんどだったので、地理空間関数は新鮮でした。

また座標の数値だけでジオメトリ間の位置関係をイメージするのが大変だったので、SVGで図示する方法を見つけられて良かったです。

参考

以上