使用Spark Streaming对接kafka 写入 mysql 并查询 插入(实时更新 没有实时覆盖)

以下是RNG S8 8强赛失败后,官微发表道歉微博下一级评论

部分数据:

17	0	2018/10/20 21:08	许向暖呐:滚       	0	0		5670089757	许向暖呐	0	1540040880
18	0	2018/10/20 21:08	曹大老实人:你知道我在网吧看比赛我周围的人一直说rng回家的时候我心里多难受吗       	0	0		6384972437	曹大老实人	3	1540040880
19	0	2018/10/20 21:08	錯過_0927:滾       	0	0		2430243037	錯過_0927	0	1540040880
20	0	2018/10/20 21:08	沉着的肉夹馍馍:明年再见       	0	0		2128400513	沉着的肉夹馍馍	5	1540040880
21	0	2018/10/20 21:08	阿禹阿我是:但是好累啊?       	0	0		2866358044	阿禹阿我是	0	1540040880
22	0	2018/10/20 21:08	只想当一个吸血鬼:你们到底在搞什么?       	0	0		3938981708	只想当一个吸血鬼	0	1540040880
23	0	2018/10/20 21:08	1999PONG:真强???演进了S9       	0	0		2142121462	1999PONG	0	1540040880
24	0	2018/10/20 21:08	大傻几和小白兔的小白兔:这就是轻敌的后果!!!       	0	0		5344521090	大傻几和小白兔的小白兔	0	1540040880
25	0	2018/10/20 21:08	郝北北的反义词_:放过锅老师 	0	0		3630596621	郝北北的反义词_	0	1540040880
26	0	2018/10/20 21:08	Xuxinxs:气死了       	0	0		6080242282	Xuxinxs	0	1540040880
27	0	2018/10/20 21:08	有基佬拉裤链啦:没有明年了再见       	0	0		5415916508	有基佬拉裤链啦	0	1540040880
28	0	2018/10/20 21:08	忆軒Dreamer:打得什么几把       	1	0		1592295730	忆軒Dreamer	0	1540040880
29	0	2018/10/20 21:08	物是人非前-:gg       	0	0		3928827486	物是人非前-	0	1540040880
30	0	2018/10/20 21:08	酸豆角和酸菜包:加油!       	0	0		5469195664	酸豆角和酸菜包	0	1540040880
31	0	2018/10/20 21:08	绿苔墙根:我依旧相信Royal       	0	1		6299145229	绿苔墙根	0	1540040880

rng_comment.txt文件中的数据字段:

字段

字段含义

index

数据id

child_comment

回复数量

comment_time

评论时间

扫描二维码关注公众号,回复: 11079852 查看本文章

content

评论内容

da_v

微博个人认证

like_status

pic

图片评论url

user_id

微博用户id

user_name

微博用户名

vip_rank

微博会员等级

stamp

时间戳

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

 kafka-topics.sh  --describe --zookeeper node001:2181 --topic  rng_comment 

    1. 数据预处理,把空行过滤掉

代码实现:

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SparkSession}

// spark 对数据 读取 和 写入 所需要导入的包 
package Rng

import org.apache.spark.SparkContext
import org.apache.spark.rdd.RDD
import org.apache.spark.sql.{DataFrame, SparkSession}


/**
  * Created by 一个蔡狗 on 2020/4/23.
  * 过滤空行数据
  */
object FilterNull {

  def main(args: Array[String]): Unit = {

    // 处理数据的思路
    /*
    * 1 读取数据
    * 2 处理数据
    * 3 写出数据
    *
    * */
    val spark: SparkSession = SparkSession.builder().appName("FilterNull").master("local").getOrCreate()
    //设置 SparkContext 对象
    val sc: SparkContext = spark.sparkContext

    //    val sc = new SparkContext(new SparkConf().setAppName("FilterNull").setMaster("local[*]"))

    //读取数据
    val file: RDD[String] = sc.textFile("G:\\rng_comment.txt")
    //过滤数据   filter  返回为 true 的 正确 要保留   :  data  每条数据
    val datas: RDD[String] = file.filter(data => {
      //filter 保留  没有 空行的数据         // 返回  boolean 类型    去掉左右 空格 空行 trim
      if (data.trim.isEmpty) {
        false
      } else {
        true
      }
    }) //.var

    //查看 数据
    //    datas.foreach(println)


    // 为了 使用  DF 对象 将数据输出 ,所以需要将 RDD 转为 DF

    import spark.implicits._
    val DataDF: DataFrame = datas.toDF

    // 结果是 两个 文件        需求 :  搞成 一个数据      repartition重新 分区
    DataDF.repartition(1).write.text("G:\\data")


    // 停止
    sc.stop()
    spark.stop()

  }


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

import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}

// KafkaToMYSql 所需要的包
package Rng;

import org.apache.kafka.clients.producer.KafkaProducer;
import org.apache.kafka.clients.producer.ProducerRecord;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.util.Properties;

/**
 * Created by 一个蔡狗 on 2020/4/23.
 * 从txt文件 读取数据 写入 Kafka
 */
public class TxtToKafka {

    public static void main(String[] args) throws Exception {

/**
 *    Kafka
 *    编写生产数据的程序
 */
        //1、配置kafka集群环境(设置)
        Properties props = new Properties();
        //kafka服务器地址
        props.put("bootstrap.servers", "node001:9092,node002:9092,node003:9092");
        //消息确认机制
        props.put("acks", "all");
        //重试机制
        props.put("retries", 0);
        //批量发送的大小
        props.put("batch.size", 16384);
        //消息延迟
        props.put("linger.ms", 1);
        //批量的缓冲区大小
        props.put("buffer.memory", 33554432);
        // kafka   key 和value的序列化
        props.put("key.serializer", "org.apache.kafka.common.serialization.StringSerializer");
        props.put("value.serializer", "org.apache.kafka.common.serialization.StringSerializer");


        //2、实例一个生产者对象
        KafkaProducer<String, String> kafkaProducer = new KafkaProducer<String, String>(props);


        //  使用 java  读取本地文件  按行读取  数据写入 Kafka 时 按时每行写入一次

        File inputFile = new File("G:\\rng_comment.txt");
        BufferedReader bufferedReader = new BufferedReader(new FileReader(inputFile));
        String line = null;
        int partition = 0;
        //获取到每条数据
        while ((line = bufferedReader.readLine()) != null) {
            //根据数据id进行分区,id为  奇数 的发送到一个分区中,偶数  的发送到另一个分区
            try {
                if (Integer.parseInt(line.split("\t")[0]) % 2 == 0) {
                    partition = 0;
                } else {
                    partition = 1;
                }

            } catch (Exception e) {
                continue;
            }
            // 10 个 \t 有意思
            if (!line.equals("\t\t\t\t\t\t\t\t\t\t")) {
                // 传入   数据 到  kafka 的    topic 中
                kafkaProducer.send(new ProducerRecord<String, String>("rng_comment", partition, String.valueOf(partition), line));
                // 一秒钟输出一次
                System.out.println(line);

                Thread.sleep(1000);
            }
        }

        //关闭 流
        bufferedReader.close();
        // 关闭 kafka
        kafkaProducer.close();
    }


}

使用Spark Streaming 读取  kafka 数据 之后进行计算 : 查询出微博会员等级为5的用户,并把这些数据写入到mysql数据库中的vip_rank表中

在数据库rng_comment创建vip_rank表,字段为数据的所有字段

CREATE TABLE `vip_rank`  (
`indexx` varchar(100)NOT NULL,
`child_comment`  varchar(100)NOT NULL,
`comment_time`  varchar(100)NOT NULL,
`content` varchar(100)NOT NULL,
`da_v` varchar(100),
`like_status` varchar(100)  NOT NULL,
`pic` varchar(100)  NOT NULL,
`user_id` varchar(100)  NOT NULL,
`user_name` varchar(100)  NOT NULL,
`vip_rank`  varchar(100)  NOT NULL,
`stamp` varchar(100) 
)ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;
select count(*) from vip_rank;

//查询 有 多少条数据 
package Rng



import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.dstream.{DStream, InputDStream, ReceiverInputDStream}

/**
  * Created by 一个蔡狗 on 2020/4/23.
  * 1.4、使用Spark Streaming对接kafka
  *1.5、使用Spark Streaming对接kafka之后进行计算
  * 在mysql中创建一个数据库
  * 在数据库rng_comment创建vip_rank表,字段为数据的所有字段
  *
  */


object KafkaToMySql {

  //mysql 数据库方法

  def ToMysql(meaaageValue:String) ={
    //meaaageValue====> 284	0	2018/10/20 21:08	文韜_:看得我....无言以对       	0	0		1617054581	文韜_	5	1540040880

    //打印数据 并 测试 查看
    println(meaaageValue)
    val str = meaaageValue.split("\t")

    //数据写入mysql的动作
    val url="jdbc:mysql://node002:3306/rng_comment?characterEncoding=UTF-8"
    val username = "root"
    val pwd = "123456"


    val connection: Connection = DriverManager.getConnection(url, username,pwd)
    //  REPLACE into  
    // REPLACE INTO:表示如果表中没有数据这插入,如果有数据则替换
    //注意:REPLACE INTO要求表有主键或唯一索引

    var sql="insert into vip_rank (indexx,child_comment,comment_time,content,da_v,like_status,Pic,user_id,user_name,vip_rank,stamp) values (?,?,?,?,?,?,?,?,?,?,?);"

    val ps: PreparedStatement = connection.prepareStatement(sql)
    ps.setString(1,strings(0))
    ps.setString(2,strings(1))
    ps.setString(3,strings(2))
    ps.setString(4,strings(3))
    ps.setString(5,strings(4))
    ps.setString(6,strings(5))
    ps.setString(7,strings(6))
    ps.setString(8,strings(7))
    ps.setString(9,strings(8))
    ps.setString(10,strings(9))
    ps.setString(11,strings(10))

    ps.executeUpdate()
  }




  def main(args: Array[String]): Unit = {

    var  kafkaParams= Map[String, Object](
      "bootstrap.servers" -> "node001:9092,node002:9092,node003:9092",
      "key.deserializer" -> classOf[StringDeserializer],
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> "SparkKafkaDemo",
      "auto.offset.reset" -> "latest",
      "enable.auto.commit" -> (false: java.lang.Boolean)

    )


    //1 创建SSC
    var  conf =new SparkConf().setMaster("local").setAppName("KafkaToMysql")
    var sc =new SparkContext(conf)
    sc.setLogLevel("WARN")
    var ssc=new  StreamingContext(sc,Seconds(5))


    //2 到kafka读取所有数据
    val kafkaDatas = KafkaUtils.createDirectStream[String, String](
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](Array("rng_comment"), kafkaParams))


// 1.5.1、查询出微博会员等级为5的用户,并把这些数据写入到mysql数据库中的vip_rank表中
    //3 过滤出星级为5的用户  使用\t切分数据,角标为9 的就是星级

    val fiveDatas: DStream[ConsumerRecord[String, String]] = kafkaDatas.filter(a => {
      if (a.value().split("\t")(9) == "5") {
        true
      } else {
        false
      }
    })

    /*    fiveDatas.foreachRDD(rdd=>{
          rdd.foreach(println)
        })*/


    //4 将星级为5的用户写入mysql
    fiveDatas.foreachRDD(rdd=>{
      //meaasge======>    ConsumerRecord(topic = 18BD12,
      // partition = 0,
      // offset = 744,
      // CreateTime = 1587612217294,
      // checksum = 4267738419,
      // serialized key size = -1
      // serialized value size = 102,
      // key = null,
      // value = 284	0	2018/10/20 21:08	文韜_:看得我....无言以对       	0	0		1617054581	文韜_	5	1540040880)
      rdd.foreach(meaasge=>ToMysql(meaasge.value()))
    })


    ssc.start()
    ssc.awaitTermination()


  }

}

在数据库rng_comment创建like_status表,字段为数据的所有字段

 CREATE TABLE `like_status`  (
`indexx` varchar(100)NOT NULL,
`child_comment`  varchar(100)NOT NULL,
`comment_time`  varchar(100)NOT NULL,
`content` varchar(100)NOT NULL,
`da_v` varchar(100),
`like_status` varchar(100)  NOT NULL,
`pic` varchar(100)  NOT NULL,
`user_id` varchar(100)  NOT NULL,
`user_name` varchar(100)  NOT NULL,
`vip_rank`  varchar(100)  NOT NULL,
`stamp` varchar(100) 
)ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;

1.5.2、查询出评论赞的个数在10个以上的数据,并写入到mysql数据库中的like_status表中 

import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}

// 需要导的包
package Rng

import java.sql.{Connection, DriverManager, PreparedStatement}

import org.apache.kafka.clients.consumer.ConsumerRecord
import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}

/**
  * Created by 一个蔡狗 on 2020/4/23.
  * 1.5.2、查询出评论赞的个数在10个以上的数据,并写入到mysql数据库中的 like_status 表中
  *
  */
object KafkaToMYSql_02 {


  //mysql 数据库方法

  def ToMysql(meaaageValue: String) = {
//    meaaageValue = 109	 261 	2018/10/20 21:08	别咬嘴唇:我见你???教练组背全锅???打的什么j8玩意儿?   
    //    	          0	  1439		2091116821	别咬嘴唇	6	1540040880
    //打印数据 并 测试 查看
    println(meaaageValue)
    val str = meaaageValue.split("\t")

    //数据写入mysql的动作
    val url="jdbc:mysql://node002:3306/rng_comment?characterEncoding=UTF-8"
    val username = "root"
    val pwd = "123456"


    val connection: Connection = DriverManager.getConnection(url, username,pwd)

    //  REPLACE into
    // REPLACE INTO:表示如果表中没有数据这插入,如果有数据则替换
    //注意:REPLACE INTO要求表有主键或唯一索引

    var sql = "insert into like_status (indexx,child_comment,comment_time,content,da_v,like_status,Pic,user_id,user_name,vip_rank,stamp) values (?,?,?,?,?,?,?,?,?,?,?);"

    val ps: PreparedStatement = connection.prepareStatement(sql)
    ps.setString(1, str(0))
    ps.setString(2, str(1))
    ps.setString(3, str(2))
    ps.setString(4, str(3))
    ps.setString(5, str(4))
    ps.setString(6, str(5))
    ps.setString(7, str(6))
    ps.setString(8, str(7))
    ps.setString(9, str(8))
    ps.setString(10, str(9))
    ps.setString(11, str(10))

    ps.executeUpdate()
  }


  // 程序入口
  def main(args: Array[String]): Unit = {

    var kafkaParams = Map[String, Object](
      "bootstrap.servers" -> "node001:9092,node002:9092,node003:9092",
      "key.deserializer" -> classOf[StringDeserializer],
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> "SparkKafkaDemo",
      "auto.offset.reset" -> "latest",
      "enable.auto.commit" -> (false: java.lang.Boolean)

    )


    //1 创建SSC
    var conf = new SparkConf().setMaster("local").setAppName("KafkaToMysql02")
    var sc = new SparkContext(conf)
    sc.setLogLevel("WARN")
    var ssc = new StreamingContext(sc, Seconds(5))


    //2 到kafka读取所有数据
    val kafkaDatas = KafkaUtils.createDirectStream[String, String](
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](Array("rng_comment"), kafkaParams))


    //3 过滤出 查询出 评论赞的个数在10个以上的数据

    val fiveDatas: DStream[ConsumerRecord[String, String]] = kafkaDatas.filter(a => {
      if (a.value().split("\t")(5).toInt > 10) {
        true
      } else {
        false
      }
    })


    //查看数据
    //
    //        fiveDatas.foreachRDD(rdd=>{
    //          rdd.foreach(println)
    //        })


    //4 1.5.2、,并写入到mysql数据库中的like_status表中
    fiveDatas.foreachRDD(rdd => {
      //meaasge======>    ConsumerRecord(topic = rng_comment,
      // partition = 1,
      // offset = 1008,
      // CreateTime = 1587624612187,
      // checksum = 3072747765,
      // serialized key size = 1
      // serialized value size = 151,
      // key = 1,
      // value = 109	 261 	2018/10/20 21:08	别咬嘴唇:我见你???教练组背全锅???打的什么j8玩意儿?       	0	  1439		2091116821	别咬嘴唇	6	1540040880)   value 是这行数据
      rdd.foreach(meaasge => ToMysql(meaasge.value()))
    })


    ssc.start()
    ssc.awaitTermination()


  }


}

在数据库rng_comment创建count_conmment表,字段为 时间,条数


 CREATE TABLE `count_conmment`  (
`stamp` varchar(100) NOT NULL,
`counts`  varchar(100) NOT NULL
)ENGINE=InnoDB AUTO_INCREMENT=26 DEFAULT CHARSET=utf8;

分别计算出2018/10/20 ,2018/10/21,2018/10/22,2018/10/23这四天每一天的评论数是多少,并写入到mysql数据库中的count_conmment表中

package Rng

import java.sql.{Connection, DriverManager, PreparedStatement}
import java.text.SimpleDateFormat

import org.apache.kafka.common.serialization.StringDeserializer
import org.apache.spark.streaming.dstream.DStream
import org.apache.spark.{SparkConf, SparkContext}
import org.apache.spark.streaming.{Seconds, StreamingContext}
import org.apache.spark.streaming.kafka010.{ConsumerStrategies, KafkaUtils, LocationStrategies}


/**
  * Created by 一个蔡狗 on 2020/4/23.
  */
object KafkaToMySql_03 {

  //mysql 数据库方法

  def ToMysql(time: String, count: String) = {

    //打印数据 并 测试 查看
    println(s"$time\t $count")
    //数据写入mysql的动作
    val url = "jdbc:mysql://node002:3306/rng_comment?characterEncoding=UTF-8"
    val username = "root"
    val pwd = "123456"

    val connection: Connection = DriverManager.getConnection(url, username, pwd)

    //  REPLACE into
    // REPLACE INTO:表示如果表中没有数据这插入,如果 有数据则替换
    //注意:REPLACE INTO要求表有主键或唯一索引

    val sql: String = "INSERT INTO count_conmment (stamp,counts) VALUES (?,?) ON DUPLICATE KEY UPDATE counts = ? "

    val ps: PreparedStatement = connection.prepareStatement(sql)
    ps.setString(1, time)
    ps.setString(2, count)
    ps.setString(3, count)
    ps.execute()
    connection.close()

  }


  // 程序入口
  def main(args: Array[String]): Unit = {

    var kafkaParams = Map[String, Object](
      "bootstrap.servers" -> "node001:9092,node002:9092,node003:9092",
      "key.deserializer" -> classOf[StringDeserializer],
      "value.deserializer" -> classOf[StringDeserializer],
      "group.id" -> "SparkKafkaDemo",
      "auto.offset.reset" -> "latest",
      "enable.auto.commit" -> (false: java.lang.Boolean)
    )
    //1 创建SSC
    var conf = new SparkConf().setMaster("local").setAppName("KafkaToMysql02")
    var sc = new SparkContext(conf)
    sc.setLogLevel("WARN")


    var ssc = new StreamingContext(sc, Seconds(5))

    //那么历史数据存在哪?我们需要给他设置一个checkpoint目录
    ssc.checkpoint("./wc") //开发中HDFS


    //2 到kafka读取所有数据
    val datas = KafkaUtils.createDirectStream[String, String](
      ssc,
      LocationStrategies.PreferConsistent,
      ConsumerStrategies.Subscribe[String, String](Array("rng_comment"), kafkaParams))


    //3 过滤 分别计算出2018/10/20 ,2018/10/21,2018/10/22,2018/10/23这四天每一天的评论数是多少,

    val dateFormat1 = new SimpleDateFormat("yyyy/MM/dd HH:mm")
    val dateFormat2 = new SimpleDateFormat("yyyy/MM/dd")


    val Counts: DStream[(String, Int)] = datas.filter(a => {
      // 数据格式 : 109	  261	  2018/10/20 21:08
      // 角标         0     1        2       2 是时间
      //先转出时间戳的 时间

      val str: String = dateFormat2.format(dateFormat1.parse(a.value().split("\t")(2)))

      //  得到这四天的 数据
      if ("2018/10/20".equals(str) || "2018/10/21".equals(str) || "2018/10/22".equals(str) || "2018/10/23".equals(str)) {
        true
      } else {
        false
      }

      //并   将 时间 和  数量    写入到mysql数据库中的 count_conmment 表中


      //      //meaasge======>    ConsumerRecord(topic = rng_comment,
      //      // partition = 1,
      //      // offset = 1008,
      //      // CreateTime = 1587624612187,
      //      // checksum = 3072747765,
      //      // serialized key size = 1
      //      // serialized value size = 151,
      //      // key = 1,
      // value =  6	0	2018/10/20 21:08	春眠不觉晓丫:滚       	0	0		3295234971	春眠不觉晓丫	0	1540040880)

    }).map(x => dateFormat2.format(dateFormat1.parse(x.value().split("\t")(2)))).map((_, 1)).updateStateByKey(updateFunc)

    //遍历统计结果
    Counts.foreachRDD(
      //调用方法把数据存储到mysql
      _.foreach(row=>ToMysql(row._1,row._2.toString)
      )
    )

    ssc.start()
    ssc.awaitTermination()


  }




  /**
    * 历史累加
    *
    * @param currentValues 当前值
    * @param historyValue  历史值
    * @return
    */
  def updateFunc(currentValues: Seq[Int], historyValue: Option[Int]): Option[Int] = {
    val result: Int = currentValues.sum + historyValue.getOrElse(0)
    Some(result)
  }




}

发布了269 篇原创文章 · 获赞 627 · 访问量 41万+

猜你喜欢

转载自blog.csdn.net/bbvjx1314/article/details/105699586