目录
公司有些数据是以复杂的JSON格式保存的,需要对里面有用的数据进行准确提取
使用的语言为scala
1.导入fastjson包
在pom.xml文件中的依赖模块加入
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.36</version>
</dependency>
之后就可以在类中直接导入fastjson包
import com.alibaba.fastjson.{JSON, JSONArray, JSONObject}
2.对json数据进行解析
复杂的JSON格式数据示例 如下所示
{
"count": 102,
"items": [
{
"pipeline": 1,
"dataCorporationId": null,
"form": {
"code": "B640312",
"id": "0342",
"name": "通讯费用"
}
},
{
"pipeline": 2,
"dataCorporationId": null,
"form": {
"code": "B660342",
"id": "0341",
"name": "出勤费用"
}
}]
}
比如说我们需要取code的值, 正常的json解析 包括spark对json的数据读取也很难解析出来, 所以选择了fastjson进行辅助,
具体代码如下:
package com.xhgj.bigdata.util
import com.alibaba.fastjson.{JSON, JSONArray, JSONObject}
import scala.collection.mutable.ArrayBuffer
object JsonParse {
def main(args: Array[String]): Unit = {
//读取json文件的路径,以本机的json文件作为演示
val lines: String = Source.fromFile("D:\\resopnses.json").mkString
get_code(lines)
}
def get_code(jsonstr:String) = {
//将{}的字符串解析成json
val jsonOBJ: JSONObject = JSON.parseObject(jsonstr)
//由于items的值是[]组成的需要,获取items下面的jsonobj数组,按照{}来识别的
val itemsJsonOBJArray: JSONArray = jsonOBJ.getJSONArray("items")
//获取总共有几个json数组(示例中有两个单位)
val len = itemsJsonOBJArray.length
//循环获取每个json
for (i <- 0 until len ){
//按照输入的i来获取指定下标的json
val firstjsonOBJ = itemsJsonOBJArray.getJSONObject(i)
//获取key为form的值字符串
val obj1: String = firstjsonOBJ.getString("form")
//对获取的值进行JSON解析
val formjsonOBJ = JSON.parseObject(obj1)
//获取最终索要的数据
val code = formjsonOBJ.getString("code")
println("code=" + code)
}
}
}
执行结果为
总而言之,
- 遇到{}花括号, 需要将其getString变成字符串,再解析成jsonObject
- 遇到[]方括号,需要将其解析成.getJSONArray,再取下标获取对应的JSON解析, 剩下的以此类推,再复杂的json串也能解析出来
3.将解析之后的数据保存至hive表中
由于上面获取的都是string格式, 我们需要将其转换成RDD再转换成DataFrame格式, 因为我使用的是sparksql
在生产中, 肯定取的不是一个字段, 而是多个, 则需要做额外处理:
//就在上方代码补充即可,比如还需要这几个字段
//先在for循环语句上方加入,需要返回三个字段
val arrb = new ArrayBuffer[(String, String, String)]()
//在for语句内部增加
val id = formjsonOBJ.getString("id")
val name = formjsonOBJ.getString("name")
arrb.append((code,id ,name ))
//在for语句之后增加
arrb.toArray
此时我们写的这个方法返回的是一个Array[(String, String, String)]类型, 我们就可以返回spark代码中, 将这个数据解析成RDD,再使用createDataFrame转换成DF格式, 最后使用sparksql将数据导入hive表中, 代码如下:
import com.xhgj.bigdata.util.{JsonParse, TableName}
import org.apache.spark.sql.types._
import org.apache.spark.sql.{DataFrame, Row, SparkSession}
import scala.io.Source
object TEST {
def main(args: Array[String]): Unit = {
//创建schema, 用于rdd转df
val schema = StructType(Array(
StructField("code", StringType, nullable = true),
StructField("id", StringType, nullable = true),
StructField("name", StringType, nullable = true)
))
val spark = SparkSession.builder().appName("Spark Hive DEMO").enableHiveSupport().getOrCreate()
val sc = spark.sparkContext
//读取json数据
val lines: String = Source.fromFile("D:\\result.json").mkString
//执行之前写的方法,并将返回的array数组一个个解析成RDD格式
val res = sc.parallelize(JsonParse.get_code(lines))
val resRDD = res.map(tup => Row(tup._1,tup._2,tup._3,tup._4,tup._5))
//rdd转df
val resDF: DataFrame = spark.createDataFrame(resRDD,schema)
run(resDF,spark)
sc.stop()
spark.stop()
}
//sparksql方法将数据转入hive表
def run(resDF: DataFrame,spark:SparkSession): Unit = {
resDF.createOrReplaceTempView("FEETY")
spark.sql(
s"""
|INSERT OVERWRITE TABLE MYTEST.TABLENAME
|SELECT
| *
|FROM
| FEETY
|""".stripMargin)
}
}
至此, 复杂json格式解析搞定