Como exportar para o BigQuery

Visão geral

A arquitetura computacional do Earth Engine é otimizada para tornar a computação de imagens (baseada em pixels) rápida e escalonável. O BigQuery também é otimizado para processamento escalonável de dados tabulares (vetores) e tem muitos recursos que o tornam um bom complemento para o Earth Engine.

Confira alguns exemplos de fluxos de trabalho:

  • Como realizar mesclagens grandes do BigQuery em dados gerados no Earth Engine
  • Como anotar dados vetoriais com estatísticas derivadas de imagens para processamento no BigQuery
  • Exportar dados periodicamente do Earth Engine para uma tabela do BigQuery que pode ser anexada

Se você tiver outros casos de uso incríveis, conte para a gente.

Noções básicas do BigQuery

O Earth Engine grava em tabelas do BigQuery, e todas as tabelas estão contidas em conjuntos de dados. As tarefas de exportação falham se o conjunto de dados especificado não estiver presente no BigQuery. Saiba mais na introdução ao conjunto de dados do BigQuery.

Criação do conjunto de dados

Os conjuntos de dados têm várias opções de criação, incluindo o nome, a região de armazenamento e o comportamento de expiração, além de várias outras opções mais avançadas.

Há vários mecanismos para criar conjuntos de dados, mas uma maneira simples de começar é pelo Console do Cloud:

  1. Acesse a página do BigQuery no console do Cloud.
  2. Clique em "Ativar" para ativar a API, se necessário.
  3. Na guia "SQL Workspace", clique no menu de três pontos () ao lado do projeto.
  4. Escolha a opção "Criar conjunto de dados".
  5. Siga o guia de configuração.

Para conferir todas as opções de criação e configuração de um conjunto de dados, consulte a documentação do BigQuery.

Permissões

Além das funções e permissões padrão necessárias para usar o Earth Engine, os autores da chamada também precisam das permissões do BigQuery corretas no projeto ou conjunto de dados do Cloud.

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

Qualquer uma das seguintes combinações de papéis predefinidos do Identity and Access Management (IAM) inclui as permissões necessárias:

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

Preços

O BigQuery é um serviço pago do Google Cloud. Por isso, você vai receber taxas pelo uso do BigQuery, incluindo armazenamento e análise de todos os dados do Earth Engine exportados para o BigQuery.

Para saber mais sobre os preços do recurso de exportação do BigQuery do Earth Engine, consulte a seção de preços abaixo.

Exportar configuração

Sintaxe

Editor de código (JavaScript)

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

Configuração do Python

Consulte a página Ambiente Python para informações sobre a API Python e o uso de geemap para desenvolvimento interativo.

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

Especificação de esquema automática ou manual

Se não houver nenhuma tabela no BigQuery, o Earth Engine tentará determinar um esquema usando as propriedades do primeiro ee.Feature na coleção. Essa é a melhor estimativa, e é possível criar uma coleção em que o esquema do primeiro recurso é diferente do esquema de outros recursos.

Se você precisar de um esquema específico na tabela do BigQuery, configure-o criando uma tabela vazia com o esquema de destino.

Nomes de propriedades

As propriedades nos elementos do Earth Engine correspondem a colunas no BigQuery. O Earth Engine usa o nome "geo" para gravar a geometria ee.Feature (o seletor ".geo") no BigQuery.

Para evitar renomeações, verifique se os objetos ee.Feature têm propriedades que são nomes de coluna válidos e se nenhum deles é chamado de "geo", já que esse nome é usado para a geometria do elemento, que não tem nome no Earth Engine.

Caracteres inválidos nos nomes de propriedade fazem com que a exportação falhe devido a restrições nos nomes de colunas do BigQuery.

Conversão de tipo

Os dados do Earth Engine (os valores das propriedades ee.Feature) são convertidos em um tipo equivalente do BigQuery sempre que possível. A nulidade é controlada pelo esquema da tabela, não pelo tipo.

Tipo do Earth Engine Tipo do BigQuery Observações
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>> Consulte a seção sobre matrizes.
Outros tipos de ee.* not supported Consulte a seção sobre valores JSON.

Matrizes

O Earth Engine exporta qualquer ee.Array multidimensional para STRUCT<ARRAY<INT64> dimensions, ARRAY<INT64|FLOAT64> values>, semelhante ao formato usado pela função ML.DECODE_IMAGE do BigQuery.

A primeira matriz na struct, dimensions, contém as dimensões da matriz do Earth Engine, de $d_1$ a $d_n$.

A segunda matriz no struct, values, contém todos os valores na matriz multidimensional, achatada em uma única matriz do BigQuery. O número total de valores na matriz achatada é $\sum_{i=1}^n d_i$, e o valor no índice $(i_i, \ldots, i_n)$ na matriz original do Earth Engine corresponde ao valor no índice a seguir na matriz achatada:

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

Para casos comuns, a expressão de indexação para a matriz values é a seguinte:

Tamanho da matriz Dimensões Expressão de indexação
Unidimensional d1 [i1]
Bidimensional d1, d2 [(i1 * d2) + i2]
Tridimensional d1, d2, d3 [(i1 * d2 * d3) + (i2 * d3) + i3]

Por exemplo, considere uma matriz 2x3x4 do 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]
      ]
    ]);

Essa matriz é convertida em um STRUCT do BigQuery em que o elemento dimensions é a matriz [2, 3, 4] e o elemento values é a matriz plana [1, 2, 3, 4, 5, 6, 7, 8, ..., 21, 22, 23, 24]. Os índices na matriz plana podem ser calculados como [(i1 * 12) + (i2 * 4) + i3].

Valores JSON

Para oferecer suporte a dados mais estruturados em uma célula, é possível codificar os valores do Earth Engine como objetos JSON. O BigQuery oferece suporte a operações SQL em dados codificados em JSON, permitindo consultas que "procuram dentro" dos valores JSON codificados que você produz no Earth Engine.

Editor de código (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);

Configuração do Python

Consulte a página Ambiente Python para informações sobre a API Python e o uso de geemap para desenvolvimento interativo.

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

Conversão de geometria

O BigQuery tem suporte limitado para diferentes projeções. Portanto, todas as geometrias do Motor do Google Earth são transformadas em EPSG:4326 geodésica usando uma margem de erro de 1 metro.

Para ter um controle mais preciso sobre esse processo de transformação, é possível mapear manualmente os elementos e transformar as geometrias deles, por exemplo:

Editor de código (JavaScript)

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

Configuração do Python

Consulte a página Ambiente Python para informações sobre a API Python e o uso de geemap para desenvolvimento interativo.

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)

Desempenho

Desempenho do Earth Engine

A computação do Earth Engine geralmente é o gargalo das operações Export. Para isso, é importante organizar o processamento para o máximo de paralelismo. Qualquer cálculo que seja incorporado ao processamento em série (por exemplo, ee.FeatureCollection.iterate()) pode fazer com que a exportação seja executada lentamente ou falhe.

Desempenho no BigQuery

Estruturar e agrupar dados corretamente é a melhor maneira de garantir que as consultas sejam eficientes no BigQuery. Se não houver uma tabela já presente no BigQuery, as tabelas exportadas do Earth Engine serão agrupadas na geometria dos elementos (se houver). Agrupar por campo de geografia é muito comum para dados geoespaciais. Isso melhora a performance e reduz o custo das consultas que usam filtros espaciais, geralmente para operações do BigQuery, como:

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

Adicionar agrupamento a uma tabela não agrupada também não prejudica nada, embora possa aumentar um pouco o tempo de carregamento de dados na tabela. Para saber mais sobre a otimização de consultas, consulte a documentação do BigQuery.

As configurações de agrupamento afetam apenas os dados novos gravados na tabela.

Demonstração: como usar reduceRegions

Em alguns casos, é possível usar reduceRegions para ter o máximo de paralelismo possível da infraestrutura de processamento do Earth Engine. Este exemplo demonstra como usar um número menor de chamadas reduceRegions (algumas centenas) em vez de dezenas de milhares de chamadas reduceRegion (a abordagem típica para mapear uma função em uma coleção).

Editor de código (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'
});

Configuração do Python

Consulte a página Ambiente Python para informações sobre a API Python e o uso de geemap para desenvolvimento interativo.

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

Paralelização de tarefas

Com a opção {append: true}, várias tarefas podem gravar dados em uma tabela do BigQuery simultaneamente. Esse é um mecanismo para gravar dados com um maior throughput, mas tem o custo de maior complexidade (gerenciamento da fila de tarefas, nova tentativa etc.).

Diferenças de desempenho entre os parâmetros append e overwrite

A substituição é mais lenta do que a adição porque o BigQuery precisa processar os novos dados antes de substituir os antigos. Definir o parâmetro {overwrite: true} ao exportar para uma tabela do BigQuery aciona um processo de substituição segura:

  1. Tabela temporária: os dados são exportados para uma nova tabela temporária no conjunto de dados de destino.
  2. Substituir de forma atômica: o conteúdo da tabela temporária é copiado para a tabela de destino final, substituindo os dados atuais em uma única transação atômica.
  3. Limpeza: a tabela temporária é excluída.

Isso garante que erros durante a exportação não corrompam seus dados. Para tabelas pequenas, o atraso geralmente é de alguns minutos.

Alternativas de alto desempenho

Para fluxos de trabalho que exigem um throughput muito alto, use o GeoBeam para mover dados do Earth Engine para o BigQuery. Isso requer mais configuração e infraestrutura. Por isso, sugerimos começar com a funcionalidade integrada do Earth Engine.

Preços

A exportação para o BigQuery é um processo em lote que consome o tempo de EECU em lote. Se você usar o Earth Engine comercialmente ou operacionalmente, a exportação de dados para o BigQuery vai cobrar o tempo de EECU usado pelas tarefas. Todo o uso pode ser monitorado com exatamente as mesmas ferramentas de monitoramento que funcionam para o restante do Earth Engine.

Contas do Cloud Billing

Para gravar dados no BigQuery, o projeto do Cloud associado precisa ter uma conta de faturamento ativada. Para saber mais sobre a configuração da conta de faturamento, consulte a documentação da conta de faturamento do Cloud.

Saída

Todos os custos de entrada e saída são cobrados como tráfego de rede padrão.

O Earth Engine é hospedado apenas nos EUA, mas os conjuntos de dados do BigQuery podem ser hospedados em várias outras regiões. Dependendo das regiões e dos volumes de dados envolvidos, a gravação de dados do Earth Engine no BigQuery pode gerar um tráfego de rede considerável.

Problemas conhecidos

Orientação para polígonos grandes

A função de exportação do BigQuery inverte polígonos maiores que um hemisfério reversando a orientação deles (mudando o polígono para o complemento geométrico). Em casos raros, polígonos maiores que um hemisfério podem não carregar.

Se necessário, os polígonos invertidos podem ser corrigidos no BigQuery invertendo-os novamente usando a expressão ST_Difference(ST_GeogFromText('fullglobe'), geo).

Para mais informações, acesse este link.