如何在Spark 2 Scala中将Row转换为json

时间:2017-01-11 22:28:23

标签: json scala apache-spark json4s

有没有一种简单的方法将给定的Row对象转换为json?

发现这有关将整个Dataframe转换为json输出: Spark Row to JSON

但我只想将一行转换为json。 这是我想要做的伪代码。

更准确地说,我在数据帧中读取json作为输入。 我正在生成一个主要基于列的新输出,但是有一个json字段用于所有不适合列的信息。

我的问题是什么是编写此函数的最简单方法:convertRowToJson()

def convertRowToJson(row: Row): String = ???

def transformVenueTry(row: Row): Try[Venue] = {
  Try({
    val name = row.getString(row.fieldIndex("name"))
    val metadataRow = row.getStruct(row.fieldIndex("meta"))
    val score: Double = calcScore(row)
    val combinedRow: Row = metadataRow ++ ("score" -> score)
    val jsonString: String = convertRowToJson(combinedRow)
    Venue(name = name, json = jsonString)
  })
}

Psidom的解决方案:

def convertRowToJSON(row: Row): String = {
    val m = row.getValuesMap(row.schema.fieldNames)
    JSONObject(m).toString()
}

仅当Row只有一个级别而不是嵌套Row时才有效。这是架构:

StructType(
    StructField(indicator,StringType,true),   
    StructField(range,
    StructType(
        StructField(currency_code,StringType,true),
        StructField(maxrate,LongType,true), 
        StructField(minrate,LongType,true)),true))

还尝试了Artem的建议,但是没有编译:

def row2DataFrame(row: Row, sqlContext: SQLContext): DataFrame = {
  val sparkContext = sqlContext.sparkContext
  import sparkContext._
  import sqlContext.implicits._
  import sqlContext._
  val rowRDD: RDD[Row] = sqlContext.sparkContext.makeRDD(row :: Nil)
  val dataFrame = rowRDD.toDF() //XXX does not compile
  dataFrame
}

8 个答案:

答案 0 :(得分:15)

您可以使用getValuesMap将行对象转换为Map,然后将其转换为JSON:

import scala.util.parsing.json.JSONObject
import org.apache.spark.sql._

val df = Seq((1,2,3),(2,3,4)).toDF("A", "B", "C")    
val row = df.first()          // this is an example row object

def convertRowToJSON(row: Row): String = {
    val m = row.getValuesMap(row.schema.fieldNames)
    JSONObject(m).toString()
}

convertRowToJSON(row)
// res46: String = {"A" : 1, "B" : 2, "C" : 3}

答案 1 :(得分:3)

我需要读取json输入并生成json输出。 大多数字段都是单独处理的,但只需要保留一些json子对象。

当Spark读取数据帧时,它会将记录转换为行。 Row是一个类似json的结构。这可以转换并写入json。

但我需要将一些子json结构输出到字符串以用作新字段。

这可以这样做:

dataFrameWithJsonField = dataFrame.withColumn("address_json", to_json($"location.address"))

location.address是传入的基于json的数据帧的子json对象的路径。 address_json是转换为json的字符串版本的对象的列名。

to_json在Spark 2.1中实现。

如果使用json4s生成输出json,则应将address_json解析为AST表示,否则输出json将对address_json部分进行转义。

答案 2 :(得分:1)

基本上,您可以拥有一个只包含一行的数据框。因此,您可以尝试过滤初始数据帧,然后将其解析为json。

答案 3 :(得分:1)

JSon有架构,但Row没有架构,所以你需要在Row&amp ;;上应用架构。转换为JSon。这是你如何做到的。

import org.apache.spark.sql.Row
import org.apache.spark.sql.types._

def convertRowToJson(row: Row): String = {

  val schema = StructType(
      StructField("name", StringType, true) ::
      StructField("meta", StringType, false) ::  Nil)

      return sqlContext.applySchema(row, schema).toJSON
}

答案 4 :(得分:1)

注意scala类scala.util.parsing.json.JSONObject已弃用,不支持空值。

@deprecated("此课程将被删除。"," 2.11.0")

" JSONFormat.defaultFormat不处理空值"

https://issues.scala-lang.org/browse/SI-5092

答案 5 :(得分:0)

我结合了以下建议:Artem,KiranM和Psidom。做了很多跟踪和错误,并提出了我为嵌套结构测试的解决方案:

def row2Json(row: Row, sqlContext: SQLContext): String = {
  import sqlContext.implicits
  val rowRDD: RDD[Row] = sqlContext.sparkContext.makeRDD(row :: Nil)
  val dataframe = sqlContext.createDataFrame(rowRDD, row.schema)
  dataframe.toJSON.first
}

此解决方案有效,但仅限于在驱动程序模式下运行。

答案 6 :(得分:0)

我有同样的问题,我有规范模式的镶木地板文件(没有数组),我只想获得json事件。我做了如下,它似乎工作得很好(Spark 2.1):

{
  "name": "myproj-util",
  "version": "0.1.0"
}

答案 7 :(得分:0)

如果要遍历数据框,则可以将数据框直接转换为带有json对象的新数据框,然后对其进行迭代

val df_json = df.toJSON