Nota
L'accés a aquesta pàgina requereix autorització. Pots provar d'iniciar sessió o canviar de directori.
L'accés a aquesta pàgina requereix autorització. Pots provar de canviar directoris.
Importante
Esta característica está en versión preliminar pública.
En este artículo se describe cómo puede consultar y transformar datos semiestructurados almacenados como VARIANT. El tipo de datos VARIANT está disponible en Databricks Runtime 15.3 y versiones posteriores.
Databricks recomienda usar VARIANT en vez de cadenas JSON. Para los usuarios que actualmente usan cadenas JSON que buscan migrar, consulte ¿En que se diferencia Variant de las cadenas JSON?
Si desea ver ejemplos para consultar datos semiestructurados almacenados con cadenas JSON, revise Consulta de cadenas JSON.
Nota:
VARIANT columnas no se pueden usar para claves de agrupamiento, particiones ni claves de orden Z. No se puede usar el tipo de datos VARIANT para comparaciones, agrupación, ordenación y establecimiento de operaciones. Para obtener una lista completa de las limitaciones, consulta Limitaciones.
Creación de una tabla con una columna Variant
Para crear una columna variant, use la parse_json función (SQL o Python).
Ejecute lo siguiente para crear una tabla con datos altamente anidados almacenados como VARIANT. (Estos datos se usan en otros ejemplos de esta página).
SQL
-- Create a table with a variant column
CREATE TABLE store_data AS
SELECT parse_json(
'{
"store":{
"fruit": [
{"weight":8,"type":"apple"},
{"weight":9,"type":"pear"}
],
"basket":[
[1,2,{"b":"y","a":"x"}],
[3,4],
[5,6]
],
"book":[
{
"author":"Nigel Rees",
"title":"Sayings of the Century",
"category":"reference",
"price":8.95
},
{
"author":"Herman Melville",
"title":"Moby Dick",
"category":"fiction",
"price":8.99,
"isbn":"0-553-21311-3"
},
{
"author":"J. R. R. Tolkien",
"title":"The Lord of the Rings",
"category":"fiction",
"reader":[
{"age":25,"name":"bob"},
{"age":26,"name":"jack"}
],
"price":22.99,
"isbn":"0-395-19395-8"
}
],
"bicycle":{
"price":19.95,
"color":"red"
}
},
"owner":"amy",
"zip code":"94025",
"fb:testid":"1234"
}'
) as raw
SELECT * FROM store_data
Pitón
# Create a table with a variant column
store_data='''
{
"store":{
"fruit":[
{"weight":8,"type":"apple"},
{"weight":9,"type":"pear"}
],
"basket":[
[1,2,{"b":"y","a":"x"}],
[3,4],
[5,6]
],
"book":[
{
"author":"Nigel Rees",
"title":"Sayings of the Century",
"category":"reference",
"price":8.95
},
{
"author":"Herman Melville",
"title":"Moby Dick",
"category":"fiction",
"price":8.99,
"isbn":"0-553-21311-3"
},
{
"author":"J. R. R. Tolkien",
"title":"The Lord of the Rings",
"category":"fiction",
"reader":[
{"age":25,"name":"bob"},
{"age":26,"name":"jack"}
],
"price":22.99,
"isbn":"0-395-19395-8"
}
],
"bicycle":{
"price":19.95,
"color":"red"
}
},
"owner":"amy",
"zip code":"94025",
"fb:testid":"1234"
}
'''
# Create a DataFrame
df = spark.createDataFrame([(store_data,)], ["json"])
# Convert to a variant
df_variant = df.select(parse_json(col("json")).alias("raw"))
# Alternatively, create the DataFrame directly
# df_variant = spark.range(1).select(parse_json(lit(store_data)))
df_variant.display()
# Write out as a table
df_variant.write.saveAsTable("store_data")
Campos de consulta en una columna Variant
Para extraer campos de una columna variant, use la variant_get función (SQL o Python) que especifica el nombre del campo JSON en la ruta de extracción. Los nombres de campo distinguen siempre entre mayúsculas y minúsculas.
SQL
-- Extract a top-level field
SELECT variant_get(store_data.raw, '$.owner') AS owner FROM store_data
También puede usar la sintaxis SQL para consultar campos en una columna variant. Consulte abreviatura SQL para variant_get.
Pitón
# Extract a top-level field
df_variant.select(variant_get(col("raw"), "$.owner", "string")).display()
Abreviatura de SQL para variant_get
La sintaxis SQL para consultar cadenas JSON y otros tipos de datos complejos en Azure Databricks se aplica a VARIANT los datos, incluidos los siguientes:
- Use
:para seleccionar campos de nivel superior. - Use
.o[<key>]para seleccionar campos anidados con claves con nombre. - Use
[<index>]para seleccionar valores de matrices.
SELECT raw:owner FROM store_data
+-------+
| owner |
+-------+
| "amy" |
+-------+
-- Use backticks to escape special characters.
SELECT raw:`zip code`, raw:`fb:testid` FROM store_data
+----------+-----------+
| zip code | fb:testid |
+----------+-----------+
| "94025" | "1234" |
+----------+-----------+
Si un nombre de campo contiene un punto (.), debe aplicarle escape con corchetes ([ ]). Por ejemplo, la consulta siguiente selecciona un campo denominado zip.code:
SELECT raw:['zip.code'] FROM store_data
Extracción de campos anidados de Variant
Para extraer campos anidados de una columna variante, especifíquelos mediante notación de punto o corchetes. Los nombres de campo distinguen siempre entre mayúsculas y minúsculas.
SQL
-- Use dot notation
SELECT raw:store.bicycle FROM store_data
-- Use brackets
SELECT raw:store['bicycle'] FROM store_data
Si no se encuentra una ruta de acceso, el resultado es NULL del tipo VARIANT.
Pitón
# Use dot notation
df_variant.select(variant_get(col("raw"), "$.store.bicycle", "string")).display()
# Use brackets
df_variant.select(variant_get(col("raw"), "$.store['bicycle']", "string")).display()
Si no se encuentra una ruta de acceso, el resultado es null del tipo VariantVal.
+-----------------+
| bicycle |
+-----------------+
| { |
| "color":"red", |
| "price":19.95 |
| } |
+-----------------+
Extracción de valores de matrices de Variant
Para extraer elementos de matrices, indexe con corchetes. Los índices tienen base 0.
SQL
-- Index elements
SELECT raw:store.fruit[0], raw:store.fruit[1] FROM store_data
Pitón
# Index elements
df_variant.select((variant_get(col("raw"), "$.store.fruit[0]", "string")),(variant_get(col("raw"), "$.store.fruit[1]", "string"))).display()
+-------------------+------------------+
| fruit | fruit |
+-------------------+------------------+
| { | { |
| "type":"apple", | "type":"pear", |
| "weight":8 | "weight":9 |
| } | } |
+-------------------+------------------+
Si no se encuentra la ruta de acceso o si el índice de matriz está fuera de los límites, el resultado es NULL.
Trabajar con variantes en Python
Puede extraer variantes de los DataFrames de Spark en Python como VariantVal y trabajar con ellas de forma individual mediante los métodos toPython y toJson.
# toPython
data = [
('{"name": "Alice", "age": 25}',),
('["person", "electronic"]',),
('1',)
]
df_person = spark.createDataFrame(data, ["json"])
# Collect variants into a VariantVal
variants = df_person.select(parse_json(col("json")).alias("v")).collect()
Output VariantVal como una cadena JSON:
print(variants[0].v.toJson())
{"age":25,"name":"Alice"}
Convertir un objeto VariantVal en un objeto de Python:
# First element is a dictionary
print(variants[0].v.toPython()["age"])
25
# Second element is a List
print(variants[1].v.toPython()[1])
electronic
# Third element is an Integer
print(variants[2].v.toPython())
1
También puede construir VariantVal mediante la VariantVal.parseJson función .
# parseJson to construct VariantVal's in Python
from pyspark.sql.types import VariantVal
variant = VariantVal.parseJson('{"a": 1}')
Imprima la variante como una cadena JSON:
print(variant.toJson())
{"a":1}
Convierta la variante en un objeto de Python e imprima un valor:
print(variant.toPython()["a"])
1
Devolver el esquema de una variante
Para devolver el esquema de una variante, use la schema_of_variant función (SQL o Python).
SQL
-- Return the schema of the variant
SELECT schema_of_variant(raw) FROM store_data;
Pitón
# Return the schema of the variant
df_variant.select(schema_of_variant(col("raw"))).display()
Para devolver los esquemas combinados de todas las variantes de un grupo, use la schema_of_variant_agg función (SQL o Python).
Los ejemplos siguientes devuelven el esquema y, a continuación, el esquema combinado para los datos json_datade ejemplo .
SQL
CREATE OR REPLACE TEMP VIEW json_data AS
SELECT '{"name": "Alice", "age": 25}' AS json UNION ALL
SELECT '{"id": 101, "department": "HR"}' UNION ALL
SELECT '{"product": "Laptop", "price": 1200.50, "in_stock": true}';
-- Return the schema
SELECT schema_of_variant(parse_json(json)) FROM json_data;
Pitón
json_data = [
('{"name": "Alice", "age": 25}',),
('{"id": 101, "department": "HR"}',),
('{"product": "Laptop", "price": 1200.50, "in_stock": true}',)
]
df_item = spark.createDataFrame(json_data, ["json"])
# Return the schema
df_item.select(parse_json(col("json")).alias("v")).select(schema_of_variant(col("v"))).display()
+-----------------------------------------------------------------+
| schema_of_variant(v) |
+-----------------------------------------------------------------+
| OBJECT<age: BIGINT, name: STRING> |
| OBJECT<department: STRING, id: BIGINT> |
| OBJECT<in_stock: BOOLEAN, price: DECIMAL(5,1), product: STRING> |
+-----------------------------------------------------------------+
SQL
-- Return the combined schema
SELECT schema_of_variant_agg(parse_json(json)) FROM json_data;
Pitón
# Return the combined schema
df.select(parse_json(col("json")).alias("v")).select(schema_of_variant_agg(col("v"))).display()
+----------------------------------------------------------------------------------------------------------------------------+
| schema_of_variant(v) |
+----------------------------------------------------------------------------------------------------------------------------+
| OBJECT<age: BIGINT, department: STRING, id: BIGINT, in_stock: BOOLEAN, name: STRING, price: DECIMAL(5,1), product: STRING> |
+----------------------------------------------------------------------------------------------------------------------------+
Simplificar objetos y matrices Variant
La variant_explode función generadora con valores de tabla (SQL o Python) se puede usar para aplanar matrices y objetos variants.
SQL
Dado que variant_explode es una función de generador, se usa como parte de la cláusula FROM en lugar de en la lista SELECT, como en los ejemplos siguientes:
SELECT key, value
FROM store_data,
LATERAL variant_explode(store_data.raw);
SELECT pos, value
FROM store_data,
LATERAL variant_explode(store_data.raw:store.basket[0]);
Pitón
Utiliza la API DataFrame de función con valores de tabla (TVF) para expandir una variante en múltiples filas.
spark.tvf.variant_explode(parse_json(lit(store_data))).display()
# To explode a nested field, first create a DataFrame with just the field
df_store_col = df_variant.select(variant_get(col("raw"), "$.store", "variant").alias("store"))
# Perform the explode with a lateral join and the outer function to return the new exploded DataFrame
df_store_exploded_lj = df_store_col.lateralJoin(spark.tvf.variant_explode(col("store").outer()))
df_store_exploded = df_store_exploded_lj.drop("store")
df_store_exploded.display()
Reglas de conversión de tipos Variant
Puede almacenar matrices y escalares usando el tipo VARIANT. Al intentar convertir tipos Variant a otros tipos, las reglas de conversión normales se aplican a valores y campos individuales, con las siguientes reglas adicionales.
Nota:
variant_get y try_variant_get toman argumentos de tipo y siguen estas reglas de conversión.
| Tipo de origen | Comportamiento |
|---|---|
VOID |
El resultado es un valor NULL de tipo VARIANT. |
ARRAY<elementType> |
El valor elementType debe ser de un tipo que se pueda convertir en VARIANT. |
Al inferir el tipo con schema_of_variant o schema_of_variant_agg, las funciones vuelven al tipo VARIANT en lugar de al tipo STRING cuando hay tipos en conflicto que no pueden resolverse.
SQL
Use la función try_variant_get (SQL) para convertir:
-- price is returned as a double, not a string
SELECT try_variant_get(raw, '$.store.bicycle.price', 'double') as price FROM store_data
+------------------+
| price |
+------------------+
| 19.95 |
+------------------+
También puede usar :: o cast convertir valores en tipos de datos admitidos:
-- cast into more complex types
SELECT cast(raw:store.bicycle AS STRUCT<price DOUBLE, color STRING>) bicycle FROM store_data;
-- `::` also supported
SELECT raw:store.bicycle::STRUCT<price DOUBLE, color STRING> bicycle FROM store_data;
+------------------+
| bicycle |
+------------------+
| { |
| "price":19.95, |
| "color":"red" |
| } |
+------------------+
Pitón
Utilice la try_variant_get función (Python) para convertir:
# price is returned as a double, not a string
df_variant.select(try_variant_get(col("raw"), "$.store.bicycle.price", "double").alias("price"))
+------------------+
| price |
+------------------+
| 19.95 |
+------------------+
Use también la try_variant_get función (SQL o Python) para controlar los errores de conversión:
SQL
SELECT try_variant_get(
parse_json('{"a" : "c", "b" : 2}'),
'$.a',
'boolean'
)
Pitón
spark.range(1).select(parse_json(lit('{"a" : "c", "b" : 2}')).alias("v")).select(try_variant_get(col('v'), '$.a', 'boolean')).display()
Reglas de valores null de Variant
Utilice la función is_variant_null (SQL o Python) para determinar si el valor de variante es nulo.
SQL
Las variantes pueden contener dos tipos de valores null:
-
SQL
NULL: los valoresNULLde SQL indican que falta el valor. Estos son los mismos valoresNULLque cuando se trabaja con datos estructurados. -
Variante
NULL: los valoresNULLde la variante indican que esta contiene explícitamente un valorNULL. No son iguales que los valoresNULLde SQL, ya que el valorNULLse almacena en los datos.
SELECT
is_variant_null(parse_json(NULL)) AS sql_null,
is_variant_null(parse_json('null')) AS variant_null,
is_variant_null(parse_json('{ "field_a": null }'):field_a) AS variant_null_value,
is_variant_null(parse_json('{ "field_a": null }'):missing) AS missing_sql_value_null
+--------+------------+------------------+----------------------+
|sql_null|variant_null|variant_null_value|missing_sql_value_null|
+--------+------------+------------------+----------------------+
| false| true| true| false|
+--------+------------+------------------+----------------------+
Pitón
data = [
('null',),
(None,),
('{"field_a" : 1, "field_b" : 2}',)
]
df = spark.createDataFrame(data, ["null_data"])
df.select(parse_json(col("null_data")).alias("v")).select(is_variant_null(col("v"))).display()
+------------------+
|is_variant_null(v)|
+------------------+
| true|
+------------------+
| false|
+------------------+
| false|
+------------------+