#apache-spark #pyspark #apache-spark-sql #azure-databricks
Вопрос:
Входные данные —
{"driverId":1,"driverRef":"hamilton","number":44,"code":"HAM","name":{"forename":"Lewis","surname":"Hamilton"},"dob":"1985-01-07","nationality":"British","url":"http://en.wikipedia.org/wiki/Lewis_Hamilton"}
{"driverId":2,"driverRef":"heidfeld","number":"\N","code":"HEI","name":{"forename":"Nick","surname":"Heidfeld"},"dob":"1977-05-10","nationality":"German","url":"http://en.wikipedia.org/wiki/Nick_Heidfeld"}
{"driverId":3,"driverRef":"rosberg","number":6,"code":"ROS","name":{"forename":"Nico","surname":"Rosberg"},"dob":"1985-06-27","nationality":"German","url":"http://en.wikipedia.org/wiki/Nico_Rosberg"}
{"driverId":4,"driverRef":"alonso","number":14,"code":"ALO","name":{"forename":"Fernando","surname":"Alonso"},"dob":"1981-07-29","nationality":"Spanish","url":"http://en.wikipedia.org/wiki/Fernando_Alonso"}
{"driverId":5,"driverRef":"kovalainen","number":"\N","code":"KOV","name":{"forename":"Heikki","surname":"Kovalainen"},"dob":"1981-10-19","nationality":"Finnish","url":"http://en.wikipedia.org/wiki/Heikki_Kovalainen"}
{"driverId":6,"driverRef":"nakajima","number":"\N","code":"NAK","name":{"forename":"Kazuki","surname":"Nakajima"},"dob":"1985-01-11","nationality":"Japanese","url":"http://en.wikipedia.org/wiki/Kazuki_Nakajima"}
{"driverId":7,"driverRef":"bourdais","number":"\N","code":"BOU","name":{"forename":"Sébastien","surname":"Bourdais"},"dob":"1979-02-28","nationality":"French","url":"http://en.wikipedia.org/wiki/Sébastien_Bourdais"}
После считывания этих данных в фрейм данных spark при отображении этого df я смог увидеть, что вся строка для идентификатора драйвера 2,5,6,7 равна НУЛЮ. Я мог видеть, что значение номера столбца равно НУЛЮ для этого идентификатора драйвера.
Вот мой код. Здесь есть какие-нибудь ошибки?
from pyspark.sql.types import StructType, StructField, IntegerType, StringType, DateType
name_field = StructType(fields =[
StructField("forename", StringType(), True),
StructField("surname", StringType(), True)
])
driver_schema = StructType(fields =[
StructField("driverId", IntegerType(), False),
StructField("driverRef", StringType(), True),
StructField("number", IntegerType(), True),
StructField("code", StringType(), True),
StructField("name", name_field),
StructField("dob", DateType(), True),
StructField("nationality", StringType(),True),
StructField("url", StringType(), True)
])
driver_df = spark.read
.schema(driver_schema)
.json('dbfs:/mnt/databrickslearnf1azure/raw/drivers.json')
driver_df.printSchema()
root
|-- driverId: integer (nullable = true)
|-- driverRef: string (nullable = true)
|-- number: integer (nullable = true)
|-- code: string (nullable = true)
|-- name: struct (nullable = true)
| |-- forename: string (nullable = true)
| |-- surname: string (nullable = true)
|-- dob: date (nullable = true)
|-- nationality: string (nullable = true)
|-- url: string (nullable = true)
display(driver_df)
Комментарии:
2. вы должны изменить тип данных числового столбца на строку в явной схеме, которую вы создаете, потому что то, что вы называете null, на самом деле не является null, это какое-то строковое значение, и spark не может проанализировать его как целое число, поэтому он показывает все столбцы как null. если вы хотите, чтобы тип данных был целочисленным, вы можете преобразовать его в целое число после его прочтения.
Ответ №1:
Вы можете изменить свою начальную схему следующим образом, предполагая, что число имеет тип string.
from pyspark.sql.types import StructType, StructField, IntegerType, StringType, DateType
name_field = StructType(fields =[
StructField("forename", StringType(), True),
StructField("surname", StringType(), True)
])
driver_schema = StructType(fields =[
StructField("driverId", IntegerType(), False),
StructField("driverRef", StringType(), True),
StructField("number", StringType(), True),
StructField("code", StringType(), True),
StructField("name", name_field),
StructField("dob", DateType(), True),
StructField("nationality", StringType(),True),
StructField("url", StringType(), True)
])
затем вы можете прочитать данные из файла json, используя тот же код, который вы используете, следующим образом:
driver_df = spark.read
.schema(driver_schema)
.json('dbfs:/mnt/databrickslearnf1azure/raw/drivers.json')
driver_df.printSchema()
После того, как вы прочитали данные, вы можете применить логику для преобразования «N» в null, а затем изменить тип данных столбца со строки на целое число, как показано ниже :
from pyspark.sql.functions import *
df = driver_df.withColumn("number", when(driver_df.number=="\N","null").otherwise(driver_df.number))
finaldf = df.withColumn("number",df.number.cast(IntegerType()))
finaldf.printSchema()
Теперь, если вы выполняете отображение или показ в кадре данных, вы можете увидеть вывод, как показано ниже :
Ответ №2:
Вы видите это, потому что, согласно официальным документам databricks: Причина
Spark 3.0 и выше (Databricks Runtime 7.3 LTS и выше) не может анализировать массивы JSON как структуры. Вы должны передать схему как тип массива, а не как тип структуры.
Решение: Передайте схему как тип массива, а не как тип структуры.
driver_schema = ArrayType(StructType(fields =[
StructField("driverId", IntegerType(), False),
StructField("driverRef", StringType(), True),
StructField("number", IntegerType(), True),
StructField("code", StringType(), True),
StructField("name", name_field),
StructField("dob", DateType(), True),
StructField("nationality", StringType(),True),
StructField("url", StringType(), True)
]))