学习记录:Scala解析ElasticSearch RestfulAPI返回的JSON字符串并提取内容转换成DataFrame

由于需要从返回报文里面解析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工具包,不过现在暂时就学习了这两种,第一种被废弃了,相当于就学习了一种。人们常说举一反三,学会一种,再学其他应该也不会太难。仅做记录使用,代码没注重太多细节。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值