由于需要从返回报文里面解析JSON字符串 并提取内容,学习了下相关API用法
需要解析的JSON字符串格式如下所示:
{
"took": 13,
"timed_out": false,
"_shards": {
"total": 5,
"successful": 5,
"skipped": 0,
"failed": 0
},
"hits": {
"total": 3,
"max_score": 1.2,
"hits": [
{
"_index": "my_store",
"_type": "products",
"_id": "2",
"_score": 1.2,
"_source": {
"price": 20,
"productID": "KDKE-B-9947-#kL5"
}
},
{
"_index": "my_store",
"_type": "products",
"_id": "4",
"_score": 1.2,
"_source": {
"price": 30,
"productID": "QQPX-R-3956-#aD8"
}
}
]
}
}
具体代码如下:
①使用Scala原生包(import scala.util.parsing.json._)里面的API--*不是很推荐*,这个API在Scala 2.11.0之后被移除了,如果使用Scala 2.11.0及之后的版本会提示API已被废弃,虽然能运行但是Maven Build会失败,只能本地IDE跑。
// 此部分代码是从main方法里面提取的代码片段,不是完整代码
// 此处是从ElasticSearch请求查询数据,返回内容response就是JSON字符串,
// 不过里面有多层,需要进行解析才能拿到自己想要的那部分
var response: String = Utils.postBody(
url = s"${esProps.getProperty(s"es.rest")}/${indexName}/_search",
body = queryString,
encoding = "utf-8",
printResponse = true)
// 进行初步解析,返回内容为Option[Any]
val jsonS = JSON.parseFull(response)
// 调用自定义的regJson方法(在下面贴出代码)将初步解析内容转换成Map[String, Any]格式内容
val first = regJson(jsonS)
// 取得最外层hits内容并转换成Map[String, Any]格式内容
val second = regJson(first.get("hits"))
var strList = List.empty[String]
// 取得内层hits内容并转为List格式
val list = second.get("hits").get.asInstanceOf[List[Any]]
// 遍历list取出里面的_source内容并拼接成JSON字符串
for (i <- list) {
// 取得_source内容
val source = i.asInstanceOf[Map[String, Any]].get("_source").get
// 将_source内容转换成字符串格式
val jsonString: String = JSONObject.apply(source.asInstanceOf[Map[String, Any]]).toString();
// 拼接到strList中
strList = strList :+ jsonString
}
debug("strList:" + strList)
// 将strList转换成DataFrame
val rddData: RDD[String] = spark.sparkContext.parallelize(strList)
val dataFromEsDf = spark.read.json(rddData)
上面代码片段使用到的regJson方法
def regJson(json:Option[Any]) = json match {
case Some(map: Map[String, Any]) => map
}
②使用json-smart,可以使用Maven添加依赖或者添加依赖包
代码如下所示:
// 此部分代码是从main方法里面提取的代码片段,不是完整代码
// 此处是从ElasticSearch请求查询数据,返回内容response就是JSON字符串,
// 不过里面有多层,需要进行解析才能拿到自己想要的那部分
import net.minidev.json.parser.JSONParser
import net.minidev.json.{JSONArray, JSONObject}
......
var response: String = Utils.postBody(
url = s"${esProps.getProperty("es.rest")}/bi_enterprise/_search?scroll=1m",
body = "{\"query\": {\"match_all\": {}},\"size\": 10000,\"sort\": [\"_doc\"]}",
encoding = "utf-8",
printResponse = true)
// 设定解析模式为-1,这个模式最快
// smart mode, fastest parsing mode. accept lots of non standard json syntax
val jsonParser = new JSONParser(-1)
// 将内容解析成JSONObject
val jsonObj: JSONObject = jsonParser.parse(response).asInstanceOf[JSONObject]
// 取得外层hits内容并转换成字符串
val hits = jsonObj.get("hits").toString
// 将外层hits内容解析成JSONObject
val jsonObjHits: JSONObject = jsonParser.parse(hits).asInstanceOf[JSONObject]
// 取得内层hits内容并转换成字符串
val hitsArray = jsonObjHits.get("hits").toString
// 将内层hits内容解析成JSONArray
val jsonObjSource: JSONArray = jsonParser.parse(hitsArray).asInstanceOf[JSONArray]
hitSize = jsonObjSource.size()
var strList = List.empty[String]
// 将JSONArray转换成Array并进行遍历
var array = jsonObjSource.toArray()
for (i <- 0 to array.length - 1) {
val Obj: JSONObject = array(i).asInstanceOf[JSONObject]
// 取得_source内容并拼接到strList
strList = strList :+ Obj.get("_source").toString
}
// 转换成DataFrame
val rddData: RDD[String] = spark.sparkContext.parallelize(strList)
val resultDF = spark.read.json(rddData)
虽然还有其他的解析JSON工具包,不过现在暂时就学习了这两种,第一种被废弃了,相当于就学习了一种。人们常说举一反三,学会一种,再学其他应该也不会太难。仅做记录使用,代码没注重太多细节。