利用spark sql生成json格式的列

导读:

利用spark sql函数,将多行数据转化为一行,并且将group by后的某些字段拼接成为json字符串。

最终将数据存入redis中。

假设hive表原始数据如下:

        day          area     playNum
        20200808    "南京"     888
        20200808    "苏州"     999
        20200809    "常州"     999

读取原始数据,声明临时表,编写sql,按day字段,将多行转为一行。

val ss: SparkSession = SparkSession.builder().config(new SparkConf()).enableHiveSupport().getOrCreate()
ss.read.load("/Users/xxxx/tmp/areaTable").createTempView("tmp")
val df=ss.sql("select concat('areaDistribution_',day) as key,cast(collect_list(concat('{\"area\"',':\"',area ,'\",','\"playNum\"',':',playNum,'}')) as string) as value from tmp group by day")

sql代码中,通过"group by day",将同一日的数据进行汇总,然后使用concat函数做json字符的拼接操作,使用collect_list函数将多个子json字符串合并成为字符串json的数组,最后通过cast函数将数组转化为string,满足最终要求。

df的数据类型如下:

root
 |-- key: string (nullable = true)
 |-- value: string (nullable = true)

df的内容如下:

+-------------------------+--------------------------------------------------------------+
|key                      |value                                                         |
+-------------------------+--------------------------------------------------------------+
|areaDistribution_20200808|[{"area":"南京","playNum":888}, {"area":"苏州","playNum":999}]|
|areaDistribution_20200809|[{"area":"南京","playNum":999}]                               |
+-------------------------+--------------------------------------------------------------+

此时,value字段是一个json格式的字符串。

通过在原始dataframe的每一个partition中声明redis的连接,注意不是每条记录声明一个连接。

//默认200个partition,按现在程序的数据量太多,没有必要初始化200个redis连接,故而调整下
    val partitionNum=if(df.rdd.getNumPartitions>6) 6 else df.rdd.getNumPartitions
    df.repartition(partitionNum).foreachPartition(p=>{
      var redis:Jedis=null
      try {
        redis = getRedis()
        var count=0
        val arrayBuffer : ArrayBuffer[String] = new ArrayBuffer[String]()
        p.foreach(e => {
          count=count+1
          val key= e.getAs[String]("key")
          val value= e.getAs[String]("value")
          //println("value:"+value)
          arrayBuffer.+=:(value.toString)
          arrayBuffer.+=:(key)
          if(count%1000==0){
            redis.mset(arrayBuffer: _*)
            arrayBuffer.clear()
          }
        })
        //清理末尾
        if(arrayBuffer.size>0){
          //println(arrayBuffer.toString())
          redis.mset(arrayBuffer: _*)
        }
      }catch {
        case e:Exception=>println(e.toString)
      }finally {
        redis.close()
      }
    })

一个简单函数,用于返回redis连接给dataframe的每一个partition调用:

 //获得redis资源
  def getRedis(): Jedis = {
    val host = "10.10.01.01"
    val port = "6379".toInt
    val db = "4".toInt
    println("--------redisInfo:",host,port,db)
    val config: JedisPoolConfig = new JedisPoolConfig()
    val metadataPool: JedisPool = new JedisPool(config, host, port, 100 * Protocol.DEFAULT_TIMEOUT, null, db)
    val redis = metadataPool.getResource
    redis
  }

 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Spark中创建对象生成JSON数组的方法如下: 首先,我们需要创建一个包含要换为JSON的对象的RDD。然后,我们可以使用`map`函数将每个对象换为JSON字符串。最后,我们可以使用`collect`函数将RDD中的所有JSON字符串收集到一个数组中。 以下是一个示例代码: ```scala import org.apache.spark.sql.Row import org.apache.spark.sql.SparkSession import org.apache.spark.sql.types.{ArrayType, StringType, StructField, StructType} // 创建SparkSession val spark = SparkSession.builder().appName("Spark JSON Array").getOrCreate() // 创建要换为JSON的对象的RDD val data = spark.sparkContext.parallelize(Seq( Row("John", 25), Row("Alice", 30), Row("Bob", 35) )) // 创建Schema,定义对象的结构 val schema = StructType(Seq( StructField("name", StringType, nullable = false), StructField("age", StringType, nullable = false) )) // 将RDD换为DataFrame val df = spark.createDataFrame(data, schema) // 将每个对象换为JSON字符串 val jsonArray = df.rdd.map(row => { val name = row.getAs[String]("name") val age = row.getAs[String]("age") s"""{"name": "$name", "age": "$age"}""" }).collect() // 打印生成JSON数组 jsonArray.foreach(println) ``` 这段代码将创建一个包含三个对象的RDD,并将它们换为具有"name"和"age"字段的JSON字符串。然后,使用`collect`函数将所有JSON字符串收集到一个数组中,并打印出来。 请注意,这只是一个示例,你可以根据你的需求调整代码以适应你的对象结构和数据。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值