Spark Row to JSON
我想从 Spark v.1.6(使用 scala)数据帧创建 JSON。我知道有做
的简单解决方案
但是,我的问题看起来有点不同。例如,考虑具有以下列的数据框:
1 2 3 4 | | A | B | C1 | C2 | C3 | ------------------------------------------- | 1 | test | ab | 22 | TRUE | | 2 | mytest | gh | 17 | FALSE | |
我希望最后有一个带有
的数据框
1 2 3 4 | | A | B | C | ---------------------------------------------------------------- | 1 | test | {"c1" :"ab","c2" : 22,"c3" : TRUE } | | 2 | mytest | {"c1" :"gh","c2" : 17,"c3" : FALSE } | |
其中 C 是包含
至于我需要这个的原因:我正在使用 Protobuf 来发送结果。不幸的是,我的数据框有时包含比预期更多的列,我仍然会通过 Protobuf 发送这些列,但我不想在定义中指定所有列。
我怎样才能做到这一点?
Spark 2.1 应该对这个用例提供原生支持(参见 #15354)。
1 2 |
我用这个命令解决to_json问题:
1 | output_df = (df.select(to_json(struct(col("*"))).alias("content"))) |
这里没有 JSON 解析器,它会适应你的模式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | import org.apache.spark.sql.functions.{col, concat, concat_ws, lit} df.select( col(df.columns(0)), col(df.columns(1)), concat( lit("{"), concat_ws(",",df.dtypes.slice(2, df.dtypes.length).map(dt => { val c = dt._1; val t = dt._2; concat( lit(""" + c +"":" + (if (t =="StringType")"""; else"") ), col(c), lit(if(t=="StringType")"""; else"") ) }):_*), lit("}") ) as"C" ).collect() |
首先让我们将 C 转换为
1 |
这个结构可以像以前一样使用
1 2 3 4 | dfStruct.toJSON.collect // Array[String] = Array( // {"A":1,"B":"test","C":{"C1":"ab","C2":22,"C3":true}}, // {"A":2,"B":"mytest","C":{"C1":"gh","C2":17,"C3":false}}) |
我不知道任何可以转换单个列的内置方法,但您可以单独转换它和
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | case class C(C1: String, C2: Int, C3: Boolean) object CJsonizer { import org.json4s._ import org.json4s.JsonDSL._ import org.json4s.jackson.Serialization import org.json4s.jackson.Serialization.write implicit val formats = Serialization.formats(org.json4s.NoTypeHints) def toJSON(c1: String, c2: Int, c3: Boolean) = write(C(c1, c2, c3)) } val cToJSON = udf((c1: String, c2: Int, c3: Boolean) => CJsonizer.toJSON(c1, c2, c3)) df.withColumn("c_json", cToJSON($"C1", $"C2", $"C3")) |