Exporter vers BigQuery

Présentation

L'architecture de calcul d'Earth Engine est optimisée pour accélérer et faire évoluer les calculs d'images (basés sur les pixels). BigQuery est également optimisé pour le traitement évolutif des données tabulaires (vecteurs). Il dispose de nombreuses fonctionnalités qui en font un complément intéressant d'Earth Engine.

Voici quelques exemples de workflows:

  • Effectuer de grandes jointures BigQuery sur des données générées dans Earth Engine
  • Annoter des données vectorielles avec des statistiques issues d'images pour un traitement ultérieur dans BigQuery
  • Exporter régulièrement des données depuis Earth Engine vers une table BigQuery pouvant être ajoutée

Si vous avez d'autres cas d'utilisation intéressants, n'hésitez pas à nous en parler.

Principes de base de BigQuery

Earth Engine écrit dans des tables BigQuery, et toutes les tables sont contenues dans des ensembles de données. Les tâches d'exportation échouent si l'ensemble de données spécifié n'est pas présent dans BigQuery. Pour en savoir plus, consultez la présentation des ensembles de données BigQuery.

Création d'ensemble de données

Les ensembles de données disposent d'un certain nombre d'options au moment de leur création, y compris le nom, la région de stockage et le comportement d'expiration (ainsi que plusieurs autres options plus avancées).

Il existe différents mécanismes pour créer des ensembles de données, mais un moyen simple de commencer est de passer par la console Cloud:

  1. Accédez à la page BigQuery de Cloud Console.
  2. Si vous y êtes invité, cliquez sur "Activer" pour activer l'API.
  3. Dans l'onglet "Espace de travail SQL", cliquez sur le menu à trois points () à côté du projet.
  4. Sélectionnez l'option "Créer un ensemble de données".
  5. Suivez le guide de configuration.

Pour connaître toutes les options de création et de configuration d'un ensemble de données, consultez la documentation BigQuery.

Autorisations

En plus des rôles et autorisations standards requis pour utiliser Earth Engine, les appelants ont également besoin des autorisations BigQuery appropriées sur le projet ou l'ensemble de données Cloud.

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

Les combinaisons suivantes de rôles IAM (Identity and Access Management) prédéfinis incluent les autorisations nécessaires:

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

Tarifs

BigQuery est un service Google Cloud payant. Des frais vous seront donc facturés pour votre utilisation de BigQuery, y compris pour le stockage et l'analyse de toutes les données Earth Engine que vous exportez vers BigQuery.

Pour en savoir plus sur la tarification de la fonctionnalité d'exportation BigQuery d'Earth Engine, consultez la section sur les tarifs ci-dessous.

Exporter la configuration

Syntaxe

Éditeur de code (JavaScript)

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

Configuration de Python

Consultez la page Environnement Python pour en savoir plus sur l'API Python et l'utilisation de geemap pour le développement interactif.

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()

Spécification automatique ou manuelle du schéma

Si aucune table n'est présente dans BigQuery, Earth Engine tente de déterminer un schéma à l'aide des propriétés du premier ee.Feature de la collection. Il s'agit d'une estimation, et il est possible de créer une collection dont le schéma de la première fonctionnalité est différent de celui des autres fonctionnalités.

Si vous avez besoin d'un schéma spécifique pour votre table BigQuery, configurez-le en créant une table vide avec le schéma cible.

Noms de propriétés

Les propriétés des éléments géographiques Earth Engine correspondent aux colonnes de BigQuery. Earth Engine utilise le nom "geo" pour écrire la géométrie ee.Feature (le sélecteur ".geo") dans BigQuery.

Pour éviter tout renommage, assurez-vous que les propriétés de vos objets ee.Feature sont des noms de colonnes valides et qu'aucun d'entre eux ne porte le nom "geo" (puisque ce nom est utilisé pour la géométrie de l'élément géographique, qui n'a pas de nom dans Earth Engine).

La présence de caractères non valides dans les noms de propriétés entraîne l'échec de l'exportation en raison des restrictions sur les noms de colonnes BigQuery.

Conversion des types de données

Les données Earth Engine (les valeurs des propriétés ee.Feature) sont converties en type BigQuery équivalent lorsque cela est possible. Notez que la possibilité d'être nulle est contrôlée par le schéma de la table, et non par le type.

Type Earth Engine Type BigQuery Remarques
ee.String STRING
ee.Number FLOAT ou INTEGER
ee.Geometry GEOGRAPHY
ee.Date TIMESTAMP
ee.ByteString BYTES
ee.Array STRUCT<ARRAY<INT64>, ARRAY<INT64|FLOAT64>> Consultez la section sur les tableaux.
Autres types ee.* non pris en charge Consultez la section sur les valeurs JSON.

Tableaux

Earth Engine exporte tous les ee.Array multidimensionnels vers STRUCT<ARRAY<INT64> dimensions, ARRAY<INT64|FLOAT64> values>, comme le format utilisé par la fonction ML.DECODE_IMAGE de BigQuery.

Le premier tableau de la structure, dimensions, contient les dimensions du tableau Earth Engine, de $d_1$ à $d_n$.

Le deuxième tableau de la structure, values, contient toutes les valeurs du tableau multidimensionnel, aplaties dans un seul tableau BigQuery. Le nombre total de valeurs dans le tableau aplati est $\sum_{i=1}^n d_i$, et la valeur à l'indice $(i_i, \ldots, i_n)$ dans le tableau Earth Engine d'origine correspond à la valeur à l'indice suivant dans le tableau aplati:

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

Dans les cas courants, l'expression d'indexation du tableau values est la suivante:

Taille du tableau Dimensions Expression d'indexation
1 dimension d1 [i1]
En deux dimensions d1, d2 [(i1 * d2) + i2]
En trois dimensions d1, d2, d3 [(i1 * d2 * d3) + (i2 * d3) + i3]

Prenons l'exemple d'un tableau 2x3x4 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]
      ]
    ]);

Ce tableau se traduit par un STRUCT BigQuery dont l'élément dimensions est le tableau [2, 3, 4] et dont l'élément values est le tableau [1, 2, 3, 4, 5, 6, 7, 8, ..., 21, 22, 23, 24] aplati. Les index du tableau aplati peuvent être calculés comme [(i1 * 12) + (i2 * 4) + i3].

Valeurs JSON

Pour prendre en charge des données plus structurées dans une cellule, vous pouvez encoder les valeurs Earth Engine en tant qu'objets JSON. BigQuery accepte les opérations SQL sur les données encodées en JSON, ce qui permet d'effectuer des requêtes qui "regardent à l'intérieur" des valeurs JSON encodées que vous produisez dans Earth Engine.

Éditeur de code (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);

Configuration de Python

Consultez la page Environnement Python pour en savoir plus sur l'API Python et l'utilisation de geemap pour le développement interactif.

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()

Conversion de géométrie

BigQuery est peu compatible avec les différentes projections. Par conséquent, toutes les géométries Earth Engine sont transformées en EPSG:4326 géodésique à l'aide d'une marge d'erreur de 1 mètre.

Pour mieux contrôler ce processus de transformation, vous pouvez mapper manuellement les éléments géographiques et transformer leurs géométries, par exemple :

Éditeur de code (JavaScript)

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

Configuration de Python

Consultez la page Environnement Python pour en savoir plus sur l'API Python et l'utilisation de geemap pour le développement interactif.

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)

Performances

Performances d'Earth Engine

Le calcul Earth Engine est souvent le goulot d'étranglement des opérations Export. Pour ce faire, il est important d'organiser votre traitement pour un parallélisme maximal. Tout calcul qui est intégré au traitement en série (par exemple, ee.FeatureCollection.iterate()) peut ralentir ou échouer votre exportation.

Performances dans BigQuery

La structuration et le clustering corrects des données sont le meilleur moyen de s'assurer que les requêtes peuvent être rendues efficaces dans BigQuery. Si aucune table n'est déjà présente dans BigQuery, les tables exportées depuis Earth Engine sont regroupées en fonction de la géométrie des éléments géographiques (si elle est présente). Le regroupement par champ géographique est très courant pour les données géospatiales. Il améliore les performances et réduit les coûts pour les requêtes qui utilisent des filtres spatiaux, le plus souvent pour les opérations BigQuery telles que:

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

Ajouter un clustering à une table non clustée n'est généralement pas nuisible, mais cela peut légèrement augmenter le temps de chargement des données dans la table. Pour en savoir plus sur l'optimisation des requêtes, consultez la documentation BigQuery.

Notez que les paramètres de clustering n'affectent que les nouvelles données écrites dans la table.

Démonstration: à l'aide de reduceRegions

Dans certains cas, vous pouvez utiliser reduceRegions pour obtenir autant de parallélisme que possible de l'infrastructure de traitement Earth Engine. Cet exemple montre comment utiliser un plus petit nombre d'appels reduceRegions (quelques centaines) plutôt que des dizaines de milliers d'appels reduceRegion (approche typique pour mapper une fonction sur une collection).

Éditeur de code (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'
});

Configuration de Python

Consultez la page Environnement Python pour en savoir plus sur l'API Python et l'utilisation de geemap pour le développement interactif.

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()

Parallélisation des tâches

Avec l'option {append: true}, plusieurs tâches peuvent écrire des données dans une table BigQuery simultanément. Il s'agit d'un mécanisme permettant d'écrire des données avec un débit plus élevé, mais cela se traduit par une complexité accrue (gestion de la file d'attente de tâches, nouvelle tentative, etc.).

Différences de performances entre les paramètres append et overwrite

Notez que l'écrasement est plus lent que l'ajout, car BigQuery doit traiter les nouvelles données avant de les écraser. Définir le paramètre {overwrite: true} lors de l'exportation vers une table BigQuery existante déclenche un processus d'écrasement sécurisé:

  1. Table temporaire: les données sont exportées vers une nouvelle table temporaire dans l'ensemble de données de destination.
  2. Écrasement atomique: le contenu de la table temporaire est copié dans la table de destination finale, remplaçant les données existantes dans une seule transaction atomique.
  3. Nettoyage: la table temporaire est supprimée.

Cela garantit que les erreurs lors de l'exportation ne corrompront pas vos données existantes. Pour les petites tables, le délai est généralement de quelques minutes.

Alternatives hautes performances

Pour les workflows qui nécessitent un débit très élevé, envisagez d'utiliser GeoBeam pour transférer des données d'Earth Engine vers BigQuery. Cela nécessite plus de configuration et d'infrastructure. Nous vous recommandons donc de commencer par la fonctionnalité Earth Engine intégrée.

Tarifs

L'exportation vers BigQuery est un processus par lot qui consomme du temps EECU par lot. Si vous utilisez Earth Engine à des fins commerciales ou opérationnelles, l'exportation de données vers BigQuery vous sera facturée en fonction du temps EECU utilisé par les tâches. Toutes les utilisations peuvent être surveillées avec exactement les mêmes outils de surveillance que ceux utilisés pour le reste d'Earth Engine.

Comptes de facturation Cloud

Pour écrire des données dans BigQuery, un compte de facturation doit être activé pour le projet Cloud associé. Pour en savoir plus sur la configuration d'un compte de facturation, consultez la documentation sur les comptes de facturation Cloud.

Sortie

Tous les coûts d'entrée et de sortie sont facturés comme du trafic réseau standard.

Earth Engine n'est hébergé qu'aux États-Unis, mais les ensembles de données BigQuery peuvent être hébergés dans un certain nombre d'autres régions. En fonction des régions et des volumes de données concernés, l'écriture de données depuis Earth Engine vers BigQuery peut générer un trafic réseau important.

Problèmes connus

Orientation des grands polygones

La fonction d'exportation BigQuery inverse les polygones plus grands qu'un hémisphère en inversant leur orientation (en remplaçant le polygone par son complément géométrique). Dans de rares cas, il est possible que les polygones plus grands qu'un hémisphère ne se chargent pas.

Si nécessaire, les polygones inversés peuvent être corrigés dans BigQuery en les inversant à nouveau à l'aide de l'expression BigQuery ST_Difference(ST_GeogFromText('fullglobe'), geo).

Pour en savoir plus, cliquez ici.