Sparksql читать JSON с внутренним массивом - PullRequest
0 голосов
/ 24 октября 2018

Я пытаюсь прочитать JSON в набор данных (спарк 2.3.2).К сожалению, это не работает хорошо.

Вот данные, это файл json с внутренним массивом

{ "Name": "helloworld", 
  "info": { "privateInfo": [ {"salary":1200}, {"sex":"M"}],
            "house": "sky road" 
          }, 
  "otherinfo":2
}   
{ "Name": "helloworld2",
  "info": { "privateInfo": [ {"sex":"M"}],
            "house": "sky road" 
          }, 
  "otherinfo":3
}

Я использую sparksession для выбора столбцов, но у него есть некоторые проблемы:результат не сами данные, а в массиве.

val sqlDF = spark.sql("SELECT name , info.privateInfo.salary ,info.privateInfo.sex   FROM people1 ")
    sqlDF.show()

Но столбцы salary & sex находятся в массиве:

+-----------+-------+-----+
|       name| salary|  sex|
+-----------+-------+-----+
| helloworld|[1200,]|[, M]|
|helloworld2|     []|  [M]|
+-----------+-------+-----+

Как я могу получитьданные с самим типом данных?

Например

+-----------+-------+-----+
|       name| salary|  sex|
+-----------+-------+-----+
| helloworld|  1200 |  M  |
|helloworld2|none/null| M |
+-----------+-------+-----+

1 Ответ

0 голосов
/ 27 августа 2019

Короткий ответ

spark.sql("SELECT name , " +
      "element_at(filter(info.privateInfo.salary, salary -> salary is not null), 1) AS salary ," +
      "element_at(filter(info.privateInfo.sex, sex -> sex is not null), 1) AS sex" +
      "   FROM people1 ")

+-----------+------+---+
|       name|salary|sex|
+-----------+------+---+
| helloworld|  1200|  M|
|helloworld2|  null|  M|
+-----------+------+---+

Длинный ответ
Основная проблема - обнуляемость массива

root
 |-- Name: string (nullable = true)
 |-- info: struct (nullable = true)
 |    |-- house: string (nullable = true)
 |    |-- privateInfo: array (nullable = true)
 |    |    |-- element: struct (containsNull = true)
 |    |    |    |-- salary: long (nullable = true)
 |    |    |    |-- sex: string (nullable = true)
 |-- otherinfo: long (nullable = true)

Так что нам нужен способ отфильтровать нулевые значения, к счастью, искра 2.4 имеет встроенные функции высшего порядка

Первая попытка была использовать array_remove, но, к сожалению, null никогда не может быть равным null.
Этовсе еще возможно с более подробным синтаксисом

df.selectExpr("filter(info.privateInfo.salary, salary -> salary is not null)")

+------+
|salary|
+------+
|[1200]|
|    []|
+------+

Теперь нам нужен какой-то способ взорвать массив, к счастью, у нас есть функция explode!

df.selectExpr(
 "explode(filter(info.privateInfo.salary, salary -> salary is not null)) AS salary",
 "explode(filter(info.privateInfo.sex, sex -> sex is not null)) AS sex")

Boom

Exception in thread "main" org.apache.spark.sql.AnalysisException: Only one generator allowed per select clause but found 2

Поскольку мы знаем, что в массиве должно быть ровно одно значение, мы можем использовать element_at

 df.selectExpr(
      "element_at(filter(info.privateInfo.salary, salary -> salary is not null), 1) AS salary",
      "element_at(filter(info.privateInfo.sex, sex -> sex is not null), 1) AS sex")

ps не заметили, что его спросили 10 месяцев назад

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...