Kommentar
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Den här artikeln beskriver hur du kan fråga och transformera halvstrukturerade data som lagras som VARIANT. Datatypen VARIANT är tillgänglig i Databricks Runtime 15.4 och senare.
Azure Databricks rekommenderar att du använder VARIANT över JSON-strängar för halvstrukturerade data. För användare som för närvarande använder JSON-strängar som vill migrera, se Hur skiljer sig varianten från JSON-strängar?.
Information om hur du kör frågor mot halvstrukturerade data som lagras som JSON-strängar finns i Fråga efter JSON-strängar.
Kommentar
VARIANT kolumner kan inte användas för klustring av nycklar, partitioner eller Z-ordernycklar. Den VARIANT datatypen kan inte användas för jämförelser, gruppering, ordning och uppsättningsåtgärder. En fullständig lista över begränsningar finns i Begränsningar.
Skapa en tabell med en variantkolumn
Om du vill skapa en variantkolumn använder du parse_json funktionen (SQL eller Python).
Kör följande för att skapa en tabell med mycket kapslade data som lagras som VARIANT. (Dessa data används i andra exempel på den här sidan.)
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")
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
Frågefält i en variantkolumn
Om du vill extrahera fält från en variantkolumn använder du variant_get funktionen (SQL eller Python) som anger namnet på JSON-fältet i din extraheringssökväg. Fältnamn är alltid skiftlägeskänsliga.
python
# Extract a top-level field
df_variant.select(variant_get(col("raw"), "$.owner", "string")).display()
SQL
-- Extract a top-level field
SELECT variant_get(store_data.raw, '$.owner') AS owner FROM store_data
Du kan också använda SQL-syntax för att fråga efter fält i en variantkolumn. Se SQL-förkortning för variant_get.
SQL-förkortning för variant_get
SQL-syntaxen för att fråga efter JSON-strängar och andra komplexa datatyper i Azure Databricks gäller för VARIANT data, inklusive följande:
- Använd
:för att välja fält på den översta nivån. - Använd
.eller[<key>]för att välja kapslade fält med namngivna nycklar. - Använd
[<index>]för att välja värden från matriser.
SELECT raw:owner FROM store_data
+-------+
| owner |
+-------+
| "amy" |
+-------+
-- Enclose a field name that contains special characters in single quotes inside square brackets.
SELECT raw:['zip code'], raw:['fb:testid'] FROM store_data
+----------+-----------+
| zip code | fb:testid |
+----------+-----------+
| "94025" | "1234" |
+----------+-----------+
Syntaxen ['<field>'] undflyr specialtecken i ett fältnamn, inklusive blanksteg, punkter (.), kolon (:) och hakparenteser ([ ]). Azure Databricks rekommenderar den här syntaxen för varje fältnamn som innehåller ett specialtecken. Använd till exempel raw:['zip.code'] för att välja ett fält med namnet zip.code, eller raw:['A[1]'] för att välja ett fält med namnet A[1].
Backticks tar också bort fältnamn som innehåller blanksteg eller kolon, men de tar inte bort punkter eller hakparenteser. Ett fältnamn som innehåller en punkt eller hakparenteser ger NULL när det omges av bakåtvända apostrofer, så använd syntaxen ['<field>'] för sådana namn.
Om du vill extrahera fält som innehåller specialtecken i PySpark använder du samma hakparentessyntax i extraheringssökvägen variant_get :
# Escape special characters in the extraction path
df_variant.select(variant_get(col("raw"), "$['zip.code']", "string"))
df_variant.select(variant_get(col("raw"), "$['A[1]']", "string"))
Extrahera kapslade variantfält
Om du vill extrahera kapslade fält från en variantkolumn anger du dem med hjälp av punkt notation eller hakparenteser. Fältnamn är alltid skiftlägeskänsliga.
python
# 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()
Om det inte går att hitta en sökväg är null resultatet av typen VariantVal.
SQL
-- Use dot notation
SELECT raw:store.bicycle FROM store_data
-- Use brackets
SELECT raw:store['bicycle'] FROM store_data
Om det inte går att hitta en sökväg är NULL resultatet av typen VARIANT.
+-----------------+
| bicycle |
+-----------------+
| { |
| "color":"red", |
| "price":19.95 |
| } |
+-----------------+
Extrahera värden från variantmatriser
För att extrahera element från matriser, använd indexering med hakparenteser. Index är 0-baserade.
python
# Index elements
df_variant.select((variant_get(col("raw"), "$.store.fruit[0]", "string")),(variant_get(col("raw"), "$.store.fruit[1]", "string"))).display()
SQL
-- Index elements
SELECT raw:store.fruit[0], raw:store.fruit[1] FROM store_data
+-------------------+------------------+
| fruit | fruit |
+-------------------+------------------+
| { | { |
| "type":"apple", | "type":"pear", |
| "weight":8 | "weight":9 |
| } | } |
+-------------------+------------------+
Om sökvägen inte kan hittas, eller om matrisindexet ligger utanför gränserna, är resultatet null.
Arbeta med varianter i Python
Du kan extrahera varianter från Spark DataFrames till Python som VariantVal och arbeta med dem individuellt med metoderna toPython och 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()
VariantVal Mata ut som en JSON-sträng:
print(variants[0].v.toJson())
{"age":25,"name":"Alice"}
Konvertera ett VariantVal till ett Python-objekt:
# 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
Du kan också skapa VariantVal med hjälp av VariantVal.parseJson funktionen.
# parseJson to construct VariantVal's in Python
from pyspark.sql.types import VariantVal
variant = VariantVal.parseJson('{"a": 1}')
Skriv ut varianten som en JSON-sträng:
print(variant.toJson())
{"a":1}
Konvertera varianten till ett Python-objekt och skriv ut ett värde:
print(variant.toPython()["a"])
1
Returnera schemat för en variant
Om du vill returnera schemat för en variant använder du schema_of_variant funktionen (SQL eller Python).
python
# Return the schema of the variant
df_variant.select(schema_of_variant(col("raw"))).display()
SQL
-- Return the schema of the variant
SELECT schema_of_variant(raw) FROM store_data;
Om du vill returnera kombinerade scheman för alla varianter i en grupp använder du schema_of_variant_agg funktionen (SQL eller Python).
Följande exempel returnerar schemat och sedan det kombinerade schemat för exempeldata 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()
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;
+-----------------------------------------------------------------+
| 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()
SQL
-- Return the combined schema
SELECT schema_of_variant_agg(parse_json(json)) FROM json_data;
+----------------------------------------------------------------------------------------------------------------------------+
| schema_of_variant(v) |
+----------------------------------------------------------------------------------------------------------------------------+
| OBJECT<age: BIGINT, department: STRING, id: BIGINT, in_stock: BOOLEAN, name: STRING, price: DECIMAL(5,1), product: STRING> |
+----------------------------------------------------------------------------------------------------------------------------+
Platta ut variantobjekt och matriser
Generatorfunktionen variant_explode för tabellvärde (SQL eller Python) kan användas för att platta ut variantmatriser och objekt.
python
Använd table-valued function (TVF) DataFrame API för att expandera en variant till flera rader.
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()
SQL
Eftersom variant_explode är en generatorfunktion använder du den som en del av FROM-satsen i stället för i listan SELECT, som i följande exempel:
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]);
Regler för gjutning av varianttyp
Du kan lagra matriser och skalärer med hjälp av VARIANT typen . När du försöker omvandla varianttyper till andra typer gäller normala gjutningsregler för enskilda värden och fält, med följande ytterligare regler.
Kommentar
variant_get och try_variant_get ta typargument och följa dessa regler för gjutning.
| Typ av källa | Funktionssätt |
|---|---|
VOID |
Resultatet är av NULL typen VARIANT. |
ARRAY<elementType> |
elementType måste vara en typ som kan konverteras till VARIANT. |
När du härleder typen med schema_of_variant eller schema_of_variant_aggåtergår funktionerna till typen i stället VARIANT för STRING typ när det finns motstridiga typer som inte kan lösas.
python
try_variant_get Använd funktionen (Python) för att casta:
# 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 |
+------------------+
SQL
Använd try_variant_get-funktionen (SQL) för att omvandla:
-- 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 |
+------------------+
Du kan också använda :: eller cast för att omvandla värden till datatyper som stöds:
-- 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" |
| } |
+------------------+
Använd också try_variant_get-funktionen (SQL eller Python) för att hantera kastfel.
python
spark.range(1).select(parse_json(lit('{"a" : "c", "b" : 2}')).alias("v")).select(try_variant_get(col('v'), '$.a', 'boolean')).display()
SQL
SELECT try_variant_get(
parse_json('{"a" : "c", "b" : 2}'),
'$.a',
'boolean'
)
Variant null-regler
is_variant_null Använd funktionen (SQL eller Python) för att avgöra om variantvärdet är en variant null.
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|
+------------------+
SQL
Varianter kan innehålla två typer av null:er:
-
SQL
NULL: SQLNULLs anger att värdet saknas. Dessa är sammaNULLsom vid hantering av strukturerade data. -
Variant
NULL: VariantNULLs anger att varianten uttryckligen innehåller ettNULLvärde. Dessa är inte samma som SQLNULLeftersomNULLvärdet lagras i data.
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|
+--------+------------+------------------+----------------------+
Ytterligare resurser
-
Hur skiljer sig varianten från JSON-strängar?: För en jämförelse av
VARIANToch JSON-strängar, inklusive migreringsvägledning för användare som flyttar från JSON-stränglagring. -
Stöd för varianttyp för Apache Iceberg och Delta Lake: För en fullständig lista över
VARIANTbegränsningar och Delta-specifika beteenden.