Consulta de tipos anidados en Parquet y archivos JSON mediante el grupo de SQL sin servidor en Azure Synapse Analytics

En este artículo, aprenderá a escribir una consulta mediante un grupo de SQL sin servidor en Azure Synapse Analytics. La consulta leerá los tipos anidados de Parquet. Los tipos anidados son estructuras complejas que representan objetos o matrices. Los tipos anidados se pueden almacenar en:

  • Parquet, donde puede tener varias columnas complejas que contengan matrices y objetos.
  • Los archivos JSON jerárquicos, donde puede leer un documento JSON complejo como una sola columna.
  • Colecciones de Azure Cosmos DB (actualmente en versión preliminar pública controlada), donde todos los documentos pueden contener propiedades anidadas complejas.

El grupo de SQL sin servidor da formato a todos los tipos anidados como matrices y objetos JSON. Por lo tanto, puede extraer o modificar objetos complejos mediante el uso de funciones JSON o analizar datos JSON mediante la función OPENJSON.

A continuación se muestra un ejemplo de una consulta que extrae valores escalares y de objetos del archivo JSON Conjunto de datos de investigación abierto para la COVID-19, que contiene objetos anidados:

SELECT
    title = JSON_VALUE(doc, '$.metadata.title'),
    first_author = JSON_QUERY(doc, '$.metadata.authors[0]'),
    first_author_name = JSON_VALUE(doc, '$.metadata.authors[0].first'),
    complex_object = doc
FROM
    OPENROWSET(
        BULK 'https://azureopendatastorage.blob.core.windows.net/covid19temp/comm_use_subset/pdf_json/000b7d1517ceebb34e1e3e817695b6de03e2fa78.json',
        FORMAT='CSV', FIELDTERMINATOR ='0x0b', FIELDQUOTE = '0x0b', ROWTERMINATOR = '0x0b'
    )
    WITH ( doc varchar(MAX) ) AS docs;

La función JSON_VALUE devuelve un valor escalar del campo en la ruta de acceso especificada. La función JSON_QUERY devuelve un objeto con formato JSON desde el campo en la ruta de acceso especificada.

Importante

En este ejemplo se usa un archivo del Conjunto de datos de investigación abierto para la COVID-19. Vea la licencia y la estructura de los datos aquí.

Requisitos previos

El primer paso es crear una base de datos en la que se creará el origen de datos. Luego, inicializará los objetos ejecutando un script de instalación en la base de datos. El script de instalación creará los orígenes de datos, las credenciales con ámbito de base de datos y los formatos de archivo externos que se usan en los ejemplos.

Proyección de datos anidados o repetidos de proyecto

Un archivo Parquet puede tener varias columnas con tipos complejos. Los valores de estas columnas tienen el formato de texto JSON y se devuelven como columnas VARCHAR. La columna siguiente lee el archivo structExample.parquet y muestra cómo leer los valores de las columnas anidadas:

SELECT
    DateStruct, TimeStruct, TimestampStruct, DecimalStruct, FloatStruct
FROM
    OPENROWSET(
        BULK 'parquet/nested/structExample.parquet',
        DATA_SOURCE = 'SqlOnDemandDemo',
        FORMAT='PARQUET'
    )
    WITH (
        DateStruct VARCHAR(8000),
        TimeStruct VARCHAR(8000),
        TimestampStruct VARCHAR(8000),
        DecimalStruct VARCHAR(8000),
        FloatStruct VARCHAR(8000)
    ) AS [r];

Esta consulta devuelve el siguiente resultado. El contenido de cada objeto anidado se devuelve como texto JSON.

DateStruct TimeStruct TimestampStruct DecimalStruct FloatStruct
{"Date":"2009-04-25"} {"Time":"20:51:54.3598000"} {"Timestamp":"5501-04-08 12:13:57.4821000"} {"Decimal":11143412.25350} {"Float":0.5}
{"Date":"1916-04-29"} {"Time":"00:16:04.6778000"} {"Timestamp":"1990-06-30 20:50:52.6828000"} {"Decimal":1963545.62800} {"Float":-2.125}

La siguiente consulta lee el archivo justSimpleArray.parquet. Proyecta todas las columnas del archivo Parquet, incluidos los datos anidados y repetidos.

SELECT
    SimpleArray
FROM
    OPENROWSET(
        BULK 'parquet/nested/justSimpleArray.parquet',
        DATA_SOURCE = 'SqlOnDemandDemo',
        FORMAT='PARQUET'
    ) AS [r];

Esta consulta devolverá el resultado siguiente:

SimpleArray
[11,12,13]
[21,22,23]

Lectura de propiedades desde columnas de objetos anidados

La función JSON_VALUE permite devolver valores desde las columnas con formato de texto JSON:

SELECT
    title = JSON_VALUE(complex_column, '$.metadata.title'),
    first_author_name = JSON_VALUE(complex_column, '$.metadata.authors[0].first'),
    body_text = JSON_VALUE(complex_column, '$.body_text.text'),
    complex_column
FROM
    OPENROWSET( BULK 'https://azureopendatastorage.blob.core.windows.net/covid19temp/comm_use_subset/pdf_json/000b7d1517ceebb34e1e3e817695b6de03e2fa78.json',
                FORMAT='CSV', FIELDTERMINATOR ='0x0b', FIELDQUOTE = '0x0b', ROWTERMINATOR = '0x0b' ) WITH ( complex_column varchar(MAX) ) AS docs;

El resultado se muestra en la tabla siguiente:

title first_author_name body_text complex_column
Información complementaria Un estudio de epide… Julien - Ilustración S1 : Filogenia de… { "paper_id": "000b7d1517ceebb34e1e3e817695b6de03e2fa78", "metadata": { "title": "Supplementary Information An eco-epidemiological study of Morbilli-related paramyxovirus infection in Madagascar bats reveals host-switching as the dominant macro-evolutionary mechanism", "authors": [ { "first": "Julien"

A diferencia de los archivos JSON, que en la mayoría de los casos devuelven una sola columna que contiene un objeto JSON complejo, los archivos Parquet pueden tener varias columnas complejas. Puede leer las propiedades de las columnas anidadas mediante la función JSON_VALUE en cada columna. OPENROWSET permite especificar directamente las rutas de acceso de las propiedades anidadas en una cláusula WITH. Puede establecer las rutas de acceso como el nombre de una columna o puede agregar una expresión de ruta de acceso JSON después del tipo de columna.

La siguiente consulta lee el archivo structExample.parquet y muestra cómo exponer los elementos de una columna anidada. Hay dos formas de hacer referencia a un valor anidado:

  • Especificando la expresión de ruta de acceso del valor anidado después de la especificación de tipo.
  • Dando formato al nombre de la columna como una ruta de acceso anidada mediante do "." para hacer referencia a los campos.
SELECT
    *
FROM
    OPENROWSET(
        BULK 'parquet/nested/structExample.parquet',
        DATA_SOURCE = 'SqlOnDemandDemo',
        FORMAT='PARQUET'
    )
    WITH (
        [DateValue] DATE '$.DateStruct.Date',
        [TimeStruct.Time] TIME,
        [TimestampStruct.Timestamp] DATETIME2,
        DecimalValue DECIMAL(18, 5) '$.DecimalStruct.Decimal',
        [FloatStruct.Float] FLOAT
    ) AS [r];

Acceso a elementos de columnas repetidas

La siguiente consulta lee el archivo justSimpleArray.parquet y usa JSON_VALUE para recuperar un elemento escalar de una columna repetida, como una matriz o una asignación:

SELECT
    *,
    JSON_VALUE(SimpleArray, '$[0]') AS FirstElement,
    JSON_VALUE(SimpleArray, '$[1]') AS SecondElement,
    JSON_VALUE(SimpleArray, '$[2]') AS ThirdElement
FROM
    OPENROWSET(
        BULK 'parquet/nested/justSimpleArray.parquet',
        DATA_SOURCE = 'SqlOnDemandDemo',
        FORMAT='PARQUET'
    ) AS [r];

Este es el resultado:

SimpleArray FirstElement SecondElement ThirdElement
[11,12,13] 11 12 13
[21,22,23] 21 22 23

Acceso a objetos secundarios desde columnas complejas

La consulta siguiente lee el archivo mapExample.parquet y usa JSON_QUERY para recuperar un elemento no escalar de una columna repetida, como una matriz o una asignación:

SELECT
    MapOfPersons,
    JSON_QUERY(MapOfPersons, '$."John Doe"') AS [John]
FROM
    OPENROWSET(
        BULK 'parquet/nested/mapExample.parquet',
        DATA_SOURCE = 'SqlOnDemandDemo',
        FORMAT='PARQUET'
    ) AS [r];

También puede hacer referencia explícitamente a las columnas que quiere que se devuelvan en una cláusula WITH:

SELECT DocId,
    MapOfPersons,
    JSON_QUERY(MapOfPersons, '$."John Doe"') AS [John]
FROM
    OPENROWSET(
        BULK 'parquet/nested/mapExample.parquet',
        DATA_SOURCE = 'SqlOnDemandDemo',
        FORMAT='PARQUET'
    ) 
    WITH (DocId bigint, MapOfPersons VARCHAR(max)) AS [r];

La estructura MapOfPersons se devuelve como una columna VARCHAR y con el formato de una cadena JSON.

Proyección de valores de columnas repetidas

Si tiene una matriz de valores escalares (por ejemplo, [1,2,3]) en algunas columnas, puede expandirlos fácilmente y combinarlos con la fila principal mediante este script:

SELECT
    SimpleArray, Element
FROM
    OPENROWSET(
        BULK 'parquet/nested/justSimpleArray.parquet',
        DATA_SOURCE = 'SqlOnDemandDemo',
        FORMAT='PARQUET'
    ) AS arrays
    CROSS APPLY OPENJSON (SimpleArray) WITH (Element int '$') as array_values

Pasos siguientes

En el siguiente artículo se muestra cómo consultar archivos JSON.