Databricksにおける地理空間情報の処理と分析のためのビルトインH3エクスプレッションの発表

[Announcing Built\-in H3 Expressions for Geospatial Processing and Analytics \- The Databricks Blog](https://www.databricks.com/blog/2022/09/14/announcing-built-h3-expressions-geospatial-processing-and-analytics.html)の翻訳です。

:::note warn
本書は抄訳であり内容の正確性を保証するものではありません。正確な内容に関しては原文を参照ください。
:::

Databricksランタイム11.2は、Databricksと地理空間情報を処理、分析しているお客様にとってのマイルストーンリリースとなります。11.2のリリースではGA(正式提供)として、効率的な地理空間情報の処理や分析のための28個のビルトインH3エクスプレッションが含まれています。この記事では、H3とは何か、従来の地理空間データ処理に対してどの様な優位性を提供するのか、DatabricksでどのようにH3を使い始められるのかを説明します。最終的には、H3を用いることで、WKT、WKB、Lat/Lon、GeoJSONのような一般的なフォーマットから空間データをH3のセルIDに容易に変換し、効率的な方法でデータを空間的に集計、join、可視化できる様になります。

# H3とは？

H3に初めて触れる人のために簡単な説明をします。

H3は同名のグローバルインデクシングシステムとライブラリとなります。もともとは、空間データパターンを可視化、探索する目的においてUberによって開発されました。グリッドシステムは、表面(この場合は地球の表面)のモザイクを形成するために長方形や三角形の様なシェイプをしようします。階層型グリッドシステムは、異なる解像度でモザイクを形成します(基本的なシェイプは異なるサイズで提供されます)。H3システムは、六角形(一部五角形)を使用する様に設計され、そして階層型システムとして異なる16の解像度を操作することができます。特定の解像度でデータをインデクシングすると、分析に使用する1つ以上のH3のセルIDが生成されます。例えば、解像度15のH3セルは約1$m^2$(異なるH3の解像度の詳細については[こちら](https://h3geo.org/docs/core-library/restable)をご覧ください)をカバーします。

H3グローバルグリッドインデクシングシステムの詳細な説明については、[こちら](https://www.uber.com/blog/h3/)と[こちら](https://h3geo.org/docs/)をご覧ください。

# H3は広く使用されています

H3は広範な利用パターンに適用でき、高度にスケーラブルなので、さまざまな業界における地理空間データ処理で活用されています。驚くべきことではありませんが、Uberによって構築されたシステムは自動運転システムや膨大な量の空間・時間データを生成するあらゆるIoTデバイスで活用されています。また、H3は一ベースのデータプロダクトで広く使用されており、移動手段に基づく洞察を明らかにすることで、リテールの計画や交通、デリバリー、農業、テレコム、保健のオペレーションをサポートしています。これはH3がどの様に活用されているのかの一部に過ぎません。

# なぜH3を使うのか？

H3システムを用いることで、膨大な量のデータを理解できる様になります。例えば、大規模なNYCのタクシー乗降データセットを用いることで、空間的なパターンをより理解するためにデータを空間的に集計することができます。10億以上のオーバーラップするデータを見たとしても、パターンを特定することはできませんが、H3を活用することで即座にパターンが明らかになり、さらならる探索に取り組める様になります。
![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-1.jpg)
*生データ*
![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-2_1.png)
*H3セルIDによる集計データを用いることで空間パターンを明らかにすることができます*

また、H3セルIDは分断したデータセットをjoinするのに適しています。すなわち、潜在的に高コストな空間述語を用いることなしに、意味論的に空間的なjoinを実行できます。セルIDを用いたデータセットのjoinを行い、位置ドリブンな疑問に答え始めることは非常にわかりやすいものです。H3を用いて空間的な問題を解くのかをさらにデモンストレーションするために、NYCタクシーデータセットを使い続けましょう。

最初に、NYCデータセットを取り込み、乗降位置を解像度15のH3セルを*trips_h3_15*として変換したものとします。同様に、LaGuardiaとNewarkの空港の領域を解像度12に変換し、それぞれの空港に対応するexplodeされたビューを持つ*airports_h3_c*に([h3\_compact](https://docs.databricks.com/spark/latest/spark-sql/language-manual/functions/h3_compact.html)関数を用いて)コンパクト化したものとします。このデータセットにおいては、コンパクト化されたH3セルの解像度は8以上であり、下でこれを活用するということに触れておきます。これで、「LaGuardia空港(LGA)で生じたタクシー乗車が最も多かった地点は？」という質問に答えられる様になります。
![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-2.png)
*LaGuardia空港におけるタクシーピックアップの分析*

これに答えるために*src_airport_trips_h3_c*というビューを生成し、上のように*trip_cnt*で定義される色と*passenger_sum*による高さを用いて[Kepler\.gl](https://kepler.gl/)でレンダリングしました。乗車位置、降車位置と空港を定義するH3セルを関連づけるために、*h3_toparent*と*h3_ischildof*を使用しました。

```sql:SQL
%sql 
create or replace view airport_trips_h3_c as (
  select
    t.passenger_count,
    t.fare_amount,
    src.locationid as src_locationid,
    trg.locationid as trg_locationid,
    src.cell as src_cell,
    trg.cell as trg_cell
  from
    trips_h3_15 t,
    airports_h3_c src,
    airports_h3_c trg
  where
    h3_toparent(t.pickup_cell, 8) = h3_toparent(src.cell, 8)
    and h3_toparent(t.dropoff_cell, 8) = h3_toparent(trg.cell, 8)
    and h3_ischildof(t.pickup_cell, src.cell)
    and h3_ischildof(t.dropoff_cell, trg.cell)
    and src.locationid <> trg.locationid
);
```

そして、Kepler.glのレンダリングに使用したビュー*src_airport_trips_h3_c*のこれらコンパクト化されたセルのピックアップに関係する興味の領域の属性値を合計、カウントしました。

```sql:SQL
create or replace view src_airport_trips_h3_c as (
  select
    src_cell as cell,
    src_locationid as locationid,
    format_number(count(*), 0) as trip_cnt_disp,
    format_number(sum(passenger_count), 0) as passenger_sum_disp,
    (
      '$' || cast(format_number(sum(fare_amount), 2) as string)
    ) as fare_sum_disp,
    count(*) as trip_cnt,
    sum(passenger_count) as passenger_sum,
    sum(fare_amount) as fare_sum
  from
    airport_trips_h3_c
  group by
    cell,
    src_locationid
);
```

DatabricksにおけるH3セルIDは、big integerか文字列として格納することができます。セルIDのbig integer表現を用いた際に、H3のインデックスがされたデータへのクエリーは最も高速になります。これらの表現によって、地理空間データの格納方法をさらに最適化することができます。効率的にデータを*空間的に*隣接させるためにZ-orderingを行うために、Delta Lakeの[OPTIMIZE](https://docs.databricks.com/spark/latest/spark-sql/language-manual/delta-optimize.html)オペレーションを活用することができます。完全にオープンソース化されているDelta Lakeには、読み込む必要があるデータ量をインテリジェントに削減するために局所性を活用するデータスキッピングアルゴリズムが含まれています。

また、H3セルの可視化もシンプルです。最も一般的で人気のあるライブラリのいくつかは、ビルトインでH3データの可視化をサポートしています。お客様は、Kepler.gl([Mosaic](https://databrickslabs.github.io/mosaic/usage/installation.html)でもバンドルされています)の様なライブラリがアタッチされた[クラスター](https://qiita.com/taka_yayoi/items/9407356caadea3dfb47c)や[ノートブック](https://qiita.com/taka_yayoi/items/d3a46efdc1ad01a581d0)や、Databricksの[ODBC、JDBCドライバー](https://docs.databricks.com/integrations/bi/jdbc-odbc-bi.html#configure-the-databricks-odbc-and-jdbc-drivers)を用いて[CARTO](https://carto.com/databricks/spatial-extension/?utm_source=databricks&utm_medium=referral&utm_campaign=H3_launch_blog)のような可視化ツールのインテグレーションを活用することができます。CARTOを用いることで、データにアクセスし、クエリーを行うために直接Databricksクラスターに接続することができます。CARTOのロケーションインテリジェンスプラットフォームによって、大規模データの可視化や分析、動的な集計を可能にするH3の階層化構造を活用することができ、H3のインデックスがなされたデータセットを用いた[空間データカタログ](https://carto.com/spatial-data-catalog/?utm_source=databricks&utm_medium=referral&utm_campaign=H3_launch_blog)も活用することができます。CARTOの活用方法に関しては[こちら](https://youtu.be/DRnGZkUGRRc?t=738)を参照ください。

**リンクをクリックすると別タブで動画が開きます**

https://player.vimeo.com/video/747697475?h=38bc7478ed&amp;version=hd1080

*CARTOを用いたDatabricksでのH3インデックスデータの探索*

# H3を使い始めてみる

以下のウォークスルーのサンプルでは、NYCタクシーデータセットとNewarkとLaGuardia空港の領域を使用します。途中では、乗車、降車、乗客数、空港間の料金に関するいくつかの質問に答えていきます。

DatabricksのH3エクスプレッションを使い始めましょう。最初に、H3エクスプレッションを使用するには、Photonアクセラレーションが有効化されたクラスターを作成する必要があります。これはシンプルであり、チェックボックスをオンにするだけです。
![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-3.png)
*Photon Accelerationをオンにすると、ビルトインのH3エクスプレッションを使用できる様になります*

ノートブックでH3 SQLエクスプレッションのScalaあるいはPythonバインディングを使用している場合、対応するDatabricksのSQL関数バインディングをインポートする必要があります。

ScalaのDatabricksのSQL関数バインディングをインポートするには以下を実行します。

```scala:Scala
import com.databricks.sql.functions._
```

PythonのDatabricksのSQL関数バインディングをインポートするには以下を実行します。

```py:Python
from pyspark.databricks.sql.functions import *
```

データは既に準備されているので、作業するために選択した解像度でデータをインデクシングします。空間的地理情報(ポリゴンやマルチポリゴン)に対しては、関数*h3_polyfillash3*を使用することができます。緯度経度から位置をインデクシングするには、関数*h3_longlatash3*を使用します。我々の例では、解像度12で位置と空港の領域をインデクシングします。

```sql:SQL
%sql 
-- drop table if exists airports_h3;
create table if not exists airports_h3 as (
  select
    locationid,
    explode(h3_polyfillash3(the_geom, 12)) as cell
  from
    airports
)
```

```sql:SQL
%sql 
-- drop table if exists trips_h3;
create table if not exists trips_h3 as (
  select
    h3_longlatash3(pickup_longitude, pickup_latitude, 12) as pickup_cell,
    h3_longlatash3(dropoff_longitude, dropoff_latitude, 12) as dropoff_cell,
    passenger_count,
    fare_amount
  from
    trips
)
```

H3セルIDを用いることで、移動データに関する一連の質問に答えるために、容易にh3のテーブル*airport*と*trips*を組み合わせることができます。空港間で何回移動がありましたか？何人の乗客が運ばれましたか？どれだけの料金が発生しましたか？

```sql:SQL
%sql
select
  format_number(count(*),0) as num_trips,
  format_number(sum(passenger_count),0) as num_passengers,
  (
    '$' || cast(format_number(sum(fare_amount), 2) as string)
  ) as earnings
from
  airport_trips_h3_c
```

![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-4.png)

子データセットを用いて数えきれない質問を投げかけ、探索することができます。H3を用いることで、新たな方法で地理情報データを探索できる様になります。どの空港がもっともピックアップの交通量を生み出したのでしょうか？LaGuardia (LGA)とNewark (EWR)では、LGAの方がはるかにピックアップが多く、LGAで生み出される移動がEWRと比較して割合としては99%以上を占めることになることがわかりました。
![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-5.png)

```sql:SQL
%sql 
create or replace temp view 
src_full_airport_trips_h3_c as (
  select
    cell,
    zone,
    borough,
    trip_cnt_disp,
    passenger_sum_disp,
    fare_sum_disp,
    airports.locationid,
    trip_cnt,
    passenger_sum,
    fare_sum
  from
    src_airport_trips_h3_c
    inner join airports
    on src_airport_trips_h3_c.locationid = airports.locationid
)
```
![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-6.png)

LaGuardia (LGA)から出発する際に最も共通する目的地はどこでしょうか？エアポートから出発した2500万の降車があり、NYCエリアの260のタクシーゾーンをカバーしていることがわかりました。これらの中には、移動に含まれる解像度12の83万8千のユニークなH3セルが存在しています。しかし、集計のパワーによって、容易にゾーンごとの降車イベントの総数を計算し、最も密度が高い領域を黄色にしてKelper.glでレンダリングすることができます。
![](https://cms.databricks.com/sites/default/files/inline-images/db-304-blog-img-7.png)
*ツールチップに表示される様にLGAからJFK空港に移動するピックアップが25万存在しています*

この答えに辿り着く過程で、LGAを表現する`locationid = 132`でフィルタリングされた*trips_h3*テーブルと*airports_h3*テーブルをjoinし、LGAからのピックアップセルに限定しました。これによって、初期の25Mトリップを取得することができます。

```sql:SQL
%sql
create or replace temp view lga_dropoffs as (
  select
    pickup_cell,
    dropoff_cell,
    passenger_count,
    fare_amount,
    air.locationid as pickup_locationid
  from
    trips_h3
    inner join (
      select
        *
      from
        airports_h3
      where
        locationid = 132
    ) air on trips_h3.pickup_cell = air.cell
)
```

ここから、*lga_agg_dropoffs*ビューとして、ユニークな83万8千の降車H3セルに集計しました。

```sql:SQL
%sql
create or replace temp view lga_agg_dropoffs as (
  select
    count(*) as dropoff_cnt,
    dropoff_cell
  from
    lga_dropoffs
  group by
    dropoff_cell
)
```

(ノートブックの[パート2](https://www.databricks.com/wp-content/uploads/notebooks/nb-02_h3_data_analysis_dbr-11.html)で説明されている)次のメインのステップは、ゾーン情報を特定するために取り込んだNYCタクシーゾーンのGeoJSONと*lga_agg_dropoffs*ビューをjoinすることです。最後のステップは、上述のレンダリングした分析結果のために、ゾーンごとのすべての*dropoff_cnt*の最終的な総和を計算することでした。

```sql:SQL
%sql
create or replace temp view lga_agg_zone_dropoffs_h3 as (
  select
    dropoff_cnt,
    dropoff_cell,
    locationid,
    borough,
    zone
  from
    lga_agg_dropoffs
    inner join taxi_zone_explode_h3
    on lga_agg_dropoffs.dropoff_cell = taxi_zone_explode_h3.cell
)
```

この例では、初期データをロードし、集計結果を含む追加のカラムを持つ様々なテーブルとビューを生成するためのDatabricksの既存の強力な機能と、新たに利用できるH3 APIを用いた地理空間処理をブレンドしています。また、空間的レイヤーをレンダリングするためのKepler.glや、Apache Sparkフレームワークの拡張であり、大規模地理空間データセットを容易かつ高速の処理する能力を提供するDatabricks Labsプロジェクトである[Mosaic](https://databrickslabs.github.io/mosaic/index.html)の便利な機能の様な外部のライブラリを組み込みました。

# Databricksで何が使えるのか？

H3を用いて現在Databricksで何ができるのかを詳しく見ていきましょう。数多くのカテゴリー関数をカバーする28のH3関連のエクスプレッションがあります。以下にDatabricksランタイム11.2で利用できるカテゴリーごとのエクスプレッションの完全なセットを示します。

- **Import**
    - h3_longlatash3	
    - h3_longlatash3string
    - h3_polyfillash3
    - h3_polyfillash3string
    - h3_try_polyfillash3 
    - h3_try_polyfillash3string
- **Export**
    - h3_boundaryasgeojson
    - h3_boundaryaswkb
    - h3_boundaryaswkt
    - h3_centerasgeojson
    - h3_centeraswkb
    - h3_centeraswkt
- **Conversions**
    - h3_h3tostring
    - h3_stringtoh3
- **Predicates**
    - h3_ischildof
    - h3_ispentagon
- **Validity**
    - h3_isvalid
    - h3_try_validate
    - h3_validate
- **Distance related**
    - h3_distance
    - h3_hexring
    - h3_kring
    - h3_kringdistances
- **Traversal**
    - h3_resolution
    - h3_tochildren
    - h3_toparent
- **Compaction**
    - h3_compact
    - h3_uncompact

セルIDにはbig integerと文字列表現の両方を使用することができ、H3ライブラリで使用される表現と同じものとなります。なので、既にデータをH3でインデクシングしているのであれば、既存のセルIDを使い続けることができます。H3のセルIDにはbig integer表現を使用すること、既存のH3セルが文字列データである場合にはbig integer表現に変換することを強くお勧めします。big integerと文字列表現の変換は、[h3\_stringtoh3](https://docs.databricks.com/spark/latest/spark-sql/language-manual/functions/h3_stringtoh3.html)や[h3\_h3tostring](https://docs.databricks.com/spark/latest/spark-sql/language-manual/functions/h3_h3tostring.html)エクスプレッションを用いて行うことができます。Databricksランタイム11.2以降には、外部依存関係としてH3ライブラリv.3.7.0が含まれます。H3エクスプレッションのDatabricks実装は、多くのケースで内部のライブラリを使用しますが、排他的なものではありません。

間も無く、全てのH3 SQLエクスプレッションがDatabricks SQLでも利用できる様になります。

DatabricksにおけるH3 SQLエクスプレッションを学ぶのであれば、[こちら](https://docs.databricks.com/spark/latest/spark-sql/language-manual/sql-ref-functions-builtin.html#h3-geospatial-functions)のドキュメントとこの記事で使用した一連のノートブックを参照ください。

- [part 1 \- Data Engineering](https://www.databricks.com/wp-content/uploads/notebooks/db-304-geospatial-h3/nb-01_h3_data_engineering_dbr11-2.html)
- [part 2 \- Analysis](https://www.databricks.com/wp-content/uploads/notebooks/nb-02_h3_data_analysis_dbr-11.html)
- [Helper](https://www.databricks.com/wp-content/uploads/notebooks/mosaic_helpers.py.html)

**訳者注** ノートブックの翻訳版を説明した記事です。

https://qiita.com/taka_yayoi/items/0f5423a93631f3fcd749

### Databricks 無料トライアル

[Databricks 無料トライアル](https://databricks.com/jp/try-databricks)