Compartir a través de


Interacción con Azure Cosmos DB mediante Apache Spark 2 en Azure Synapse Link

Nota

En el caso de Azure Synapse Link para Azure Cosmos DB mediante Spark 3, consulte el artículo Azure Synapse Link para Azure Cosmos DB en Spark 3.

En este artículo, aprenderá a interactuar con Azure Cosmos DB mediante Synapse Apache Spark 2. Gracias a su compatibilidad completa con Scala, Python, SparkSQL y C#, Synapse Apache Spark es fundamental para los escenarios de análisis, ingeniería de datos, ciencia de datos y exploración de datos en Azure Synapse Link para Azure Cosmos DB.

Al interactuar con Azure Cosmos DB, se admiten las siguientes funcionalidades:

  • Apache Spark de Synapse permite analizar los datos de los contenedores de Azure Cosmos DB que están habilitados con Azure Synapse Link casi en tiempo real, sin afectar al rendimiento de las cargas de trabajo transaccionales. Las dos opciones siguientes están disponibles para consultar el almacén analítico de Azure Cosmos DB desde Spark:
    • Cargar a DataFrame de Spark
    • Crear una tabla de Spark
  • Apache Spark de Synapse también le permite ingerir datos en Azure Cosmos DB. Es importante tener en cuenta que los datos siempre se ingieren en contenedores de Azure Cosmos DB a través del almacén transaccional. Cuando el Synapse Link está habilitado, las nuevas inserciones, actualizaciones y eliminaciones se sincronizan automáticamente con el almacén analítico.
  • Apache Spark de Synapse también admite Spark Structured Streaming con Azure Cosmos DB como origen y receptor.

Las secciones siguientes le guiarán por la sintaxis de las funcionalidades anteriores. También puede consultar el módulo de Learn sobre cómo consultar Azure Cosmos DB con Apache Spark para Azure Synapse Analytics. Los gestos en el área de trabajo de Azure Synapse Analytics están diseñados para proporcionarle una experiencia de introducción fácil de usar. Los gestos se muestran al hacer clic con el botón derecho en un contenedor de Azure Cosmos DB en la pestaña Datos del área de trabajo de Synapse. Con ellos, puede generar código rápidamente y adaptarlo a sus necesidades. También son ideales para detectar datos con un solo clic.

Importante

Debe tener en cuenta algunas restricciones en el esquema analítico que podrían provocar un comportamiento inesperado en las operaciones de carga de datos. Por ejemplo, en el esquema analítico solo están disponibles las mil primeras propiedades del esquema transaccional, las propiedades con espacios no lo están, etc. Si aparecen resultados inesperados, consulte las restricciones del esquema del almacén analítico para obtener más información.

Consulta al almacén analítico de Azure Cosmos DB

Antes de obtener información acerca de los dos métodos posibles para consultar al almacén analítico de Azure Cosmos DB, así como para cargar a un DataFrame de Spark y crear una tabla de Spark, merece la pena explorar las diferencias entre experiencias para que pueda elegir la opción que mejor se adapte a sus necesidades.

La diferencia en la experiencia radica en si los cambios de datos subyacentes en el contenedor de Azure Cosmos DB se deben reflejar automáticamente en el análisis realizado en Spark. Cuando se registra un DataFrame de Spark o se crea una tabla de Spark en el almacén analítico de un contenedor, los metadatos de la instantánea de datos actual en el almacén analítico se capturan en Spark para un aplicación eficaz del análisis subsiguiente. Es importante tener en cuenta que, ya que Spark usa una directiva de evaluación diferida, a menos que se invoque una acción en el DataFrame de Spark o se ejecute una consulta SparkSQL en la tabla de Spark, no se capturarán datos reales desde el almacén analítico del contenedor subyacente.

En el caso de la carga a DataFrame de Spark, los metadatos capturados se almacenan en caché durante la sesión de Spark y, por tanto, las siguientes acciones invocadas en el DataFrame se evalúan con según la instantánea del almacén analítico en el momento de creación del DataFrame.

Por otro lado, en el caso de la creación de una tabla de Spark, los metadatos del estado del almacén analítico no se almacenan en caché en Spark y se recargan en cada ejecución de la consulta de SparkSQL en la tabla de Spark.

Por lo tanto, puede elegir entre cargar a DataFrame de Spark y crear una tabla de Spark en función de si quiere que el análisis de Spark se evalúe con una instantánea fija del almacén analítico o con la instantánea más reciente del almacén analítico, respectivamente.

Si las consultas analíticas han usado filtros con frecuencia, tiene la opción de crear particiones en función de estos campos para mejorar el rendimiento de las consultas. Puede ejecutar periódicamente un trabajo de creación de particiones desde un cuaderno de Spark para Azure Synapse para desencadenar la creación de particiones en un almacén analítico. Este almacén con particiones apunta a la cuenta de almacenamiento principal de ADLS Gen2 que está vinculada al área de trabajo de Azure Synapse. Para más información, vea los artículos de introducción a la creación de particiones personalizadas y sobre cómo configurar la creación de particiones personalizadas.

Nota

Para consultar cuentas de Azure Cosmos DB for MongoDB, obtenga más información sobre la representación de esquemas de fidelidad completa en el almacén analítico y los nombres de propiedad extendidos que se van a usar.

Nota

Tenga en cuenta que todos los valores options de los comandos siguientes distinguen mayúsculas de minúsculas. Por ejemplo, debe usar Gateway, ya que gateway devolverá un error.

Cargar a DataFrame de Spark

En este ejemplo, creará un DataFrame de Spark que apunte al almacén analítico de Azure Cosmos DB. A continuación, puede realizar un análisis adicional mediante la invocación de las acciones de Spark en el DataFrame. Esta operación no afecta al almacén transaccional.

La sintaxis en Python sería la siguiente:

# To select a preferred list of regions in a multi-region Azure Cosmos DB account, add .option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

df = spark.read.format("cosmos.olap")\
    .option("spark.synapse.linkedService", "<enter linked service name>")\
    .option("spark.cosmos.container", "<enter container name>")\
    .load()

La sintaxis equivalente en Scala sería la siguiente:

// To select a preferred list of regions in a multi-region Azure Cosmos DB account, add option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

val df_olap = spark.read.format("cosmos.olap").
    option("spark.synapse.linkedService", "<enter linked service name>").
    option("spark.cosmos.container", "<enter container name>").
    load()

Crear una tabla de Spark

En este ejemplo, creará una tabla de Spark que apunte al almacén analítico de Azure Cosmos DB. A continuación, puede realizar un análisis adicional mediante la invocación de las consultas de SparkSQL en la tabla. Esta operación no afecta al almacén de transacciones ni provoca ningún movimiento de datos. Si decide eliminar esta tabla de Spark, el contenedor subyacente de Azure Cosmos DB y el almacén analítico correspondiente no se verán afectados.

Este escenario resulta práctico para volver a usar las tablas de Spark a través de herramientas de terceros y proporcionar accesibilidad a los datos subyacentes durante el tiempo de ejecución.

La sintaxis para crear una tabla de Spark es la siguiente:

%%sql
-- To select a preferred list of regions in a multi-region Azure Cosmos DB account, add spark.cosmos.preferredRegions '<Region1>,<Region2>' in the config options

create table call_center using cosmos.olap options (
    spark.synapse.linkedService '<enter linked service name>',
    spark.cosmos.container '<enter container name>'
)

Nota

Si hay escenarios en los que el esquema del contenedor de Azure Cosmos DB subyacente cambia con el tiempo y quiere que el esquema actualizado se refleje automáticamente en las consultas a la tabla de Spark, puede lograrlo estableciendo la opción spark.cosmos.autoSchemaMerge en true en las opciones de la tabla de Spark.

Escritura de DataFrame de Spark en el contenedor de Azure Cosmos DB

En este ejemplo, escribirá un DataFrame de Spark en un contenedor de Azure Cosmos DB. Esta operación afectará al rendimiento de las cargas de trabajo transaccionales y consumirá unidades de solicitud aprovisionadas en el contenedor de Azure Cosmos DB o en la base de datos compartida.

La sintaxis en Python sería la siguiente:

# Write a Spark DataFrame into an Azure Cosmos DB container
# To select a preferred list of regions in a multi-region Azure Cosmos DB account, add .option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

YOURDATAFRAME.write.format("cosmos.oltp")\
    .option("spark.synapse.linkedService", "<enter linked service name>")\
    .option("spark.cosmos.container", "<enter container name>")\
    .option("spark.cosmos.write.upsertEnabled", "true")\
    .mode('append')\
    .save()

La sintaxis equivalente en Scala sería la siguiente:

// To select a preferred list of regions in a multi-region Azure Cosmos DB account, add option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

import org.apache.spark.sql.SaveMode

df.write.format("cosmos.oltp").
    option("spark.synapse.linkedService", "<enter linked service name>").
    option("spark.cosmos.container", "<enter container name>"). 
    option("spark.cosmos.write.upsertEnabled", "true").
    mode(SaveMode.Overwrite).
    save()

Cargar un DataFrame de streaming desde un contenedor

En este gesto, usará la funcionalidad de streaming de Spark para cargar datos de un contenedor en un DataFrame. Los datos se almacenarán en la cuenta principal del lago de datos (y en el sistema de archivos) que conectó al área de trabajo.

Nota

Si quiere hacer referencia a bibliotecas externas en Apache Spark de Synapse, obtenga más información aquí. Por ejemplo, si quiere ingerir un DataFrame de Spark en un contenedor de Azure Cosmos DB for MongoDB, puede usar el conector de Mongo DB para Spark.

Cargar un DataFrame de streaming desde un contenedor de Azure Cosmos DB

En este ejemplo, usará la funcionalidad Structured Streaming de Spark para cargar datos de un contenedor de Azure Cosmos DB a un DataFrame de streaming de Spark mediante la funcionalidad de fuente de cambios en Azure Cosmos DB. Los datos del punto de comprobación que usó Spark se almacenarán en la cuenta principal del lago de datos (y en el sistema de archivos) que conectó al área de trabajo.

Si no se creó la carpeta /localReadCheckpointFolder (en el siguiente ejemplo), se creará automáticamente. Esta operación afectará al rendimiento de las cargas de trabajo transaccionales y consumirá unidades de solicitud aprovisionadas en el contenedor de Azure Cosmos DB o la base de datos compartida.

La sintaxis en Python sería la siguiente:

# To select a preferred list of regions in a multi-region Azure Cosmos DB account, add .option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

dfStream = spark.readStream\
    .format("cosmos.oltp")\
    .option("spark.synapse.linkedService", "<enter linked service name>")\
    .option("spark.cosmos.container", "<enter container name>")\
    .option("spark.cosmos.changeFeed.readEnabled", "true")\
    .option("spark.cosmos.changeFeed.startFromTheBeginning", "true")\
    .option("spark.cosmos.changeFeed.checkpointLocation", "/localReadCheckpointFolder")\
    .option("spark.cosmos.changeFeed.queryName", "streamQuery")\
    .load()

La sintaxis equivalente en Scala sería la siguiente:

// To select a preferred list of regions in a multi-region Azure Cosmos DB account, add .option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

val dfStream = spark.readStream.
    format("cosmos.oltp").
    option("spark.synapse.linkedService", "<enter linked service name>").
    option("spark.cosmos.container", "<enter container name>").
    option("spark.cosmos.changeFeed.readEnabled", "true").
    option("spark.cosmos.changeFeed.startFromTheBeginning", "true").
    option("spark.cosmos.changeFeed.checkpointLocation", "/localReadCheckpointFolder").
    option("spark.cosmos.changeFeed.queryName", "streamQuery").
    load()

Escritura de DataFrame de streaming a un contenedor de Azure Cosmos DB

En este ejemplo, escribirá un DataFrame de streaming en un contenedor de Azure Cosmos DB. Esta operación afectará al rendimiento de las cargas de trabajo transaccionales y consumirá unidades de solicitud aprovisionadas en el contenedor de Azure Cosmos DB o la base de datos compartida. Si no se creó la carpeta /localWriteCheckpointFolder (en el siguiente ejemplo), se creará automáticamente.

La sintaxis en Python sería la siguiente:

# To select a preferred list of regions in a multi-region Azure Cosmos DB account, add .option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

# If you are using managed private endpoints for Azure Cosmos DB analytical store and using batch writes/reads and/or streaming writes/reads to transactional store you should set connectionMode to Gateway. 

def writeBatchToCosmos(batchDF, batchId):
  batchDF.persist()
  print("--> BatchId: {}, Document count: {} : {}".format(batchId, batchDF.count(), datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S.%f")))
  batchDF.write.format("cosmos.oltp")\
    .option("spark.synapse.linkedService", "<enter linked service name>")\
    .option("spark.cosmos.container", "<enter container name>")\
    .option("spark.cosmos.write.upsertEnabled", "true")\
    .mode('append')\
    .save()
  print("<-- BatchId: {}, Document count: {} : {}".format(batchId, batchDF.count(), datetime.datetime.utcnow().strftime("%Y-%m-%d %H:%M:%S.%f")))
  batchDF.unpersist()

streamQuery = dfStream\
        .writeStream\
        .foreachBatch(writeBatchToCosmos) \
        .option("checkpointLocation", "/localWriteCheckpointFolder")\
        .start()

streamQuery.awaitTermination()

La sintaxis equivalente en Scala sería la siguiente:

// To select a preferred list of regions in a multi-region Azure Cosmos DB account, add .option("spark.cosmos.preferredRegions", "<Region1>,<Region2>")

// If you are using managed private endpoints for Azure Cosmos DB analytical store and using batch writes/reads and/or streaming writes/reads to transactional store you should set connectionMode to Gateway. 

val query = dfStream.
            writeStream.
            foreachBatch { (batchDF: DataFrame, batchId: Long) =>
              batchDF.persist()
              batchDF.write.format("cosmos.oltp").
                option("spark.synapse.linkedService", "<enter linked service name>").
                option("spark.cosmos.container", "<enter container name>"). 
                option("spark.cosmos.write.upsertEnabled", "true").
                mode(SaveMode.Overwrite).
                save()
              println(s"BatchId: $batchId, Document count: ${batchDF.count()}")
              batchDF.unpersist()
              ()
            }.        
            option("checkpointLocation", "/localWriteCheckpointFolder").
            start()

query.awaitTermination()

Pasos siguientes