我正在从Spark读取一个dynamodb表,这个表在一个字段中有一个JSON字符串,在其他字段中有字符串。我能够读取JSON字段,但不能读取嵌套的JSON字段。这不是使用dataframes的查询Json列的副本。这个问题解释了如何从JSON字符串中提取列,但没有解释嵌套的JSON列。
import com.github.traviscrawford.spark.dynamodb._
val users = sqlContext.read.dynamodb("Dynamodb_table")
users.show(1)
示例数据集
|col1 | ID | field2|field3|
-------------------------------------------------------------------------------------
|{"a":[{"b":"value1","x":23},{"b":value2,"x":52}],"c":"valC"}|A1 | X1 |Y1 |
我需要从col1(JSON结构)和ID字段中提取几个字段。我能够理解如何解析JSON字段(col1)并从col1中获取字段‘c ’,就像这里解释的那样,但是不能提取嵌套字段。
我的代码:
val users = sqlContext.read.dynamodb("Dynamodb_table")
val data = users.selectExpr("get_json_object(col1, '$.c')","get_json_object(col1, '$.a')","ID")
data.show(1,false)
|a |c |ID|
---------------------------------------------------------
|[{"b":"value1","x":23},{"b":value2","x":52}...]|valC|A1|
现在,当我尝试在上面的数据帧上应用相同的get_json_object时,我得到所有的空值。
val nestedData = data.selectExpr("get_json_object(a, '$.b')","c","ID")
nestedData.show(false)
|get_json_object(a, '$.b')| c | ID|
------------------------------------
|null |valC|A1 |
我也尝试了爆炸,因为col 'a'有数组和结构。但这也不起作用,因为数据帧“data”将col/字段“a”作为字符串而不是数组返回。任何想法如何解决这个问题?
更新:我还尝试使用JSON4s和net.liftweb.json.parse进行解析。那也无济于事
case class aInfo(b: String)
case class col1(a: Option[aInfo]), c: String)
import net.liftweb.json.parse
val parseJson = udf((data: String) => {
implicit val formats = net.liftweb.json.DefaultFormats
parse(data).extract[Data]
})
val parsed = users.withColumn("parsedJSON", parseJson($"data"))
parsed.show(1)
当我使用这些解析器时,所有值都显示为空。
我的预期结果:我试图从数据集中得到一个扁平的结构
|b |x |c | ID|
--------------------
|value1|23|valC|A1 |
|value2|52|valC|A1 |
我相信所有必需的拼图都已经在这里了,所以让我们一步一步地遵循这个步骤。您的数据相当于:
val df = Seq((
"""{"a":[{"b":"value1"},{"b": "value2"}],"c":"valC"}""", "A1", "X1", "Y1"
)).toDF("col1", "ID", "field2", "field3")
Spark 提供了 json4s,它实现了与 Lift 相同的查询 API:
import org.json4s._
import org.json4s.jackson.JsonMethods._
例如,我们可以使用LINQ风格的API来定义UDF:
val getBs = udf((s: String) => for {
JString(b) <- parse(s) \ "a" \ "b"
} yield b)
如果你想提取多个字段,你当然可以扩展它。例如,如果JSON字符串有多个字段
{"a":[{"b":"value1","d":1},{"b":"value2","d":2}],"c":"valC"}
你可以:
for {
JObject(a) <- parse(s) \ "a"
JField("b", JString(b)) <- a
JField("d", JInt(d)) <- a
} yield (b, d)
这假设两个字段都存在,否则不会有匹配。要处理丢失的字段,您可能更喜欢类似XPath的表达式或提取器:
case class A(b: Option[String], d: Option[Int])
(parse(s) \ "a").extract(Seq[A])
像这样的UDF可以与爆炸
一起使用以提取字段:
val withBs = df.withColumn("b", explode(getBs($"col1")))
结果:
+--------------------+---+------+------+------+
| col1| ID|field2|field3| b|
+--------------------+---+------+------+------+
|{"a":[{"b":"value...| A1| X1| Y1|value1|
|{"a":[{"b":"value...| A1| X1| Y1|value2|
+--------------------+---+------+------+------+
您尝试使用Lift是不正确的,因为您希望<code>a。它应该是选项[Seq[aInfo]]
:
case class col1(a: Option[Seq[aInfo]], c: String)
使用这样定义的类,解析应该可以正常工作。
如果使用当前版本 (Spark 2.1.0),则 SPARK-17699 引入了一个from_json
方法,该方法需要架构:
import org.apache.spark.sql.types._
val bSchema = StructType(Seq(StructField("b", StringType, true)))
val aSchema = StructField("a", ArrayType(bSchema), true)
val cSchema = StructField("c", StringType, true)
val schema = StructType(Seq(aSchema, cSchema))
并可应用为:
import org.apache.spark.sql.functions.from_json
val parsed = df.withColumn("col1", from_json($"col1", schema))
之后,您可以使用常用符号选择字段:
parsed.select($"col1.a.b")
我的数据框中有一列包含JSON列表,但类型是字符串。我需要在此列上运行,因此首先需要将其转换为列表。我找不到太多关于这个用例的参考。 示例数据: 上面是数据的样子,字段是不固定的(索引0可能有JSON和一些字段,而索引1将有一些字段和一些其他字段)。列表中可以有更多嵌套的JSONs或一些额外的字段。我现在正在用这个- <code>“分解(拆分(regexp_replace(regexp_repla
我正在以JSON字符串的形式从数据库中获取数据: 如何从给定的JSON字符串中提取公司名称?
我正在使用ApacheJMeter发出HTTP请求。 响应格式如下: HTTP/1.1 100继续 HTTP/1.1 200 OK x-powering-by: Express access-Control-low-source:*access-Control-low-method: HEAD, POST, PUT, GET, OPTIONS, DELETE access-Control-low-
问题内容: 我正在使用select2中的multiselect元素来输入多个“标签”。当我想从元素中获取值时,我会得到如下信息(对于我在框中输入的tag1和tag2): 如何从数组中的文本中获取结果,如下所示: 而我该如何逆转这一过程呢? 问题答案: 试试这个简单的迭代。
问题内容: 我有一个包含Json的字符串。看起来像这样: 我正在尝试保留“ img_url”。我已经安装了Json.NET,并且在这里发现了类似的问题。 例如这样的事情: 在我来说,我改变到,etc..no运气 现在这是我的代码: 在提取值之前,是否必须对字符串做一些事情?谢谢! 问题答案: 不是根对象的属性-它是对象的属性: 另外的选择:
所谓字符串,指的就是字符的序列或者“串”。我们要在字符串上执行的第一个操作是提取所有字符中的一个。C++使用方括号([和])执行该操作: apstring fruit = "banana"; char letter = fruit[1]; cout << letter << endl; 表达式fruit[1]表明我们要从字符串变量fruit中取得编号为1的字符,并将结果保存在字符变量letter