Pular para o conteúdo principal

Consultar dados de variantes

info

Visualização

Esse recurso está em Public Preview.

VARIANT é um tipo de dado semiestruturado que armazena dados semelhantes a JSON em um formato binário autodescritivo. O tipo de dados VARIANT está disponível no Databricks Runtime 15.3 e acima.

Databricks recomenda usar VARIANT em vez de strings JSON para dados semiestruturados. Para usuários que atualmente usam strings JSON e buscam migrar, consultar Como a variante difere das strings JSON?.

Para consultar dados semiestruturados armazenados como strings JSON, consulte Consultar strings JSON.

nota

VARIANT não podem ser usadas para a chave clustering, partições ou chave Z-order. O tipo de dados VARIANT não pode ser usado para comparações, agrupamento, ordenação e operações de conjunto. Para obter uma lista completa das limitações, consulte Limitações.

Crie uma tabela com uma coluna variante

Para criar uma coluna variante, use a função parse_json (SQL ou Python).

execute o seguinte para criar uma tabela com dados altamente aninhados armazenados como VARIANT. (Esses dados são usados em outros exemplos nesta página.)

Python
# 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 em uma coluna variante

Para extrair campos de uma coluna variante, use a função variant_get (SQL ou Python) especificando o nome do campo JSON no seu caminho de extração. Os nomes dos campos sempre diferenciam maiúsculas de minúsculas.

Python
# Extract a top-level field
df_variant.select(variant_get(col("raw"), "$.owner", "string")).display()

Abreviação SQL para variant_get

A sintaxe SQL para consultar strings JSON e outros tipos de dados complexos no Databricks se aplica a dados VARIANT , incluindo os seguintes:

  • Use : para selecionar campos de nível superior.
  • Use . ou [<key>] para selecionar campos aninhados com chave nomeada.
  • Use [<index>] para selecionar valores de matrizes.
SQL
SELECT raw:owner FROM store_data
+-------+
| owner |
+-------+
| "amy" |
+-------+
SQL
-- Use backticks to escape special characters.
SELECT raw:`zip code`, raw:`fb:testid` FROM store_data
+----------+-----------+
| zip code | fb:testid |
+----------+-----------+
| "94025" | "1234" |
+----------+-----------+

Se o nome de um campo contiver um ponto (.), você deverá escapá-lo com colchetes ([ ]). Por exemplo, a consulta a seguir seleciona um campo chamado zip.code:

SQL
SELECT raw:['zip.code'] FROM store_data

Extrair campos aninhados variantes

Para extrair campos aninhados de uma coluna variante, especifique-os usando a notação de ponto ou colchetes. Os nomes dos campos sempre diferenciam maiúsculas de minúsculas.

Python
# Use dot notation
df_variant.select(variant_get(col("raw"), "$.store.bicycle", "string")).display()
Python
# Use brackets
df_variant.select(variant_get(col("raw"), "$.store['bicycle']", "string")).display()

Se um caminho não puder ser encontrado, o resultado será null do tipo VariantVal.

+-----------------+
| bicycle |
+-----------------+
| { |
| "color":"red", |
| "price":19.95 |
| } |
+-----------------+

Extraia valores de matrizes variantes

Para extrair elementos de arrays, use índices entre colchetes. Os índices são baseados em 0.

Python
# 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 |
| } | } |
+-------------------+------------------+

Se o caminho não for encontrado, ou se o índice da matriz estiver fora dos limites, o resultado será nulo.

Trabalhando com variantes em Python

Você pode extrair variantes de DataFrames do Spark para Python como VariantVal e trabalhar com elas individualmente usando os métodos toPython e toJson .

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

Gere o resultado VariantVal como uma string JSON :

Python
print(variants[0].v.toJson())
{"age":25,"name":"Alice"}

Converter um VariantVal em um objeto Python:

Python
# First element is a dictionary
print(variants[0].v.toPython()["age"])
25
Python
# Second element is a List
print(variants[1].v.toPython()[1])
electronic
Python
# Third element is an Integer
print(variants[2].v.toPython())
1

Você também pode construir VariantVal usando a função VariantVal.parseJson .

Python
# parseJson to construct VariantVal's in Python
from pyspark.sql.types import VariantVal

variant = VariantVal.parseJson('{"a": 1}')

Imprima a variante como uma string JSON :

Python
print(variant.toJson())
{"a":1}

Converta a variante em um objeto Python e imprima um valor:

Python
print(variant.toPython()["a"])
1

Retorna o esquema de uma variante.

Para retornar o esquema de uma variante, use a função schema_of_variant (SQL ou Python).

Python
# Return the schema of the variant
df_variant.select(schema_of_variant(col("raw"))).display()

Para retornar os esquemas combinados de todas as variantes em um grupo, use a função schema_of_variant_agg (SQL ou Python).

Os exemplos a seguir retornam o esquema e, em seguida, o esquema combinado para os dados de exemplo json_data.

Python

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> |
+-----------------------------------------------------------------+
Python
# 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> |
+----------------------------------------------------------------------------------------------------------------------------+

Nivelar objetos e matrizes variantes

A função geradora de valores de tabela variant_explode (SQL ou Python) pode ser usada para achatar arrays e objetos variantes.

Utilize a API DataFrame de função com valor de tabela (TVF) para expandir uma variante em várias linhas:

Python
spark.tvf.variant_explode(parse_json(lit(store_data))).display()
Python
# 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()

Regras de transmissão do tipo variante

Você pode armazenar matrizes e escalares usando o tipo VARIANT. Ao tentar converter tipos de variantes em outros tipos, as regras normais de conversão se aplicam a valores e campos individuais, com as seguintes regras adicionais.

nota

variant_get e try_variant_get pegam argumentos de tipo e seguem essas regras de conversão.

Tipo de origem

Comportamento

VOID

O resultado é um NULL do tipo VARIANT.

ARRAY<elementType>

O elementType deve ser um tipo que possa ser convertido em VARIANT.

Ao inferir o tipo com schema_of_variant ou schema_of_variant_agg, as funções retornam ao tipo VARIANT em vez do tipo STRING quando existem tipos conflitantes que não podem ser resolvidos.

Use a função try_variant_get (Python) para converter:

Python
# 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 também a função try_variant_get (SQL ou Python) para lidar com falhas de conversão:

Python
spark.range(1).select(parse_json(lit('{"a" : "c", "b" : 2}')).alias("v")).select(try_variant_get(col('v'), '$.a', 'boolean')).display()

Regras nulas variantes

Use a função is_variant_null (SQL ou Python) para determinar se o valor da variante é uma variante nula.

Python
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|
+------------------+

Recursos adicionais