有兴趣想学习国内整套Spark+Spark Streaming+Machine learning顶级课程的,可加我qq 471186150。共享视频,性价比超高!
本讲的目标是广告点击流进来,我们对它进行统计。首先实现对数据进行统计,后续十讲我们再做其它操作。
1:spark用scala开发,只能用java与数据库交互,用Hbase交互的时候,Spark在线上生产环境与Hbase交互的时候,也是用java交互。等,应该国内大多数情况下还是使用java。而scala更多是为spark 内核服务,要求精通scala,估计主要不是为了开发项目,而是为了研究和改造框架的源码,连scala都不会,精通什么spark,无法读懂源码,出了故障,就很可能没戏了。中大型项目基本主要是用java开发。主要Spark是位于企业的一个大环境下的,scala再优秀,不可能把企业的其它项目全部改成scala。这个就是十年之内估计也没法达到这个目标,因为java在企业级开发的地位十年内几乎完全是不可撼动的。
package com.dt.streaming; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.spark.SparkConf; import org.apache.spark.api.java.function.FlatMapFunction; import org.apache.spark.api.java.function.Function; import org.apache.spark.api.java.function.Function2; import org.apache.spark.api.java.function.PairFunction; import org.apache.spark.streaming.Durations; import org.apache.spark.streaming.api.java.JavaDStream; import org.apache.spark.streaming.api.java.JavaPairDStream; import org.apache.spark.streaming.api.java.JavaPairInputDStream; import org.apache.spark.streaming.api.java.JavaStreamingContext; import org.apache.spark.streaming.kafka.KafkaUtils; import kafka.serializer.StringDecoder; import scala.Tuple2; /** * * 在线处理广告点击流 * 广告点击的基本数据格式:timestamp、ip、userID、adID、province、city * * */ public class AdClickedStreamingStats { public static void main(String[] args) { /* * 第一步:配置SparkConf: * 1,至少2条线程:因为Spark Streaming应用程序在运行的时候,至少有一条 * 线程用于不断的循环接收数据,并且至少有一条线程用于处理接受的数据(否则的话无法 * 有线程用于处理数据,随着时间的推移,内存和磁盘都会不堪重负); * 2,对于集群而言,每个Executor一般肯定不止一个Thread,那对于处理Spark Streaming的 * 应用程序而言,每个Executor一般分配多少Core比较合适?根据我们过去的经验,5个左右的 * Core是最佳的(一个段子分配为奇数个Core表现最佳,例如3个、5个、7个Core等); */ SparkConf conf = new SparkConf().setMaster("local[5]"). setAppName("AdClickedStreamingStats"); /*SparkConf conf = new SparkConf().setMaster("spark://Master:7077"). setAppName("SparkStreamingOnKafkaReceiver");*/ /* * 第二步:创建SparkStreamingContext: * 1,这个是SparkStreaming应用程序所有功能的起始点和程序调度的核心 * SparkStreamingContext的构建可以基于SparkConf参数,也可基于持久化的SparkStreamingContext的内容 * 来恢复过来(典型的场景是Driver崩溃后重新启动,由于Spark Streaming具有连续7*24小时不间断运行的特征, * 所有需要在Driver重新启动后继续上衣系的状态,此时的状态恢复需要基于曾经的Checkpoint); * 2,在一个Spark Streaming应用程序中可以创建若干个SparkStreamingContext对象,使用下一个SparkStreamingContext * 之前需要把前面正在运行的SparkStreamingContext对象关闭掉,由此,我们获得一个重大的启发SparkStreaming框架也只是 * Spark Core上的一个应用程序而已,只不过Spark Streaming框架箱运行的话需要Spark工程师写业务逻辑处理代码; */ JavaStreamingContext jsc = new JavaStreamingContext(conf, Durations.seconds(10)); /* * 第三步:创建Spark Streaming输入数据来源input Stream: * 1,数据输入来源可以基于File、HDFS、Flume、Kafka、Socket等 * 2, 在这里我们指定数据来源于网络Socket端口,Spark Streaming连接上该端口并在运行的时候一直监听该端口 * 的数据(当然该端口服务首先必须存在),并且在后续会根据业务需要不断的有数据产生(当然对于Spark Streaming * 应用程序的运行而言,有无数据其处理流程都是一样的); * 3,如果经常在每间隔5秒钟没有数据的话不断的启动空的Job其实是会造成调度资源的浪费,因为并没有数据需要发生计算,所以 * 实例的企业级生成环境的代码在具体提交Job前会判断是否有数据,如果没有的话就不再提交Job; * 4,在本案例中具体参数含义: * 第一个参数是StreamingContext实例; * 第二个参数是ZooKeeper集群信息(接受Kafka数据的时候会从ZooKeeper中获得Offset等元数据信息) * 第三个参数是Consumer Group * 第四个参数是消费的Topic以及并发读取Topic中Partition的线程数 */ /** * 创建Kafka元数据,来让Spark Streaming这个Kafka Consumer利用 */ Map<String, String> kafkaParameters = new HashMap<String, String>(); kafkaParameters.put("metadata.broker.list", "Master:9092,Worker1:9092,Worker2:9092"); Set<String> topics = new HashSet<String>(); topics.add("AdClicked"); JavaPairInputDStream<String, String> adClickedStreaming = KafkaUtils.createDirectStream(jsc, String.class, String.class, StringDecoder.class, StringDecoder.class, kafkaParameters, topics); /* * 第四步:接下来就像对于RDD编程一样基于DStream进行编程!!!原因是DStream是RDD产生的模板(或者说类),在Spark Streaming具体 * 发生计算前,其实质是把每个Batch的DStream的操作翻译成为对RDD的操作!!! *对初始的DStream进行Transformation级别的处理,例如map、filter等高阶函数等的编程,来进行具体的数据计算 * 广告点击的基本数据格式:timestamp、ip、userID、adID、province、city */ //下面是把广告数据切分出来,重新组拼成后面我们需要的格式 JavaPairDStream<String, Long> pairs = adClickedStreaming.mapToPair(new PairFunction<Tuple2<String,String>, String, Long>() { @Override public Tuple2<String, Long> call(Tuple2<String, String> t) throws Exception { String[] splited = t._2.split("\t"); String timestamp = splited[0]; String ip = splited[1]; String userID = splited[2]; String adID = splited[3]; String province = splited[4]; String city = splited[5]; String clickedRecord = timestamp + "_" + ip + "_" + userID + "_" + adID + "_" + province + "_" + city; return new Tuple2<String, Long>(clickedRecord, 1L); } }); /* * * 计算每个Batch Duration中每个User的广告点击量,Function2里面的3个long,第一个value,第2个value,第3个是结果值 */ JavaPairDStream<String, Long> adClickedUsers = pairs.reduceByKey(new Function2<Long, Long, Long>(){ @Override public Long call(Long v1, Long v2) throws Exception { // TODO Auto-generated method stub return v1 + v2; } }); /** * * 计算出什么叫有效的点击? * 1,复杂化的一般都是采用机器学习训练好模型直接在线进行过滤; * 2,简单的?可以通过一个Batch Duration中的点击次数来判断是不是非法广告点击,但是实际上讲非法广告 * 点击程序,会尽可能模拟真实的广告点击行为,所以通过一个Batch来判断是 不完整的,我们需要对例如一天(也可以是每一个小时) * 的数据进行判断 * */ JavaPairDStream<String, Long> filteredClickInBatch = adClickedUsers.filter(new Function<Tuple2<String,Long>, Boolean>() { @Override public Boolean call(Tuple2<String, Long> v1) throws Exception { if ( 1 < v1._2){ return false;//一个batch里面如果点击次数大于一次,视为黑名单,过滤掉 } else { return true; } } }); // Todo。。。。 /* * 此处的print并不会直接出发Job的执行,因为现在的一切都是在Spark Streaming框架的控制之下的,对于Spark Streaming * 而言具体是否触发真正的Job运行是基于设置的Duration时间间隔的 * * 诸位一定要注意的是Spark Streaming应用程序要想执行具体的Job,对Dtream就必须有output Stream操作, * output Stream有很多类型的函数触发,类print、saveAsTextFile、saveAsHadoopFiles等,最为重要的一个 * 方法是foraeachRDD,因为Spark Streaming处理的结果一般都会放在Redis、DB、DashBoard等上面,foreachRDD * 主要就是用用来完成这些功能的,而且可以随意的自定义具体数据到底放在哪里!!! * */ filteredClickInBatch.print(); /* * Spark Streaming执行引擎也就是Driver开始运行,Driver启动的时候是位于一条新的线程中的,当然其内部有消息循环体,用于 * 接受应用程序本身或者Executor中的消息; */ jsc.start(); jsc.awaitTermination(); jsc.close(); } }