注:本記事は(2022年6月27日)に公開された(Getting Started with GEOGRAPHY Data—Why Don’t Planes Fly in a Straight Line?)を翻訳して公開したものです。

昨年6月、Snowflakeは、geographyデータ型を使用した地理空間データを一般公開しました。それ以来、地理空間クエリ数は大幅に増加しています。その人気が高まると同時に、Snowflakeユーザーからは、地理空間データを使用してビジネスインサイトを充実させる方法についての質問も増えました。このブログ記事では、地理空間データを初めて使用する方が基本を理解し、Snowflakeを使い始めるのに役立つ情報を紹介し、さらにこの地理空間に焦点を当てたクイックスタートガイドを開始しようとしている方にとっては、事前に知っておきたい情報を紹介します。

地理学(geography)の基本:なぜ飛行機はまっすぐ飛ばないのか?

私たちは、地球を視覚的に表示したものをよく目にしています。年齢によっては、教室の壁に貼られていた地図のポスターを覚えている方もいるでしょう。社会の先生の机には地球儀があったかもしれません。あるいは車の中に地図帳を置いていた人もいるでしょう。しかし、今ではほとんどの人がスマートフォンで今いる場所やこれから行く場所を見る機会が多いと思います。

ここでは、先生の机にあった地球儀を思い出してみましょう。子どもの頃(または大人でも)、地球儀を回して、回転する球体の滑らかな表面に指をすべらせた経験があると思います。地球儀上で自分のいる場所を探したり、行ってみたい国や大陸への行き方を考えたり、今いる場所から別の場所までの道筋を指で辿ってみたりしませんでしたか。おそらく、それは最短のルートではなかった可能性があります。

上の画像を見てください。ベルリンからサンフランシスコまでの飛行する時に、航空会社から、アイスランド、グリーンランド、カナダの上空を飛ぶよう指示されたらどう思いますか。「何を言っているんだ」と思うと思います。弧を描くよりも、ベルリンからサンフランシスコまで直線で飛んだ方が明らかにフライト時間は短いはずです。以下の図を見てください。

断然短く見えますよね、でも実はそうではないんです。その理由は、Snowflakeのgeographyデータ型の核心を理解することにつながります。測地線ユークリッドの計測方法の違いです。簡単に言うと、測地線の計測は3D球形に基づき、曲率全体の距離を測定しますが、ユークリッド測定は、上の画像のように普段見慣れている平らな2D形状に基づきます。最初の画像の線を球形の視点から見ると、飛行機がその飛行経路を選ぶ理由が見えてきます。

Snowflakeのgeographyデータ型では、緯度と経度に基づく座標系を使用して地球を球形オブジェクトとして表すための標準である最新の世界測地学システムWGS 84を使用し、この3D曲率を考慮しています。geographyデータ型のサポートについてさらに掘り下げてみましょう(ユークリッド2D派の方も、パート2でユークリッド2D法について取り上げますのでご安心ください)。

地理空間フォーマット、関数、オブジェクトタイプ

geographyデータ型は、3つの基本概念を理解するとスムーズに理解できます。

  • 地理空間データフォーマット
  • 地理空間オブジェクトタイプ(「ディメンション」とも呼ばれる)
  • 地理空間関数と適用方法

まずは地理空間データフォーマットから見ていきましょう。これらのフォーマットは、入力フォーマット(geographyデータ型へのデータの読み込み)であると同時に出力フォーマット(geography型カラムからクエリした時にデータが表示される形式)でもあります。Snowflakeでは、3つの主なフォーマットをサポートしています。(E)WKT -(拡張)Well-Known Text、(E)WKB -(拡張)Well-Known Binary、GeoJSONです。以下の表は、ラスベガスにあるベラージオの噴水(Snowflakeサミット2022の開催地である都市にちなんで出題してみました)の経度と緯度の3つのフォーマットと拡張変数、およびクエリ出力表現を示しています。

上記の表では、セッションパラメータ「GEOGRAPHY_OUTPUT_FORMAT」の使用にも注意する必要があります。これは、アンロード操作後にgeography出力がSnowflakeまたはファイルにどのように表示されるかを制御します。

ベラージオの噴水に関する上記の出力表現では、出力は特定のオブジェクトタイプ、または地理空間ディメンションタイプ(POINT)を示しています。次の表のように、単一のオブジェクトや複数のオブジェクトのグループなど、さまざまなオブジェクトタイプがあります。

面積、周長、交点の計算など、小学校の算数の授業を思い出して憂鬱な気分になる必要はありません。地理空間関数側でgeography型オブジェクトの操作方法を把握しているため、簡単に計算を行えます。地理空間関数のカテゴリとそれぞれの例、さらにSQLでの使用方法のサンプルを見ていきましょう。すべての関数のリストについては、こちらで確認できます。

さまざまなタイプの関数を利用できるだけでなく、SELECT句、クエリ述語、JOIN句など、関数の使い方も複数あります。それぞれ異なる関数を使用した使用例を見ていきましょう。

クエリの例

SELECTでの変換

この例は前のフォーマットセクションでもお見せしましたが、今回はSELECT句のTO_GEOGRAPHYの使用について見てみましょう。ここで行われているのは、地理空間データとして適切にフォーマットされた文字列(‘POINT (-115.174016 36.112650)’)を渡し、これを地理空間関数で使用できる真の地理空間データ型オブジェクトに変換します。この文字列をTO_GEOGRAPHY関数で囲まなければ、Snowflakeはこの文字列が地理空間データであると判別できません。この例では、このクエリの出力が実際にGeoJSONの地理空間データであることを示すことで、WKT文字列を反復しているだけではないため、変換ポイントがさらにホームに送られます。

文字列について簡単に説明します。座標-115.174016 36.112650は、インターネット上に多数ある、インタラクティブマップ上のポイントをクリックすると経度と緯度の座標を出力するウェブサイトの一つから取得した値です。後ほど出てきますが、テーブルの中にポリゴンの形としてベラージオの噴水もあります。高品質ですぐにクエリできる地理空間データが必要な場合は、Snowflakeアカウント内からすぐにアクセスできる地理空間を中心とした多数のリストがSnowflake Marketplaceにあります。

SELECTでの変換と計測

上の1つ目のクエリは非常にシンプルで、テーブルクエリでさえありません。4行目のコメントにあるように、ベラージオの噴水ポイントに最も近い建物のテーブルの中の行を見つけようとしています。これを行うには、噴水とテーブル内のすべての行との間の距離を計測し、距離を昇順で並び替え、結果を1行目(=最も近い)に絞り込みます。(こっそり正解をお教えすると、ベラージオ噴水に最も近い建物はベラージオホテルです)

ここで行われる内容:

  • ST_MAKEPOINTは、TO_GEOGRAPHYと非常に似ていますが、POINT限定です。構文は少し異なり、経度と緯度の値を(この順序で)フィードするだけで、周囲に余分なテキストはありませんが、結果は同じです。
  • ST_DISTANCEは、2つのオブジェクト間(上の箇条書きで作成された噴水POINTと、それ自体がgeography-型列であるbuildingテーブルのshape列)の距離をメートル単位で計算します。
  • Snowflakeの他の数値と同じように、上記の箇条書きで計算された数値に対して並べ替えを実行できます。

WHERE句のリレーションシップ比較

何かの測定値を計算する代わりに、関数を使用して、オブジェクトが互いにどのように関連しているかを調べます。上記のクエリは、先ほど行った距離の計算に似ていますが、2つのオブジェクト間の最短距離を見つける代わりに、オブジェクトが互いにスペースを共有しているか、交差しているかどうかを確認しています。これは、WHERE句で交差するか、交差しないかを評価する条件です。

ここで行われる内容:

  • このクエリでは先ほどと同じbuildings(建物)テーブルを使用しますが、2つ目のテーブルall_objectsも登場します。前者は特定の地点タイプで、後者にはすべての地点のポリゴンが含まれ、ベラージオの噴水用のポリゴンもあり、値はway_id=22971030です。これで、面倒なリサーチなしにこの行を簡単に見つけるこができました。
  • その後、ST_INTERSECTSbuilding内のshapeを調べ、all_objectsに対するサブクエリを実行して見つかった形状と交差するかどうかを確認します。答えがTRUEの場合は、行が返されます。FALSEの場合は返されません。TRUEの結果を探している場合は、すでに暗示されているため条件に=TRUEと指定する必要はありませんが、交差しない行を返したい場合は=FALSEを含める必要があります。

JOIN句のリレーションシップ比較

前のリレーションシップクエリでは、サブクエリを実行して特定のオブジェクトの形状を返し、そのオブジェクトを特定のテーブルのすべての行と比較しました。しかし、あるテーブルの多数の行を別のテーブルの多数の行と比較したい場合はどうでしょうか。このクエリでは、単純なt1.column = t2.column 条件を使用するのではなく、2つのテーブル間の結合の条件として地理空間関数を使用し、2つの方法で記述できます。

ここで行われる内容:

  • ST_DWITHINが、2つのオブジェクトが互いに特定のメートルの距離内にあるかどうかを確認します。これはST_DISTANCE() <= [meters]の記述に相当します。ここでの2つのオブジェクトは、それぞれsportsテーブルとcemeteryテーブル内の形状です(念のため、これらのテーブル名には深い意味はありません)。
  • 18行目から始まるクエリは、WHERE句で表現された結合条件を使用して記述されています。23行目から始まるクエリは、ANSI SQL JOIN句を使用して記述されており、どちらも同じように正確で高性能です。この例のJOINは完全なデカルト積のCROSS JOINではないかと思われたでしょうか?そのとおりです。ただし、Snowflakeはこの種の地理空間結合で低速のCROSS JOINを使用しないため、Snowflakeの地理空間結合ではCROSS JOINを指定しないでください。代わりに、この種のクエリに対してより最適化された結合テクニックがあります。

このブログ記事で紹介したサンプルクエリはほんの一例です。クイックスタートではここで紹介したものよりも多くの地理空間関数の使用方法を学ぶことができますが、この記事で十分な予備知識を身に付けていただけることを願っています。

パート2もお楽しみに

まとめると、Snowflakeが導入した地理空間のgeographyデータ型機能では、一般的な地理空間フォーマットを使用してSnowflakeでデータを表示でき、特殊な関数を使用してそのデータをクエリできます。geographyは、地球を球体として扱い、2次元の直線ではなく、曲線に沿った測地線を使用して測定値を計算するWGS84を使用します。パート2では、Snowflakeがこの機能を拡張して、より多くの種類の地理空間データに対するクエリに対応する方法について説明します。