Spark中的小案例(RNG S8 失败后的微博评论)

rng_comment.txt文件中的数据说明

字段字段含义
index数据id
child_comment回复数量
comment_time评论时间
content评论内容
da_v微博个人认证
like_status
pic图片评论url
user_id微博用户id
user_name微博用户名
vip_rank微博会员等级
stamp时间戳

1、在kafak中创建rng_comment主题,设置2个分区2个副本

bin/kafka-topics.sh --create --zookeeper node01:2181,node02:2181,node03:2181 --replication-factor 2 --partitions 2 --topic rng_comment

2、数据预处理,把空行过滤掉

在这里插入图片描述

import org.apache.spark.sql.SparkSession
 
object tt02 {
  def main(args: Array[String]): Unit = {
    val spark = SparkSession.builder().appName("tt02").master("local[*]").getOrCreate()
    val sc = spark.sparkContext
    sc.setLogLevel("warn")
    //读取数据过滤掉空行
    val data = sc.textFile("D:\学习课件\网课\Spark_04.15\4.14号练习题\rng_comment.txt")
    val filterdata = data.filter(a => {
      if (a.trim != null) {
        true
      } else {
        false
      }
    })
 
    import spark.implicits._
    val dataFrame = filterdata.toDF()
    //reparttion :修改分区数,默认为2个分区,改为一个
    dataFrame.repartition(1).write.text("D:\学习课件\网课\Spark_04.15\4.14号练习题\rng")
  }
}

在这里插入图片描述

3、请把给出的文件写入到kafka中,根据数据id进行分区,id为奇数的发送到一个分区中,偶数的发送到另一个分区

package com.czxy.demo1;
 
import org.apache.commons.io.FileUtils;
import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;
 
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
 
public class kafkaProducer {
    public static void main(String[] args) {
        Properties props = new Properties();
//kafka服务器地址
        props.put("bootstrap.servers", "node01:9092,node02:9092,node03:9092");
//消息确认机制
        props.put("acks", "all");
//重试机制
        props.put("retries", 0);
//批量发送的大小
        props.put("batch.size", 16384);
//消息延迟
        props.put("linger.ms", 1);
批量的缓冲区大小
        props.put("buffer.memory", 33554432);
        props.put("key.serializer",
                "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer",
                "org.apache.kafka.common.serialization.StringSerializer");
        //自定义分区
        props.put("partitioner.class", "com.czxy.demo1.MyPartition");
 
        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(props);
        List list = null;
        try {
            //读取本地json文件
            list = FileUtils.readLines(new File("D:\学习课件\网课\Spark_04.15\4.14号练习题\rng_comment.txt"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        ArrayList<String> arrayList = new ArrayList<>();
        for (Object o : list) {
            String s = o.toString();
            if (s.trim()!=""){
                arrayList.add(s);
            }
        }
        for (String s : arrayList) {
            String[] split = s.split("\t");
           if (split.length>=11){
               //指定分区
//               if (Integer.parseInt(split[0])%2==0){
//                   kafkaProducer.send(new ProducerRecord<String, String>("rng_comment",0,String.valueOf(0),s));
//               }else {
//                   kafkaProducer.send(new ProducerRecord<String, String>("rng_comment",1,String.valueOf(1),s));
//               }
 
               //自定义分区
               kafkaProducer.send(new ProducerRecord<String, String>("rng_comment",s));
           }
        }
        kafkaProducer.close();
    }
}
package com.czxy.demo1;
 
 
import org.apache.kafka.clients.producer.Partitioner;
import org.apache.kafka.common.Cluster;
 
import java.util.Map;
 
public class MyPartition  implements Partitioner {
 
    @Override
    public int partition(String s, Object o, byte[] bytes, Object o1, byte[] bytes1, Cluster cluster) {
        String[] split = s.split("\t");
        int id=Integer.parseInt(split[0]);
        if (id%2==0){
            return 0;
        }else {
            return 1;
        }
    }
 
    @Override
    public void close() {
 
    }
 
    @Override
    public void configure(Map<String, ?> map) {
 
    }
}

4、使用Spark Streaming对接kafka

使用Spark Streaming对接kafka之后进行计算
在mysql中创建一个数据库rng_comment
在数据库rng_comment创建vip_rank表,字段为数据的所有字段
在数据库rng_comment创建like_status表,字段为数据的所有字段
在数据库rng_comment创建count_conmment表,字段为 时间,条数
5查询出微博会员等级为5的用户,并把这些数据写入到mysql数据库中的vip_rank表中
6查询出评论赞的个数在10个以上的数据,并写入到mysql数据库中的like_status表中
7分别计算出2018/10/20 ,2018/10/21,2018/10/22,2018/10/23这四天每一天的评论数是多少,并写入到mysql数据库中的count_conmment表中

package com.czxy.demo01
 
import org.apache.kafka.clients.consumer.{ConsumerRecord}
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.streaming.dstream.{DStream, InputDStream}
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import java.sql.{Connection, DriverManager, PreparedStatement}
import org.apache.spark.rdd.{JdbcRDD, RDD}
import org.apache.spark.{SparkConf, SparkContext}
 

object tt01 {
  def main(args: Array[String]): Unit = {
    val config: SparkConf = new SparkConf().setAppName("SparkStream").setMaster("local[*]")
    val sc = new SparkContext(config)
    sc.setLogLevel("WARN")
    val ssc = new StreamingContext(sc, Seconds(5))
    ssc.checkpoint("./kafka")
 
    //链接kafka
    val kafkaParams = Map[String, Object](
      "bootstrap.servers" -> "node01:9092,node02:9092,node03:9092",
      "key.deserializer" -> classOf[StringDeserializer],
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> "SparkKafkaDemo",
      //earliest:当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,从头开始消费
      //latest:当各分区下有已提交的offset时,从提交的offset开始消费;无提交的offset时,消费新产生的该分区下的数据
      //none:topic各分区都存在已提交的offset时,从offset后开始消费;只要有一个分区不存在已提交的offset,则抛出异常
      //这里配置latest自动重置偏移量为最新的偏移量,即如果有偏移量从偏移量位置开始消费,没有偏移量从新来的数据开始消费
      "auto.offset.reset" -> "earliest",
      //false表示关闭自动提交.由spark帮你提交到Checkpoint或程序员手动维护
      "enable.auto.commit" -> (false: java.lang.Boolean)
    )
 
    //读取数据
    val kafkaDatas: InputDStream[ConsumerRecord[String, String]] =
      KafkaUtils.createDirectStream[String, String](ssc,
        LocationStrategies.PreferConsistent, //本地策略,PreferConsistent官方推荐、高效、均衡
        ConsumerStrategies.Subscribe[String, String](Array("rng_comment"), kafkaParams) //消费策略
      )
    val line: DStream[Array[String]] = kafkaDatas.map(_.value()).map(_.split("\t")).cache()
 
 
    //    1.5.1、查询出微博会员等级为5的用户,并把这些数据写入到mysql数据库中的vip_rank表中
    val filterdata: DStream[Array[String]] = line.filter(_ (9) == "5")
    filterdata.foreachRDD {
      rdd: RDD[Array[String]] => {
        rdd.foreachPartition(saveToMySQL)
      }
    }
 
 
    //    1.5.2、查询出评论赞的个数在10个以上的数据,并写入到mysql数据库中的like_status表中
    val filterdata2: DStream[Array[String]] = line.filter(_ (5).toInt > 10)
    filterdata2.foreachRDD {
      rdd: RDD[Array[String]] => {
        rdd.foreachPartition(saveToMySQL2)
      }
    }
 
    //    1.5.3、分别计算出2018/10/20 ,2018/10/21,2018/10/22,2018/10/23这四天每一天的评论数是多少,并写入到mysql数据库中的count_conmment表中
    val filterdata3: DStream[Array[String]] = line.filter {
      date: Array[String] => {
        if(date(2).contains("2018/10/20")||date(2).contains("2018/10/21")||date(2).contains("2018/10/22")||date(2).contains("2018/10/23")){
          true
        } else {
          false
        }
      }
    }
    filterdata2.foreachRDD {
      rdd: RDD[Array[String]] => {
        rdd.foreachPartition(saveToMySQL3)
      }
    }
 
 
    ssc.start() //开启
    ssc.awaitTermination() //等待优雅停止
  }
 
  def getConn(): Connection = {
    DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8", "root", "root")
  }
 
  def saveToMySQL(partitionData: Iterator[Array[String]]): Unit = {
    //将数据存入到MySQL
    //获取连接
    val conn: Connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8", "root", "root")
    partitionData.foreach(
      data => {
        //将每一条数据存入到MySQL
        var sql = "insert into vip_rank values (?,?,?,?,?,?,?,?,?,?,?)"
        val ps: PreparedStatement = conn.prepareStatement(sql)
        ps.setInt(1, data(0).toInt)
        ps.setInt(2, data(1).toInt)
        ps.setString(3, data(2))
        ps.setString(4, data(3))
        ps.setString(5, data(4))
        ps.setString(6, data(5))
        ps.setString(7, data(6))
        ps.setString(8, data(7))
        ps.setString(9, data(8))
        ps.setInt(10, data(9).toInt)
        ps.setString(11, data(10))
        ps.executeUpdate()
        ps.close()
      })
    //ps.executeBatch()
    conn.close()
  }
 
 
  def saveToMySQL2(partitionData: Iterator[Array[String]]): Unit = {
    //将数据存入到MySQL
    //获取连接
    val conn: Connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8", "root", "root")
    partitionData.foreach(
      data => {
        //将每一条数据存入到MySQL
        var sql = "insert into like_status values (?,?,?,?,?,?,?,?,?,?,?)"
        val ps: PreparedStatement = conn.prepareStatement(sql)
        ps.setInt(1, data(0).toInt)
        ps.setInt(2, data(1).toInt)
        ps.setString(3, data(2))
        ps.setString(4, data(3))
        ps.setString(5, data(4))
        ps.setString(6, data(5))
        ps.setString(7, data(6))
        ps.setString(8, data(7))
        ps.setString(9, data(8))
        ps.setInt(10, data(9).toInt)
        ps.setString(11, data(10))
        ps.executeUpdate()
        ps.close()
      })
    //ps.executeBatch()
    conn.close()
  }
 
 
  def saveToMySQL3(partitionData: Iterator[Array[String]]): Unit = {
    //将数据存入到MySQL
    //获取连接
    val conn: Connection = DriverManager.getConnection("jdbc:mysql://localhost:3306/bigdata?characterEncoding=UTF-8", "root", "root")
    partitionData.foreach(
      data => {
        //将每一条数据存入到MySQL
        var sql = "insert into count_conmment values (?,?)"
        val ps: PreparedStatement = conn.prepareStatement(sql)
        ps.setString(1, data(0))
        ps.setInt(2, data(1).toInt)
        ps.executeUpdate()
        ps.close()
      })
    //ps.executeBatch()
    conn.close()
  }
}
 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值