Общий способ анализа Spark DataFrame в JSON Object / Array с использованием Spray JSON - PullRequest
0 голосов
/ 10 октября 2019

Я пытаюсь найти общий способ (без использования конкретного класса case в Scala) для анализа Spark DataFrame в JSON Object / Array с использованием Spray JSON или любой другой библиотеки.

Я пытался приблизиться к этому с помощью spray-json, и мой текущий код выглядит примерно так

import spray.json._
import spray.json.DefaultJsonProtocol._

val list = sc.parallelize(List(("a1","b1","c1","d1"),("a2","b2","c2","d2"))).toDF

list.show
+---+---+---+---+                                                               
| _1| _2| _3| _4|
+---+---+---+---+
| a1| b1| c1| d1|
| a2| b2| c2| d2|
+---+---+---+---+

val json = list.toJSON.collect.toJson.prettyPrint

println(json)

Токовый выход:

["{\"_1\":\"a1\",\"_2\":\"b1\",\"_3\":\"c1\",\"_4\":\"d1\"}", "{\"_1\":\"a2\",\"_2\":\"b2\",\"_3\":\"c2\",\"_4\":\"d2\"}"]

Ожидаемый вывод:

[{
    "_1": "a1",
    "_2": "b1",
    "_3": "c1",
    "_4": "d1"
}, {
    "_1": "a2",
    "_2": "b2",
    "_3": "c2",
    "_4": "d2"
}]

Пожалуйста, предложите, как получить ожидаемый результат в требуемом формате, не используя "конкретный класс случая scala". Либо с помощью spray-json, либо из любой другой библиотеки.

Ответы [ 2 ]

1 голос
/ 11 октября 2019

Я получил помощь от предыдущего поста . Если бы вы посмотрели здесь, я думаю, вы бы получили свой ответ.

Вы правы на полпути. Добавив пользовательский код форматирования, вы сможете получить выходные данные в нужном формате.

import scala.util.parsing.json.JSON
import scala.util.parsing.json.JSONArray   
import scala.util.parsing.json.JSONFormat   
import scala.util.parsing.json.JSONObject   
import scala.util.parsing.json.JSONType

// Thanks to Senia for providing this in her solution
def format(t: Any, i: Int = 0): String = t match {
  case o: JSONObject =>
    o.obj.map{ case (k, v) =>
      "  "*(i+1) + JSONFormat.defaultFormatter(k) + ": " + format(v, i+1)
    }.mkString("{\n", ",\n", "\n" + "  "*i + "}")

  case a: JSONArray =>
    a.list.map{
      e => "  "*(i+1) + format(e, i+1)
    }.mkString("[\n", ",\n", "\n" + "  "*i + "]")

  case _ => JSONFormat defaultFormatter t
}

val list = sc.parallelize(List(("a1","b1","c1","d1"),("a2","b2","c2","d2"))).toDF

// Create array
val jsonArray = list.toJSON.collect()

val jsonFormattedArray = jsonArray.map(j => format(JSON.parseRaw(j).get))

res1: Array[String] =
Array({
  "_1": "a1",
  "_2": "b1",
  "_3": "c1",
  "_4": "d1"
}, {
  "_1": "a2",
  "_2": "b2",
  "_3": "c2",
  "_4": "d2"
})

Преобразование отформатированного Json в строку

scala> jsonFormattedArray.toList.mkString(",")

res2: String =
{
  "_1": "a1",
  "_2": "b1",
  "_3": "c1",
  "_4": "d1"
},{
  "_1": "a2",
  "_2": "b2",
  "_3": "c2",
  "_4": "d2"
}
0 голосов
/ 11 октября 2019

Попробовав различные подходы с использованием различных библиотек, я, наконец, остановился на следующем простом подходе.

val list = sc.parallelize(List(("a1","b1","c1","d1"),("a2","b2","c2","d2"))).toDF

val jsonArray = list.toJSON.collect
/*jsonArray: Array[String] = Array({"_1":"a1","_2":"b1","_3":"c1","_4":"d1"}, {"_1":"a2","_2":"b2","_3":"c2","_4":"d2"})*/

val finalOutput = jsonArray.mkString("[", ",", "]")

/*finalOutput: String = [{"_1":"a2","_2":"b2","_3":"c2","_4":"d2"},{"_1":"a1","_2":"b1","_3":"c1","_4":"d1"}]*/

В этом подходе нам не нужно использовать spray-JSON или любую другую библиотеку.

Особая благодарность @Aman Sehgal. Его ответ помог мне найти это оптимальное решение.

Примечание. Мне еще предстоит проанализировать производительность этого подхода с использованием большого DF, но с некоторыми базовыми тестами производительности он выглядит одинаково быстро. "ToJson. prettyPrint "of" spray-json ".

...