Короткий ответ
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 месяцев назад