Executar um DAG de análise de dados no Google Cloud usando dados do Azure

Cloud Composer 1 | Cloud Composer 2 | Cloud Composer 3

Este tutorial é uma modificação Execute um DAG de análise de dados no Google Cloud que mostra como conectar seu ambiente do Cloud Composer ao Microsoft Azure para utilizar os dados armazenados nele. Ele mostra como usar o Cloud Composer para criar DAG do Apache Airflow (em inglês). O O DAG mescla os dados de um conjunto de dados público do BigQuery e um arquivo CSV armazenado em uma Armazenamento de blobs do Azure e executa um job em lote do Dataproc sem servidor para processar os dados dados.

O conjunto de dados público do BigQuery neste tutorial é ghcn_d, um banco de dados integrado de resumos climáticos em todo o globo. O arquivo CSV contém informações sobre as datas e os nomes dos feriados dos EUA de 1997 a 2021.

A pergunta que queremos responder usando a DAG é: "Qual foi a temperatura em Chicago no Dia de Ação de Graças nos últimos 25 anos?"

Objetivos

  • Criar um ambiente do Cloud Composer na configuração padrão
  • Criar um blob no Azure
  • Criar um conjunto de dados vazio do BigQuery
  • Crie um novo bucket do Cloud Storage
  • Crie e execute um DAG que inclua as seguintes tarefas:
    • Carregue um conjunto de dados externo do Armazenamento de Blobs do Azure para Cloud Storage
    • Carregar um conjunto de dados externos do Cloud Storage para o BigQuery
    • Mesclar dois conjuntos de dados no BigQuery
    • Executar um job de análise de dados do PySpark

Antes de começar

Ativar APIs

Ative as APIs a seguir:

Console

Enable the Dataproc, Cloud Composer, BigQuery, Cloud Storage APIs.

Enable the APIs

gcloud

Enable the Dataproc, Cloud Composer, BigQuery, Cloud Storage APIs:

gcloud services enable dataproc.googleapis.com  composer.googleapis.com  bigquery.googleapis.com  storage.googleapis.com

Conceder permissões

Conceda os seguintes papéis e permissões à conta de usuário:

Criar e preparar seu ambiente do Cloud Composer

  1. Crie um ambiente do Cloud Composer com padrões parâmetros:

  2. Conceda os papéis a seguir à conta de serviço usada no seu ambiente do Cloud Composer para que os workers do Airflow possam executar tarefas de DAG:

    • Usuário do BigQuery (roles/bigquery.user)
    • Proprietário de dados do BigQuery (roles/bigquery.dataOwner)
    • Usuário da conta de serviço (roles/iam.serviceAccountUser)
    • Editor do Dataproc (roles/dataproc.editor)
    • Worker do Dataproc (roles/dataproc.worker)
  1. Instale o apache-airflow-providers-microsoft-azure pacote PyPI no seu ambiente do Cloud Composer.

  2. Crie um conjunto de dados vazio do BigQuery com os seguintes parâmetros:

    • Nome: holiday_weather
    • Região: US
  3. Crie um bucket do Cloud Storage na multirregião US.

  4. Execute o comando a seguir para ativar o Acesso particular do Google na sub-rede padrão na região em que você quer executar o Dataproc sem servidor para atender aos requisitos de rede. Qa use a mesma região do Cloud Composer de nuvem.

    gcloud compute networks subnets update default \
        --region DATAPROC_SERVERLESS_REGION \
        --enable-private-ip-google-access
    
  1. Crie uma conta de armazenamento com as configurações padrão.

  2. Receba a chave de acesso e a string de conexão para sua conta de armazenamento.

  3. Crie um contêiner com opções padrão na conta de armazenamento recém-criada.

  4. Conceder ao delegador de blob de armazenamento para o contêiner criado na etapa anterior.

  5. Fazer upload do arquivo holidays.csv para criar um blob de bloco com opções padrão no portal do Azure.

  6. Crie um token SAS para o blob de bloco criado na etapa anterior no portal do Azure.

    • Método de assinatura: chave de delegação do usuário
    • Permissões: leitura
    • Endereço IP permitido: nenhum
    • Protocolos permitidos: somente HTTPS

Conectar ao Azure pelo Cloud Composer

Adicionar o Microsoft Azure conexão usando a interface do Airflow:

  1. Acesse Administrador > Conexões.

  2. Crie uma nova conexão com a seguinte configuração:

    • ID da conexão: azure_blob_connection
    • Tipo de conexão: Azure Blob Storage
    • Login no armazenamento de blobs:o nome da sua conta de armazenamento
    • Chave de armazenamento de blobs: a chave de acesso para sua conta de armazenamento
    • String de conexão da conta do Blob Storage: sua string de conexão da conta de armazenamento.
    • Token SAS: o token SAS gerado do seu blob

Processamento de dados com o Dataproc sem servidor

conheça o exemplo de job do PySpark

O código mostrado abaixo é um exemplo de job do PySpark que converte a temperatura de décimos de um grau em graus Celsius. Esse job converte os dados de temperatura do conjunto de dados em um formato diferente.

import sys


from py4j.protocol import Py4JJavaError
from pyspark.sql import SparkSession
from pyspark.sql.functions import col


if __name__ == "__main__":
    BUCKET_NAME = sys.argv[1]
    READ_TABLE = sys.argv[2]
    WRITE_TABLE = sys.argv[3]

    # Create a SparkSession, viewable via the Spark UI
    spark = SparkSession.builder.appName("data_processing").getOrCreate()

    # Load data into dataframe if READ_TABLE exists
    try:
        df = spark.read.format("bigquery").load(READ_TABLE)
    except Py4JJavaError as e:
        raise Exception(f"Error reading {READ_TABLE}") from e

    # Convert temperature from tenths of a degree in celsius to degrees celsius
    df = df.withColumn("value", col("value") / 10)
    # Display sample of rows
    df.show(n=20)

    # Write results to GCS
    if "--dry-run" in sys.argv:
        print("Data will not be uploaded to BigQuery")
    else:
        # Set GCS temp location
        temp_path = BUCKET_NAME

        # Saving the data to BigQuery using the "indirect path" method and the spark-bigquery connector
        # Uses the "overwrite" SaveMode to ensure DAG doesn't fail when being re-run
        # See https://spark.apache.org/docs/latest/sql-data-sources-load-save-functions.html#save-modes
        # for other save mode options
        df.write.format("bigquery").option("temporaryGcsBucket", temp_path).mode(
            "overwrite"
        ).save(WRITE_TABLE)
        print("Data written to BigQuery")

Faça upload do arquivo PySpark para o Cloud Storage

Para fazer upload do arquivo PySpark no Cloud Storage:

  1. Salve data_analytics_process.py na sua máquina local.

  2. No console do Google Cloud, acesse a página Navegador do Cloud Storage:

    Ir para o navegador do Cloud Storage

  3. Clique no nome do bucket que você criou anteriormente.

  4. Na guia Objetos do bucket, clique no botão Fazer upload de arquivos, selecione data_analytics_process.py na caixa de diálogo exibida e clique em Abrir.

DAG de análise de dados

conheça o DAG de exemplo

O DAG usa vários operadores para transformar e unificar os dados:

import datetime

from airflow import models
from airflow.providers.google.cloud.operators import dataproc
from airflow.providers.google.cloud.operators.bigquery import BigQueryInsertJobOperator
from airflow.providers.google.cloud.transfers.gcs_to_bigquery import (
    GCSToBigQueryOperator,
)
from airflow.providers.microsoft.azure.transfers.azure_blob_to_gcs import (
    AzureBlobStorageToGCSOperator,
)
from airflow.utils.task_group import TaskGroup

PROJECT_NAME = "{{var.value.gcp_project}}"
REGION = "{{var.value.gce_region}}"

# BigQuery configs
BQ_DESTINATION_DATASET_NAME = "holiday_weather"
BQ_DESTINATION_TABLE_NAME = "holidays_weather_joined"
BQ_NORMALIZED_TABLE_NAME = "holidays_weather_normalized"

# Dataproc configs
BUCKET_NAME = "{{var.value.gcs_bucket}}"
PYSPARK_JAR = "gs://spark-lib/bigquery/spark-bigquery-latest_2.12.jar"
PROCESSING_PYTHON_FILE = f"gs://{BUCKET_NAME}/data_analytics_process.py"

# Azure configs
AZURE_BLOB_NAME = "{{var.value.azure_blob_name}}"
AZURE_CONTAINER_NAME = "{{var.value.azure_container_name}}"

BATCH_ID = "data-processing-{{ ts_nodash | lower}}"  # Dataproc serverless only allows lowercase characters
BATCH_CONFIG = {
    "pyspark_batch": {
        "jar_file_uris": [PYSPARK_JAR],
        "main_python_file_uri": PROCESSING_PYTHON_FILE,
        "args": [
            BUCKET_NAME,
            f"{BQ_DESTINATION_DATASET_NAME}.{BQ_DESTINATION_TABLE_NAME}",
            f"{BQ_DESTINATION_DATASET_NAME}.{BQ_NORMALIZED_TABLE_NAME}",
        ],
    },
    "environment_config": {
        "execution_config": {
            "service_account": "{{var.value.dataproc_service_account}}"
        }
    },
}

yesterday = datetime.datetime.combine(
    datetime.datetime.today() - datetime.timedelta(1), datetime.datetime.min.time()
)

default_dag_args = {
    # Setting start date as yesterday starts the DAG immediately when it is
    # detected in the Cloud Storage bucket.
    "start_date": yesterday,
    # To email on failure or retry set 'email' arg to your email and enable
    # emailing here.
    "email_on_failure": False,
    "email_on_retry": False,
}

with models.DAG(
    "azure_to_gcs_dag",
    # Continue to run DAG once per day
    schedule_interval=datetime.timedelta(days=1),
    default_args=default_dag_args,
) as dag:
    azure_blob_to_gcs = AzureBlobStorageToGCSOperator(
        task_id="azure_blob_to_gcs",
        # Azure args
        blob_name=AZURE_BLOB_NAME,
        container_name=AZURE_CONTAINER_NAME,
        wasb_conn_id="azure_blob_connection",
        filename=f"https://console.cloud.google.com/storage/browser/{BUCKET_NAME}/",
        # GCP args
        gcp_conn_id="google_cloud_default",
        object_name="holidays.csv",
        bucket_name=BUCKET_NAME,
        gzip=False,
        impersonation_chain=None,
    )

    create_batch = dataproc.DataprocCreateBatchOperator(
        task_id="create_batch",
        project_id=PROJECT_NAME,
        region=REGION,
        batch=BATCH_CONFIG,
        batch_id=BATCH_ID,
    )

    load_external_dataset = GCSToBigQueryOperator(
        task_id="run_bq_external_ingestion",
        bucket=BUCKET_NAME,
        source_objects=["holidays.csv"],
        destination_project_dataset_table=f"{BQ_DESTINATION_DATASET_NAME}.holidays",
        source_format="CSV",
        schema_fields=[
            {"name": "Date", "type": "DATE"},
            {"name": "Holiday", "type": "STRING"},
        ],
        skip_leading_rows=1,
        write_disposition="WRITE_TRUNCATE",
    )

    with TaskGroup("join_bq_datasets") as bq_join_group:
        for year in range(1997, 2022):
            BQ_DATASET_NAME = f"bigquery-public-data.ghcn_d.ghcnd_{str(year)}"
            BQ_DESTINATION_TABLE_NAME = "holidays_weather_joined"
            # Specifically query a Chicago weather station
            WEATHER_HOLIDAYS_JOIN_QUERY = f"""
            SELECT Holidays.Date, Holiday, id, element, value
            FROM `{PROJECT_NAME}.holiday_weather.holidays` AS Holidays
            JOIN (SELECT id, date, element, value FROM {BQ_DATASET_NAME} AS Table
            WHERE Table.element="TMAX" AND Table.id="USW00094846") AS Weather
            ON Holidays.Date = Weather.Date;
            """

            # For demo purposes we are using WRITE_APPEND
            # but if you run the DAG repeatedly it will continue to append
            # Your use case may be different, see the Job docs
            # https://cloud.google.com/bigquery/docs/reference/rest/v2/Job
            # for alternative values for the writeDisposition
            # or consider using partitioned tables
            # https://cloud.google.com/bigquery/docs/partitioned-tables
            bq_join_holidays_weather_data = BigQueryInsertJobOperator(
                task_id=f"bq_join_holidays_weather_data_{str(year)}",
                configuration={
                    "query": {
                        "query": WEATHER_HOLIDAYS_JOIN_QUERY,
                        "useLegacySql": False,
                        "destinationTable": {
                            "projectId": PROJECT_NAME,
                            "datasetId": BQ_DESTINATION_DATASET_NAME,
                            "tableId": BQ_DESTINATION_TABLE_NAME,
                        },
                        "writeDisposition": "WRITE_APPEND",
                    }
                },
                location="US",
            )

        azure_blob_to_gcs >> load_external_dataset >> bq_join_group >> create_batch

Usar a interface do Airflow para adicionar variáveis

No Airflow, as variáveis são uma maneira universal de armazenar e recuperar configurações ou configurações arbitrárias como um repositório de chave-valor simples. Esse DAG usa variáveis do Airflow para armazenar valores comuns. Para adicionar ao seu ambiente:

  1. Acesse a IU do Airflow pelo console do Cloud Composer.

  2. Acesse Administrador > Variáveis.

  3. Adicione as seguintes variáveis:

    • gcp_project: o ID do projeto.

    • gcs_bucket: o nome do bucket criado anteriormente (sem o prefixo gs://).

    • gce_region: a região em que você quer que as job do Dataproc que atenda Requisitos de rede sem servidor do Dataproc. Esta é a região em que você ativou o Acesso privado do Google anteriormente.

    • dataproc_service_account: a conta de serviço do ambiente do Cloud Composer. Você pode encontrar esse serviço do contêiner na guia de configuração do ambiente da sua ambiente do Cloud Composer.

    • azure_blob_name: o nome do blob criado anteriormente.

    • azure_container_name: o nome do contêiner criado anteriormente.

Faça upload do DAG para o bucket do ambiente

O Cloud Composer programa DAGs localizados no /dags no bucket do ambiente. Para fazer o upload do DAG usando o Console do Google Cloud:

  1. Na máquina local, salve o arquivo azureblobstoretogcsoperator_tutorial.py.

  2. No console do Google Cloud, acesse a página Ambientes.

    Acessar "Ambientes"

  3. Na lista de ambientes, na coluna Pasta de DAGs, clique no link DAGs. A pasta de DAGs do seu ambiente é aberta.

  4. Clique em Fazer o upload dos arquivos.

  5. Selecione azureblobstoretogcsoperator_tutorial.py na máquina local e clique em Abrir.

Como acionar o DAG

  1. No ambiente do Cloud Composer, clique na guia DAGs.

  2. Clique no ID do DAG azure_blob_to_gcs_dag.

  3. Clique em Trigger DAG.

  4. Aguarde de cinco a dez minutos até que uma marca de seleção verde apareça, indicando que as tarefas foram concluídas.

Validar o sucesso do DAG

  1. No console do Google Cloud, acesse a página do BigQuery.

    Ir para o BigQuery

  2. No painel Explorer, clique no nome do projeto.

  3. Clique em holidays_weather_joined.

  4. Clique em "Visualizar" para ver a tabela resultante. Os números na coluna "Valor" estão em décimos de um grau Celsius.

  5. Clique em holidays_weather_normalized.

  6. Clique em "Visualizar" para ver a tabela resultante. Os números na coluna de valores estão em graus Celsius.

Limpeza

Exclua os recursos individuais que você criou para este tutorial:

A seguir