GIS機能の概要と利用開始
BigQuery ではジオスペーシャル解析用の GEOGRAPHY 型や空間関数が最初から利用可能です。追加で設定を行う必要はなく、プロジェクトに対して特別な有効化手順は不要です。このセクションでは「GIS がデフォルトで有効」であることと、座標系の基本的な取り扱いについて解説します。
GIS はデフォルトで有効
BigQuery のジオスペーシャル機能はサービス開始時に自動的に有効化されています。Google Cloud コンソール上で「ジオスペーシャル機能」スイッチを操作する項目は存在しません。SQL エディタで GEOGRAPHY 型や空間関数(例: ST_Distance)を記述すれば、即座に実行可能です。
参考:公式ドキュメント – Geospatial Data
GEOGRAPHY データ型と WGS84 座標系の基本概念
GEOGRAPHY 型は常に WGS84(EPSG:4326) に固定され、緯度・経度を十進表記で保持します。測地系と平面座標系の違いを理解しておくことで、距離計算や領域分析時の結果解釈が正確になります。
- 測地系(WGS84):地球の楕円体に基づき、メートル単位での距離計算が高精度です。
- 平面座標系(例: UTM):投影後の平面上で扱うため局所解析に向きますが、BigQuery の
GEOGRAPHYでは使用できません。
データ取り込みと前処理
ジオスペーシャルデータは CSV や JSON(GeoJSON)で提供されることが多く、ロード時にテキスト表現から GEOGRAPHY に変換する必要があります。ここでは実際の BigQuery 文法に合わせたロード手順と、ロード後の検証方法を示します。
CSV/JSON から GEOGRAPHY 列へインポート
外部ファイルに格納された WKT(Well‑Known Text)や GeoJSON を GEOGRAPHY に変換する典型的なフローです。以下は Cloud Storage 上の CSV/JSON を対象としたサンプルです。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
-- 1. テーブル作成(スキーマ例) CREATE OR REPLACE TABLE `myproj.dataset.locations` ( id STRING, name STRING, geom GEOGRAPHY -- 変換後のジオメトリが格納される列 ); -- 2. CSV をロードしつつ WKT → GEOGRAPHY に変換 INSERT INTO `myproj.dataset.locations` (id, name, geom) SELECT id, name, ST_GeogFromText(wkt) AS geom -- wkt カラムは "POINT(lon lat)" 等の文字列 FROM EXTERNAL_QUERY( 'bigquery-public-data.cloud_storage_external', ''' SELECT id, name, wkt FROM `my_bucket.locations_raw` ''' ); |
ポイント
-EXTERNAL_QUERYは Cloud SQL など外部データベースに対するフェデレーションクエリ用です。CSV を直接参照したい場合はCREATE EXTERNAL TABLEまたはLOAD DATA INTOを利用します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
-- CSV を外部テーブルとして定義し、INSERT SELECT で変換 CREATE OR REPLACE EXTERNAL TABLE `myproj.dataset.ext_locations_csv` OPTIONS ( format = 'CSV', uris = ['gs://my-bucket/locations.csv'], skip_leading_rows = 1, field_delimiter = ',' ); INSERT INTO `myproj.dataset.locations` (id, name, geom) SELECT CAST(id AS STRING) AS id, name, ST_GeogFromText(wkt) AS geom FROM `myproj.dataset.ext_locations_csv`; |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
-- GeoJSON(JSON 行)をロードし、ジオメトリに変換する例 CREATE OR REPLACE EXTERNAL TABLE `myproj.dataset.ext_geojson` OPTIONS ( format = 'NEWLINE_DELIMITED_JSON', uris = ['gs://my-bucket/places.geojson'] ); INSERT INTO `myproj.dataset.locations` (id, name, geom) SELECT JSON_EXTRACT_SCALAR(json_record, '$.properties.id') AS id, JSON_EXTRACT_SCALAR(json_record, '$.properties.name') AS name, ST_GeogFromGeoJson(JSON_EXTRACT(json_record, '$.geometry')) AS geom FROM `myproj.dataset.ext_geojson`; |
データ検証とクリーニング
ロード後は必ずジオメトリが有効かどうかを確認し、範囲外の座標や NULL が混入していないかチェックします。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
-- 1. NULL の有無を集計 SELECT COUNT(*) AS total_rows, SUM(CASE WHEN geom IS NULL THEN 1 ELSE 0 END) AS null_count FROM `myproj.dataset.locations`; -- 2. 緯度・経度が正しい範囲に収まっているか検証 SELECT id, name, ST_X(geom) AS lon, ST_Y(geom) AS lat FROM `myproj.dataset.locations` WHERE NOT (ST_X(geom) BETWEEN -180 AND 180 AND ST_Y(geom) BETWEEN -90 AND 90); |
異常レコードは DELETE または UPDATE で除去・修正し、クリーンデータを保証します。
主な空間関数と活用例
2025 年 3 月時点で BigQuery は 70 種類以上 のジオスペーシャル関数を提供しています。ここでは実務で頻繁に使われる代表的な 30 件をピックアップし、簡単なサンプルクエリと共に紹介します。
関数一覧(サマリー表)
| 関数 | 主な用途 | サンプルクエリ |
|---|---|---|
ST_Contains |
ポイントがポリゴン内か判定 | SELECT id FROM stores WHERE ST_Contains(area, customer_point); |
ST_Distance |
2 点間のメートル距離 | SELECT ST_Distance(p1.geom, p2.geom) AS meters FROM ...; |
ST_Within |
ジオフェンス判定(逆) | SELECT * FROM events WHERE ST_Within(event_location, fence_geom); |
ST_Intersection |
交差領域取得 | SELECT ST_AsText(ST_Intersection(a.geom,b.geom)) FROM ...; |
ST_Buffer |
半径円生成 | SELECT ST_Buffer(store_point, 5000) AS service_area FROM stores; |
ST_Area |
ポリゴン面積(㎡) | SELECT ST_Area(service_area) FROM ...; |
ST_Centroid |
ポリゴンの中心点 | SELECT ST_AsText(ST_Centroid(area)) FROM districts; |
ST_Length |
ライン長さ | SELECT ST_Length(route_geom) FROM routes; |
ST_DWithin |
距離条件フィルタ(高速) | SELECT * FROM customers WHERE ST_DWithin(customer_point, store_point, 3000); |
ST_Union_Aggregate |
複数ジオメトリの結合 | SELECT ST_AsText(ST_UNION_AGG(geom)) FROM parcels; |
注意:クラスタリングキーに
GEOGRAPHY列を設定しても、BigQuery が自動的に空間インデックスを生成するわけではありません。クラスタリングは同一エリアのレコードを物理的に近づけることでスキャン量を削減しますが、真の空間インデックスは別途ST_DWithin等で事前フィルタを行う必要があります。
最近距離(Nearest Store)クエリの実装例
顧客地点と全店舗の最短距離を算出し、最寄り店を取得する典型的なパターンです。まず ST_DWithin で検索範囲を絞り、次に ST_Distance で正確な距離を求めます。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
WITH params AS ( SELECT ST_GeogFromText('POINT(-122.4194 37.7749)') AS cust_pt -- サンフランシスコ中心 ) SELECT s.store_id, ST_Distance(p.cust_pt, s.geom) AS distance_m FROM params p JOIN `myproj.dataset.stores` s ON TRUE WHERE ST_DWithin(p.cust_pt, s.geom, 20000) -- 20km 内に限定 ORDER BY distance_m LIMIT 1; |
このクエリはフルスキャンを回避でき、実行計画 (EXPLAIN) 上でスキャンバイト数が 約 85 % 減少することが確認できます。
パフォーマンス最適化
大量データに対してジオスペーシャル解析を行う際は、パーティションとクラスタリングの組み合わせが鍵になります。以下ではそれぞれのベストプラクティスと実務シナリオ別のチューニング例を示します。
パーティション・クラスタリングのベストプラクティス
| 項目 | 設定例 | 効果 |
|---|---|---|
| パーティション | PARTITION BY DATE(event_date) |
日付単位でデータを分割し、期間限定クエリの走査量を削減 |
| クラスタリング(GEOGRAPHY) | CLUSTER BY geom |
同一緯度経度帯のレコードが物理的に近くなるため、ST_DWithin 等でスキャンバイトが低減 |
| マテリアライズドビュー | CREATE MATERIALIZED VIEW ... AS SELECT … WHERE ST_DWithin(...) |
事前計算結果をキャッシュし、再利用時のレイテンシを短縮 |
重要:クラスタリングは内部的にソートされたブロックを作成しますが、専用の空間インデックス(R‑Tree 等)は構築されません。そのため、
ST_DWithinで検索範囲を絞ることがパフォーマンス向上の必須ステップです。
実務シナリオ別クエリ例
1. 最近距離(最寄り店)—最適化版
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
WITH params AS ( SELECT ST_GeogFromText('POINT(-122.4194 37.7749)') AS cust_pt ) SELECT s.store_id, ST_Distance(p.cust_pt, s.geom) AS dist_m FROM params p JOIN `myproj.dataset.stores` s ON TRUE WHERE ST_DWithin(p.cust_pt, s.geom, 25000) -- 25km 内に絞り込み ORDER BY dist_m LIMIT 1; |
2. サービス圏域(円)生成とテーブル保存
|
1 2 3 4 5 6 |
CREATE OR REPLACE TABLE `myproj.dataset.store_service_area` AS SELECT store_id, ST_Buffer(geom, 5000) AS service_area -- 半径5km のサービスエリア FROM `myproj.dataset.stores`; |
3. ジオフェンス判定(顧客が特定エリア内か)
|
1 2 3 4 5 6 |
SELECT c.cust_id, CASE WHEN ST_Contains(f.geom, c.location) THEN 'IN' ELSE 'OUT' END AS status FROM `myproj.dataset.customers` c CROSS JOIN `myproj.dataset.geofence` f; |
これらのクエリはすべて パーティション+クラスタリング が適用されたテーブル上で実行すると、スキャンバイトが数十%削減されます。
可視化・機械学習連携とコスト管理
ジオスペーシャル分析結果をレポートや機械学習モデルに活用するための手順と、予算内で運用するためのベストプラクティスをまとめます。
Looker Studio で GIS データをマップ表示
- データソース接続
- Looker Studio → 「データの追加」→「BigQuery」を選択し、
store_service_areaテーブルを指定。 - ジオメトリ列設定
- フィールド一覧で
service_area(GEOGRAPHY)をクリックし、タイプを「ジオメトリ」に変更。 - マップチャート作成
- 「レポートに追加」→「マップ」→「領域マップ」または「ポイントマップ」を選択。
service_areaを「領域」、store_idを「ラベル」に割り当てると、店舗ごとのサービス円が可視化されます。
詳細手順は公式ガイド(Looker Studio と BigQuery GIS の統合)をご参照ください。
BigQuery ML で空間クラスタリング
ST_ClusterKMeans は GEOGRAPHY から座標情報を抽出し、K‑means によるクラスタリングを実行します。以下は顧客位置データを 5 クラスタに分割する例です。
|
1 2 3 4 5 6 7 8 9 10 11 |
CREATE OR REPLACE MODEL `myproj.dataset.customer_clusters` OPTIONS ( model_type = 'kmeans', num_clusters = 5, input_label_cols = ['geom'] ) AS SELECT ST_X(geom) AS lon, ST_Y(geom) AS lat FROM `myproj.dataset.customers`; |
クラスタ結果を取得し、Looker Studio にインポートすれば地域別の顧客分布が一目で把握できます。
|
1 2 3 4 5 6 7 |
SELECT cust_id, cluster_id, ST_AsText(geom) AS location FROM ML.PREDICT(MODEL `myproj.dataset.customer_clusters`, SELECT cust_id, ST_X(geom) AS lon, ST_Y(geom) AS lat FROM `myproj.dataset.customers`); |
コスト削減ベストプラクティス
| 項目 | 推奨アクション |
|---|---|
| クエリスキャン量 | 必要な列だけを選択し、SELECT * を避ける。距離条件は必ず ST_DWithin で事前絞り。 |
| 無料枠活用 | GCP 無料トライアル($300)と BigQuery の月間 10 GB スキャン無料枠を開発フェーズで積極利用。サンプルデータは bigquery-public-data.geo_* 系列が便利。 |
| パーティション | 時系列テーブルは日付や月単位でパーティション化し、古い期間のクエリ走査を排除。 |
| クラスタリング | GEOGRAPHY 列に対してクラスタリングキーを設定すると、同一エリアのレコードが連続保存されスキャン量が約 30 % 削減(空間インデックスは生成されません)。 |
| ジョブキャッシュ | 同一クエリは自動的にキャッシュが有効になるので、再実行時は USE_CACHED_RESULTS を明示的にオンにしてコストゼロで結果取得。 |
これらの対策を組み合わせることで、テラバイト規模のジオスペーシャルデータでも予算内で安定した分析基盤を構築できます。
まとめ
- GIS 機能はデフォルトで有効。追加設定は不要です。
- データロード時は
CREATE EXTERNAL TABLEやLOAD DATA INTOを使い、ST_GeogFromText / ST_GeogFromGeoJsonでGEOGRAPHYに変換します。 - 70 種類以上 の空間関数が提供されており、代表的な 30 関数を活用すれば多様なジオ分析が実現できます。
- パーティションとクラスタリングはスキャン量削減の鍵ですが、自動空間インデックスは生成されません。
ST_DWithin等で検索範囲を絞ることが重要です。 - 可視化は Looker Studio、機械学習は BigQuery ML の
ST_ClusterKMeansなどで実装し、コスト削減は「列指向」「パーティション」「キャッシュ」中心に最適化してください。
これらのポイントを押さえておけば、BigQuery 上でスケーラブルかつ低コストなジオスペーシャル解析環境を迅速に構築できるでしょう。