Как взорвать get_json_object в Apache Spark - PullRequest
0 голосов
/ 31 октября 2018

В одном из столбцов моего информационного кадра есть следующая строка:

row1:[{"key":"foo"},{"key":"bar"},{"key":"baz"}]
row2:[{"key":"foo"},{"key":"bar"}]
row3:null
etc

Я обнаружил, что Spark имеет функцию "get_json_object". Поэтому, если я хочу использовать xpath для извлечения данных, я бы использовал:

 get_json_object($"json", s"$[0].key")

вернул бы:

"foo"
"foo"
null

но мне нужен эквивалент "взрывной" функции Spark.

Я обнаружил, что могу использовать символ "*" в моем xpath.

 get_json_object($"json", s"$[*].key")

Если вы не сделаете, как ожидалось, это создаст строку вроде:

[foo,bar,baz]
[foo,baz]

Я нашел решение в другом потоке stackoverflow,

val jsonElements = (0 until 3).map(i => get_json_object($"json", s"$$[$i].key"))


val jsonElements = .map(i => get_json_object($"json", s"$$[$i].key"))
df.select($"id",explode(array(jsonElements: _*).alias("foo")))

Это частично решает мою проблему, потому что это решение предполагает, что я знаю, какой максимальной глубины может быть мой массив. Функция "from_json" в Spark нуждается в схеме, у меня огромный сложный тип JSON, для создания схемы потребуется "бесконечность" времени.

Отказ

Я не буду использовать никакие регулярные выражения / подстроки / etc для анализа JSON. Весь смысл использования парсера таков.

Ответы [ 2 ]

0 голосов
/ 01 июня 2019

Это решение ответит на ваш вопрос, вы можете определить схему один раз, используя Spark, а затем использовать схему позже.

Apache Spark Read JSON с дополнительными столбцами

0 голосов
/ 31 октября 2018

Просто придерживаясь основ скалы, можно решить это просто. Попробуйте кейсы с опциями для решения проблемы.

Вы можете использовать любой стандартный анализатор json. Я пользуюсь liftweb.

import net.liftweb.json.{DefaultFormats, parseOpt}

case class jsonElement(key: String, value: Optional[String])
//assuming the value key always exists and value may or may not exist, 
//so making that as optional / ignore the fields if you don't really care at all

val jsonKeys = inputRdd.map(eachRow => 
  implicit val formats = DefaultFormats // hate this but deal with scala

  val parsedObject = parseOpt(eachRow).flatMap(_.extractOpt[List[jsonElement]])

  parsedObject match{
    case Some(parsedItem) => parsedItem.map(json => json.key)
    case None => List()
})

Это дает Rdd списка (ключ). Используйте фильтр (list =>! List.isEmpty), если вы хотите удалить пустые списки. Вы знаете это оттуда.

...