Eksportowanie do BigQuery

Omówienie

Architektura obliczeniowa Earth Engine została zoptymalizowana pod kątem szybkiego i skalowanego przetwarzania obrazów (na podstawie pikseli). BigQuery jest podobnie zoptymalizowany pod kątem skalowanego przetwarzania danych tabelarycznych (wektorów) i zawiera wiele funkcji, które sprawiają, że jest on przydatnym uzupełnieniem Earth Engine.

Przykładowe przepływy pracy:

  • Wykonywanie dużych złączeń BigQuery na danych wygenerowanych w Earth Engine
  • Dodawanie adnotacji do danych wektorowych za pomocą statystyk pochodzących z obrazów na potrzeby dalszego przetwarzania w BigQuery
  • okresowy eksport danych z Earth Engine do tabeli BigQuery, do której można dołączać dane;

Jeśli znasz inne świetne przypadki użycia, daj nam znać.

Podstawy BigQuery

Earth Engine zapisuje dane w tabelach BigQuery, a wszystkie tabele znajdują się w zbiorach danych. Zadania eksportu kończą się niepowodzeniem, jeśli określony zbiór danych nie jest obecny w BigQuery. Więcej informacji znajdziesz w wprowadzeniu do zbiorów danych BigQuery.

Tworzenie zbioru danych

Zbiory danych mają wiele opcji dotyczących czasu utworzenia, w tym nazwę, region przechowywania i zachowanie po wygaśnięciu (oraz kilka innych, bardziej zaawansowanych opcji).

Istnieją różne mechanizmy tworzenia zbiorów danych, ale najprostszym sposobem na rozpoczęcie jest konsola Cloud:

  1. Otwórz stronę BigQuery w konsoli Cloud.
  2. Jeśli pojawi się taka prośba, kliknij „Włącz”, aby włączyć interfejs API.
  3. Na karcie „Obszar roboczy SQL” kliknij menu z 3 kropkami () obok projektu.
  4. Wybierz opcję „Utwórz zbiór danych”.
  5. Postępuj zgodnie z instrukcjami w przewodniku po konfiguracji.

Wszystkie opcje tworzenia i konfigurowania zbioru danych znajdziesz w dokumentacji BigQuery.

Uprawnienia

Oprócz standardowych ról i uprawnień wymaganych do korzystania z Earth Engine, wywołujący muszą też mieć odpowiednie uprawnienia BigQuery w projekcie lub zbiorze danych Cloud.

  • bigquery.tables.get
  • bigquery.tables.create
  • bigquery.tables.updateData
  • bigquery.tables.delete
  • bigquery.jobs.create

Każda z tych kombinacji wstępnie zdefiniowanych ról zarządzania tożsamościami i dostępem obejmuje niezbędne uprawnienia:

  • bigquery.dataEditor plus bigquery.jobUser
  • bigquery.dataOwner plus bigquery.jobUser
  • bigquery.user
  • bigquery.admin

Ceny

BigQuery to płatna usługa Google Cloud, więc za jej korzystanie (w tym za przechowywanie i analizę danych Earth Engine wyeksportowanych do BigQuery) będą naliczane opłaty.

Szczegółowe informacje o cenach funkcji eksportu do BigQuery w Earth Engine znajdziesz w sekcji dotyczącej cen poniżej.

Eksportuj konfigurację

Składnia

Edytor kodu (JavaScript)

Export.table.toBigQuery({
  collection: features,
  table: 'myproject.mydataset.mytable',
  description: 'put_my_data_in_bigquery',
  append: true,
  overwrite: false
});

Konfiguracja Pythona

Informacje o interfejsie Python API i o używaniu pakietu geemap do programowania interaktywnego znajdziesz na stronie Python Environment.

import ee
import geemap.core as geemap

Colab (Python)

task = ee.batch.Export.table.toBigQuery(
    collection=features,
    table='myproject.mydataset.mytable',
    description='put_my_data_in_bigquery',
    append=True,
    overwrite=False,
)
task.start()

Specyfikacja schematu automatycznego lub ręcznego

Jeśli w BigQuery nie ma tabeli, Earth Engine próbuje określić schemat, korzystając z właściwości pierwszego ee.Feature w zbiorze. Jest to najlepsze przypuszczenie, ponieważ można stworzyć kolekcję, w której schemat pierwszej funkcji różni się od schematu innych funkcji.

Jeśli potrzebujesz określonego schematu w tabeli BigQuery, skonfiguruj go, tworząc pustą tabelę z docelowym schematem.

Nazwy właściwości

Właściwości funkcji Earth Engine odpowiadają kolumnom w BigQuery. Earth Engine używa nazwy „geo” do zapisywania geometrii ee.Feature (selektora „.geo”) w BigQuery.

Aby uniknąć zmiany nazwy, sprawdź, czy obiekty ee.Feature mają właściwości, które są prawidłowymi nazwami kolumn, i czy żadna z nich nie ma nazwy „geo” (ta nazwa jest używana do geometrii obiektu, która nie ma nazwy w Earth Engine).

Nieprawidłowe znaki w nazwach usług powodują niepowodzenie eksportu z powodu ograniczeń dotyczących nazw kolumn BigQuery.

Konwertowanie typów

Dane Earth Engine (wartości właściwości ee.Feature) są w miarę możliwości konwertowane na odpowiednie typy BigQuery. Pamiętaj, że możliwość występowania wartości null jest kontrolowana przez schemat tabeli, a nie przez typ.

Typ Earth Engine Typ w BigQuery Uwagi
ee.String STRING
ee.Number FLOAT lub INTEGER
ee.Geometry GEOGRAPHY
ee.Date TIMESTAMP
ee.ByteString BYTES
ee.Array STRUCT<ARRAY<INT64>, ARRAY<INT64|FLOAT64>> Zobacz sekcję dotyczącą tablic.
Inne typy ee.* not supported Przeczytaj sekcję Wartości JSON.

Tablice

Earth Engine eksportuje dowolne wielowymiarowe dane ee.Array do formatu STRUCT<ARRAY<INT64> dimensions, ARRAY<INT64|FLOAT64> values>, który jest podobny do formatu używanego przez funkcję ML.DECODE_IMAGE w BigQuery.

Pierwsza tablica w strukturze, dimensions, zawiera wymiary tablicy Earth Engine, $d_1$ do $d_n$.

Drugi tablica w strukturze, values, zawiera wszystkie wartości z tablicy wielowymiarowej spłaszczone w jedną tablicę BigQuery. Łączna liczba wartości w spłaszczonej tablicy to $\sum_{i=1}^n d_i$, a wartość w indeksie $(i_i, \ldots, i_n)$ w pierwotnej tablicy Earth Engine odpowiada wartości w tym indeksie w spłaszczonej tablicy:

\[ \sum_{j=1}^n \left( i_j \cdot \prod_{k=j+1}^n d_k \right) \]

W typowych przypadkach wyrażenie indeksowania tablicy values ma postać:

Rozmiar tablicy Wymiary Indeksowanie wyrażenia
jednowymiarowy, d1 [i1]
2-wymiarowy d1, d2 [(i1 * d2) + i2]
trójwymienny d1, d2, d3 [(i1 * d2 * d3) + (i2 * d3) + i3]

Weźmy na przykład tablicę 2x3x4 w Earth Engine:

    ee.Array([
      [
        [1, 2, 3, 4],
        [5, 6, 7, 8],
        [9, 10, 11, 12]
      ],
      [
        [13, 14, 15, 16],
        [17, 18, 19, 20],
        [21, 22, 23, 24]
      ]
    ]);

Ta tablica jest tłumaczona na typ STRUCT w BigQuery, którego element dimensions jest tablicą [2, 3, 4], a element values jest spłaszczoną tablicą [1, 2, 3, 4, 5, 6, 7, 8, ..., 21, 22, 23, 24]. Indeksy w sprasowanej tablicy można obliczyć jako [(i1 * 12) + (i2 * 4) + i3].

wartości JSON,

Aby obsługiwać w komórce bardziej złożone dane, możesz kodować wartości Earth Engine jako obiekty JSON. BigQuery obsługuje operacje SQL na danych zakodowanych w formacie JSON, co umożliwia tworzenie zapytań, które „zaglądają do środka” zakodowanych wartości JSON utworzonych w Earth Engine.

Edytor kodu (JavaScript)

var states = ee.FeatureCollection('TIGER/2018/States');
var mod11a1 = ee.ImageCollection('MODIS/061/MOD11A1');

// Find the max day and night temperatures per pixel for a given time.
var maxTemp = mod11a1
    .select(['LST_Day_1km', 'LST_Night_1km'])
    .filterDate('2023-05-15', '2023-05-25')
    .max();

// Annotate each state with its max day/night temperatures.
var annotatedStates = states.map(function (e) {
  var dict = maxTemp.reduceRegion({
    reducer: ee.Reducer.max(),
    geometry: e.geometry(),
    scale: 10 * 1000,  // 10 km
  });
  // Convert the dictionary to JSON and add it as a property.
  return e.set('maxTemp', ee.String.encodeJSON(dict));
});

Export.table.toBigQuery(annotatedStates);

Konfiguracja Pythona

Informacje o interfejsie Python API i o używaniu pakietu geemap do programowania interaktywnego znajdziesz na stronie Python Environment.

import ee
import geemap.core as geemap

Colab (Python)

states = ee.FeatureCollection('TIGER/2018/States')
mod11a1 = ee.ImageCollection('MODIS/061/MOD11A1')

# Find the max day and night temperatures per pixel for a given time.
max_temp = (
    mod11a1.select(['LST_Day_1km', 'LST_Night_1km'])
    .filterDate('2023-05-15', '2023-05-25')
    .max()
)


def get_max_temp_for_state(e):
  max_temp_dict = max_temp.reduceRegion(
      reducer=ee.Reducer.max(),
      geometry=e.geometry(),
      scale=10 * 1000,  # 10 km
  )
  # Convert the dictionary to JSON and add it as a property.
  return e.set('maxTemp', ee.String.encodeJSON(max_temp_dict))


# Annotate each state with its max day/night temperatures.
annotated_states = states.map(get_max_temp_for_state)

task = ee.batch.Export.table.toBigQuery(
    collection=annotated_states, table='myproject.mydataset.mytable'
)
task.start()

Konwersja geometryczna

BigQuery ma ograniczone wsparcie dla różnych projekcji, więc wszystkie geometrie Earth Engine są przekształcane na geodezję EPSG:4326 z marginesem błędu wynoszącym 1 metr.

Aby mieć większą kontrolę nad tym procesem transformacji, możesz ręcznie mapować funkcje i przekształcać ich geometrię, np.:

Edytor kodu (JavaScript)

var transformedCollection = originalCollection.map(function transformGeo(e) {
  var myErrorMargin = 10 * 1000;  // meters
  return e.setGeometry(e.geometry(myErrorMargin, 'EPSG:4326', true));
});

Konfiguracja Pythona

Informacje o interfejsie Python API i o używaniu pakietu geemap do programowania interaktywnego znajdziesz na stronie Python Environment.

import ee
import geemap.core as geemap

Colab (Python)

def transform_geo(e):
  my_error_margin = 10 * 1000  # meters
  return e.setGeometry(e.geometry(my_error_margin, 'EPSG:4326', True))


transformed_collection = original_collection.map(transform_geo)

Wyniki

Wydajność Earth Engine

Obliczenia w Earth Engine często stanowią wąskie gardło w przypadku operacji Export. W tym celu ważne jest, aby przetwarzanie było zorganizowane w sposób zapewniający maksymalny stopień równoległości. Każde obliczenie, które powoduje przetwarzanie szeregowe (np. ee.FeatureCollection.iterate()), może spowodować, że eksport będzie przebiegać wolno lub nie powiedzie się.

Wydajność w BigQuery

Prawidłowe ustrukturyzowanie danych i ich grupowanie to najlepszy sposób na zapewnienie wydajności zapytań w BigQuery. Jeśli w BigQuery nie ma jeszcze tabeli, tabele wyeksportowane z Earth Engine są grupowane według geometrii elementów (jeśli taka istnieje). Utworzenie klastrów według pola geograficznego jest bardzo powszechne w przypadku danych geoprzestrzennych. Zwiększa wydajność i obniża koszty zapytań, które korzystają z filtrów przestrzennych, najczęściej w przypadku operacji BigQuery takich jak:

WHERE ST_DWithin(<table_column>, <constant_geography>, <distance>)
WHERE ST_Intersects(<table_column>, <constant_geography>)

Dodanie grupowania do tabeli bez grupowania nie powoduje żadnych problemów, ale może nieznacznie wydłużyć czas wczytywania danych do tabeli. Więcej informacji o optymalizacji zapytań znajdziesz w dokumentacji BigQuery.

Pamiętaj, że ustawienia grupowania mają wpływ tylko na nowe dane zapisywane w tabeli.

Demo: korzystanie z reduceRegions

W niektórych przypadkach można użyć opcji reduceRegions, aby uzyskać jak największą równoległość przetwarzania w ramach infrastruktury przetwarzania Earth Engine. Ten przykład pokazuje, jak używać mniejszej liczby wywołań funkcji reduceRegions (kilkaset) zamiast dziesiątek tysięcy wywołań funkcji reduceRegion (typowe podejście do mapowania funkcji na kolekcji).

Edytor kodu (JavaScript)

var lucas = ee.FeatureCollection('JRC/LUCAS_HARMO/COPERNICUS_POLYGONS/V1/2018');
var s2 = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED');

// Fetch the unique date values from the dataset.
var dates = lucas.aggregate_array('survey_date')
    .distinct()
    .map(function (date) {
      return ee.Date.parse('dd/MM/yy', date);
    });

// For each date, annotate the LUCAS samples with the Sentinel-2 band values for
// a two-week window.
function getLucasSamplesForDate(date) {
  date = ee.Date(date);
  var imageForDate = s2
    .filterDate(
      date.advance(-1, 'week'),
      date.advance(1, 'week'))
    .select('B.*');
  var median = imageForDate.median();
  var lucasForDate = lucas.filter(
    ee.Filter.equals('survey_date', date.format('dd/MM/yy')));
  var sample = median.reduceRegions({
    collection: lucasForDate,
    reducer: ee.Reducer.mean(),
    scale: 10,
    tileScale: 8,
  });
  return sample;
}

// Flatten the collection.
var withSamples =
    ee.FeatureCollection(dates.map(getLucasSamplesForDate))
      .flatten();

Export.table.toBigQuery({
  collection: withSamples,
  description: 'lucas_s2_annotated'
});

Konfiguracja Pythona

Informacje o interfejsie Python API i o używaniu pakietu geemap do programowania interaktywnego znajdziesz na stronie Python Environment.

import ee
import geemap.core as geemap

Colab (Python)

lucas = ee.FeatureCollection('JRC/LUCAS_HARMO/COPERNICUS_POLYGONS/V1/2018')
s2 = ee.ImageCollection('COPERNICUS/S2_SR_HARMONIZED')

# Fetch the unique date values from the dataset.
dates = (
    lucas.aggregate_array('survey_date')
    .distinct()
    .map(lambda date: ee.Date.parse('dd/MM/yy', date))
)


# For each date, annotate the LUCAS samples with the Sentinel-2 band values for
# a two-week window.
def get_lucas_samples_for_date(date):
  date = ee.Date(date)
  image_for_date = s2.filterDate(
      date.advance(-1, 'week'), date.advance(1, 'week')
  ).select('B.*')
  median = image_for_date.median()
  lucas_for_date = lucas.filter(
      ee.Filter.equals('survey_date', date.format('dd/MM/yy'))
  )
  sample = median.reduceRegions(
      collection=lucas_for_date,
      reducer=ee.Reducer.mean(),
      scale=10,
      tileScale=8,
  )
  return sample


# Flatten the collection.
with_samples = ee.FeatureCollection(
    dates.map(get_lucas_samples_for_date)
).flatten()

task = ee.batch.Export.table.toBigQuery(
    collection=with_samples,
    table='myproject.mydataset.mytable',
    description='lucas_s2_annotated',
)
task.start()

równoległe wykonywanie zadań;

Opcja {append: true} umożliwia jednoczesne zapisywanie danych w tabeli BigQuery przez wiele zadań. Jest to mechanizm zapisywania danych z większą przepustowością, ale wiąże się z większym stopniem złożoności (zarządzanie kolejką zadań, ponowne próby itp.).

Różnice w skuteczności między parametrami append i overwrite

Pamiętaj, że zastępowanie jest wolniejsze niż dołączanie, ponieważ BigQuery musi przetworzyć nowe dane przed zastąpieniem starych. Ustawienie parametru {overwrite: true} podczas eksportowania do istniejącej tabeli BigQuery powoduje bezpieczne zastąpienie:

  1. Tabela tymczasowa: dane są eksportowane do nowej, tymczasowej tabeli w zbiorze danych docelowym.
  2. Zastępowanie w sposób atomowy: zawartość tabeli tymczasowej jest kopiowana do końcowej tabeli docelowej, zastępując istniejące dane w ramach pojedynczej transakcji atomowej.
  3. Czyszczenie: tabela tymczasowa zostaje usunięta.

Dzięki temu błędy podczas eksportu nie spowodują uszkodzenia dotychczasowych danych. W przypadku małych tabel opóźnienie wynosi zwykle kilka minut.

Alternatywy o wysokiej wydajności

W przypadku procesów wymagających bardzo wysokiej przepustowości rozważ użycie GeoBeam do przenoszenia danych z Earth Engine do BigQuery. Wymaga to większej konfiguracji i infrastruktury, dlatego zalecamy rozpoczęcie od wbudowanej funkcji Earth Engine.

Ceny

Eksportowanie do BigQuery to proces zbiorczy, który zużywa czas EECU zbiorczego. Jeśli używasz Earth Engine do celów komercyjnych lub operacyjnych, eksportowanie danych do BigQuery powoduje obciążenie za czas EECU wykorzystany przez zadania. Cały czas korzystania można monitorować za pomocą tych samych narzędzi monitorowania, które działają w pozostałych częściach Earth Engine.

Konta rozliczeniowe Cloud

Aby zapisywać dane w BigQuery, musisz włączyć konto rozliczeniowe powiązanego projektu Cloud. Więcej informacji o konfiguracji konta rozliczeniowego znajdziesz w dokumentacji dotyczącej kont rozliczeniowych Cloud.

Ruch wychodzący

Wszystkie koszty związane z ruchem przychodzącym i wychodzącym są naliczane jako standardowy ruch sieciowy.

Earth Engine jest hostowany tylko w Stanach Zjednoczonych, ale zbiory danych BigQuery mogą być hostowane w wielu innych regionach. W zależności od regionów i objętości danych zapisywanie danych z Earth Engine w BigQuery może generować znaczny ruch w sieci.

Znane problemy

Orientacja dużych wielokątów

Funkcja eksportu BigQuery odwraca orientację wielokątów większych niż półkula, przez co odwraca ich orientację (przekształca wielokąt w jego geometriczną komplementarną). W rzadkich przypadkach wczytywanie wielokątów większych niż półkula może się nie udać.

W razie potrzeby odwrócone wielokąty można skorygować w BigQuery, odwracając je ponownie za pomocą wyrażenia BigQueryST_Difference(ST_GeogFromText('fullglobe'), geo).

Więcej informacji znajdziesz tutaj.