zoukankan      html  css  js  c++  java
  • SparkStreaming实战(数据库(NoSQL))

    完全搞清楚项目需求,思考项目选项,这块就是使用的是数据库,就是HBase,因为它里面有一个非常合适的API,直接调用,即可



    功能一: 今天到现在为止 实战课程 的访问量

    yyyyMMdd

    使用数据库来进行存储我们的统计结果 Spark Streaming吧统计结果写入到数据库里面 可视化前端根据: yyyyMMdd courseid 把数据库里面的统计结果展示出来

    选择什么数据库为统计结果的存储呢?
        RDBMS: MySQL、Oracle...
            day     course_id   click_count
            20171111    1           10                              
            20171111    2           10
    
            下一个批次数据进来以后:
    

    NoSQL: HBase、Redis....

    Hbase: 一个API就能搞定,非常方便(城市字段,这块需要键 - 值,各自相加, 在多听听项目需求吧) ==> incrementColumnValue()

    20171111 + 1 ==> click_count + 下一个批次的统计结果写入到数据库中

    前提:

    HBase
    Zookeeper
    HBase

    HBase表设计

    创建表

    create 'imooc_course_clickcount', 'info';
    Rowkey设计
    day_courseid





    pom.xml

    <!--添加scala依赖-->
     <dependency>
          <groupId>org.scala-lang</groupId>
          <artifactId>scala-library</artifactId>
          <version>${scala.version}</version>
        </dependency>
    <!--添加hbase-client依赖-->
      <dependency>
          <groupId>org.apache.hbase</groupId>
          <artifactId>hbase-client</artifactId>
          <version>1.3.1</version>
        </dependency>
    <!--添加spark-streaming依赖-->
      <dependency>
          <groupId>org.apache.spark</groupId>
          <artifactId>spark-streaming_2.11</artifactId>
          <version>${spark.version}</version>
      </dependency>
    

    如何使用Scala来操作HBase

    • 先定义一个实体类 domain/ ClickLog.scala CourseClickCount.scala

    ClickLog.scala

    /**
      * 清洗后的日志信息
      * @param ip    日志访问的ip地址
      * @param time  日志访问的时间
      * @param courseId   日志访问的实战课程编号
      * @param statusCode 日志访问的状态码
      * @param referer    日志访问的referer
      */
    case class ClickLog(ip: String, time: String, courseId: Int, statusCode: Int, referer: String)
    

    CourseClickCount.scala

    
    /**
      * 实战课程点击数
      * @param day_course   对应的就是HBase中的rowkey, 20171111_1
      * @param click_count  对应的20171111_1的访问总数
      */
    case class CourseClickCount(day_course: String, click_count: Long)
    
    • 再定义一个访问层 dao/ CourseClickCountDAO.scala
    import com.project.domain.CourseClickCount
    /**
      * 实战课程点击数-数据访问层)
      */
    object CourseClickCountDAO {
    
     val tableName = "imooc_course_clickcount"
     val cf = "info"
     val qualifer = "click_count"
    
     /**
       * 保存数据到HBase
       * @param list  CourseClickCount集合(要传一个集合进来)
       */
     def save(list: ListBuffer[CourseClickCount]): Unit = {
    
     }
    
     /**
       * 根据rowkey查询值
       * @param day_course
       * @return
       */
     def count(day_course: String): Long = {
    
      }
    
    • 接下来需要开发HBase的工具类,来完成HBase的操作 utils/ HBaseUtils.java
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.client.HBaseAdmin;
    import org.apache.hadoop.hbase.client.HTable;
    import org.apache.hadoop.hbase.client.Put;
    import org.apache.hadoop.hbase.util.Bytes;
    
    import java.io.IOException;
    
    /**
     * HBase操作工具类:Java工具类建议采用单例模式封装
     */
    public class HBaseUtils {
    
        HBaseAdmin admin = null;
        Configuration configuration = null;
    
    
        /**
         * 私有构造方法
         */
        private HBaseUtils() {
            configuration = new Configuration();
            configuration.set("hbase.zookeeper.quorum","localhost:2181");
            configuration.set("hbase.rootdir","hdfs://localhost:8020/hbase");
    
            try {
                admin = new HBaseAdmin(configuration);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        /**
         * 单例模式
         */
        private static HBaseUtils instance = null;
        public static HBaseUtils getInstance() {
            if (null == instance) {
                instance = new HBaseUtils();
            }
            return instance;
        }
    
    
        /**
         * 根据表名获取到HTable实例
         */
        public HTable getTable(String tableName) {
    
            HTable table = null;
    
    
            try {
                table = new HTable(configuration, tableName);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
    
            return table;
        }
    
    
        /**
         * 添加一条记录到HBase表
         * @param tableName HBase表名
         * @param rowkey   HBase表rowkey
         * @param cf   HBase表columnfamily
         * @param column   HBase表的列
         * @param value  写入HBase表的值
         */
        public void put(String tableName, String rowkey, String cf, String column, String value) {
    
            //先拿到表名
            HTable table= getTable(tableName);
    
            //放入一个列值
            Put put = new Put(Bytes.toBytes(rowkey));
            //放入数据
            put.add(Bytes.toBytes(cf), Bytes.toBytes(column), Bytes.toBytes(value));
    
            //传给表,需要捕获异常,增加代码的健壮性
            try {
                table.put(put);
            } catch (IOException e) {
                e.printStackTrace();
            }
    
    
        }
    
        //测试
        public static void main(String[] args) {
    
    //        // 获取表名
    //        HTable table = HBaseUtils.getInstance().getTable("imooc_course_clickcount");
    //
    //        System.out.println(table.getName().getNameAsString());
    
    
    
            // 往HBase表中写入数据
            String tableName = "imooc_course_clickcount";
            String rowkey = "20171111_88";
            String cf = "info";
            String column = "click_count";
            String value = "2";
    
            HBaseUtils.getInstance().put(tableName,rowkey,cf,column,value);
    
        }
    }
    
    • 在scala代码中调用HBase工具类,去创建属性,实现方法 dao/ CourseClickCountDAO.scala
    import com.project.domain.CourseClickCount
    import com.project.utils.HBaseUtils
    import org.apache.hadoop.hbase.client.Get
    import org.apache.hadoop.hbase.util.Bytes
    
    import scala.collection.mutable.ListBuffer
    
    /**
      * 实战课程点击数-数据访问层(下面我们就把我们的统计结果调用dao层,写入hbase中就可以了)
      */
    object CourseClickCountDAO {
    
     val tableName = "imooc_course_clickcount"
     val cf = "info"
     val qualifer = "click_count"
    
     /**
       * 保存数据到HBase
       * @param list  CourseClickCount集合(要传一个集合进来)
       */
     def save(list: ListBuffer[CourseClickCount]): Unit = {
    
      val table = HBaseUtils.getInstance().getTable(tableName)
    
      for (ele <- list) {
       table.incrementColumnValue(Bytes.toBytes(ele.day_course),
        Bytes.toBytes(cf),
        Bytes.toBytes(qualifer),
        ele.click_count)
      }
     }
    
     /**
       * 根据rowkey查询值
       * @param day_course
       * @return
       */
     def count(day_course: String): Long = {
    
      val table = HBaseUtils.getInstance().getTable(tableName)
      val get = new Get(Bytes.toBytes(day_course))
      val value = table.get(get).getValue(cf.getBytes,qualifer.getBytes)
    
      if (value == null) {
       0l
      } else {
       Bytes.toLong(value)
      }
     }
    
    
     /**
       * 测试可否操作HBase数据库成功---
       * @param args
       */
     def main(args: Array[String]): Unit = {
    
      val list = new ListBuffer[CourseClickCount]
      list.append(CourseClickCount("20171111_8", 8))
      list.append(CourseClickCount("20171111_9", 9))
      list.append(CourseClickCount("20171111_1", 100))
    
      save(list)
    
      println(s"${count("20171111_8")} : ${count("20171111_9")} : ${count("20171111_100")}")
     }
    
    }
    
    

    下面我们就把我们的统计结果调用dao(访问)层,写入hbase中就可以了)

    三、(功能一: )统计今天到现在为止实战课程的访问量并写入HBase中

    spark/ ImoocStatStreamingApp.scala

    
    
    object ImoocStatStreamingApp extends App {
    
        //配置入口点
        val conf = new SparkConf().setAppName(getClass.getSimpleName).setMaster("local[2]")
        val ssc= new StreamingContext(conf, Seconds(1))
    
        //输入数据流(DStream) (自己随便定义的,不是用这个,为了不报错)
        val cleanData = ssc.textFileStream("")
    
      //测试步骤三: 统计今天到现在为止实战课程的访问量,并把它写到HBase数据库中
    
      cleanData.map(x => {
        // HBase rowkey设计: 20171111_88
    
        (x.time.substring(0,8)) + "_" + x.courseId, 1)            // key ==> k+1
      }).reduceBykey(_ + _).foreachRDD(rdd => {        //用foreachRDD对DStream进行隐式转换,让它拥有RDD的方法(反射)
        rdd.foreachPartition(partitionRecords => {
          val list = new ListBuffer[CourseClickCount]
          partitionRecords.foreach(pair => {
            list.append(CourseClickCount(pair._1, pair._2))
          })
    
          CourseClickCountDAO.save(list)
        })
      })
      
      
      //启动StreamingContext,接收数据,然后处理数据
      ssc.start()
      ssc.awaitTermination()
    

    此处代码已经在本地开发测试完成,接下来,就需要打包到服务器上去执行.

    四、(功能二)统计今天到现在为止从搜索引擎引流过来的实战课程的访问量

    功能二: 功能一+从搜索引擎引流过来的

    HBase表设计

    create 'imooc_course_search_clickcount', 'info' //创建表
    scan 'imooc_course_search_clickcount' // 查看内容
    

    rowkey设计: 也是根据我们的业务需求来的
    20171111 + search + 1 (rowkey设计后的格式)

    代码开发:
    domain/ CourseSearchClickCount.scala(数据实体类层开发)

    /**
      * 从搜索引擎过来的实战课程点击数实体类
      * @param day_search_course
      * @param click_count
      */
    case class CourseSearchClickCount(day_search_course: String, click_count: Long)
    

    DAO/ CourseSearchClickCountDAO.scala(数据访问层开发)

    import com.project.domain.CourseSearchClickCount
    import com.project.utils.HBaseUtils
    import org.apache.hadoop.hbase.client.Get
    import org.apache.hadoop.hbase.util.Bytes
    
    import scala.collection.mutable.ListBuffer
    
    /**
      * 实战课程点击数-数据访问层(下面我们就把我们的统计结果调用dao层,写入hbase中就可以了)
      */
    object CourseSearchClickCountDAO {
    
     val tableName = "imooc_course_search_clickcount"
     val cf = "info"
     val qualifer = "click_count"
    
    
     /**
       * 保存数据到HBase
       * @param list  CourseSearchClickCount(要传一个集合进来)
       */
     def save(list: ListBuffer[CourseSearchClickCount]): Unit = {
    
      val table = HBaseUtils.getInstance().getTable(tableName)
    
      for (ele <- list) {
       table.incrementColumnValue(Bytes.toBytes(ele.day_search_course),
        Bytes.toBytes(cf),
        Bytes.toBytes(qualifer),
        ele.click_count)
      }
     }
    
     /**
       * 根据rowkey查询值
       * @param day_search_course
       * @return
       */
     def count(day_search_course: String): Long = {
    
      val table = HBaseUtils.getInstance().getTable(tableName)
      val get = new Get(Bytes.toBytes(day_search_course))
      val value = table.get(get).getValue(cf.getBytes,qualifer.getBytes)
    
      if (value == null) {
       0l
      } else {
       Bytes.toLong(value)
      }
     }
    
    
     /**
       * 测试可否操作HBase数据库成功---
       * @param args
       */
     def main(args: Array[String]): Unit = {
    
      val list = new ListBuffer[CourseSearchClickCount]
      list.append(CourseSearchClickCount("20171111_www.baidu.com_8", 8))
      list.append(CourseSearchClickCount("20171111_cn.bing.com_9", 9))
    
    
      save(list)
    
      println(s"${count("20171111_www.baidu.com_8")} : ${count("20171111_cn.bing.com_9")} ")
     }
    
    }
    

    spark/ ImoocStatStreamingApp.scala

    // 测试步骤四: 统计从搜索引擎过来的今天到现在为止实战课程的访问量
      
      cleanData.map(x => {
    
    
        /**
          * https://www.sogou.com/web?query=Spark SQL实战
          * 
          * ==>
          * 
          * https:/www.sogou.com/web?query=Spark SQL实战   
          */
        val referer = x.referer.replaceAll("//", "/")   //( 把 // 替换为 / )
        val splits = referer.split("/")   //用 / 将url分开
        var host = ""
        if (splits.length > 2) {   //如果大于2,才说明从搜索引擎过来的
          host = splits(1)
          
        }
        
        (host, x.courseId, x.time)  //返回三个字段    元组类型
      }).filter(_._1 != "")    //对返回值进行操作; 如果不为空,就是从refer过来的;为空,就不是从refer过来的,过滤掉
          .map(x => {
        (s"${x._3.substring(0,8)}_${x._1}_${x._2} ",1)   // 获取每条记录的  时间,搜索引擎,时间编号,  并给每条赋 1 
      }).reduceBykey(_ + _).foreachRDD(rdd => {        //用foreachRDD对DStream进行隐式转换,让它拥有RDD的方法(反射)将其写入数据库中
        rdd.foreachPartition(partitionRecords => {
          val list = new ListBuffer[CourseSearchClickCount]
          partitionRecords.foreach(pair => {
            list.append(CourseSearchClickCount(pair._1, pair._2))
          })
    
          CourseSearchClickCountDAO.save(list)
        })
      })
    

    注意:

    测试时,预先需要在Hbase数据库中建立相应的表,便于测试

    将结果打印在控制台上(在IDEA中观察结果,再到HBase数据库中查看结果,验证是否正确)

    本地测试到此结束,下面开启将程序打包提交到服务器端运行.

    将项目运行在服务器环境中

    • 编译打包
    • 运行

    项目打包: $ mvn clean package -DskipTests

    报错:

    需要注销这两行,因为在本地进行scala调用java代码的时候,可以直接操作, 编译打包到生产上的时候,没有指向java目录中,所以需要,将下面两行注销

    <sourceDirectory>src/main/scala</sourceDirectory>
    <testSourceDirectory></testSourceDirecetory>
    

    mac系统,需要使用scp去传递到生产上.

    
    --package org.apache.spark:spark-streaming-kafka-0-8_2.11:2.2.0 
    --jars $(echo /home/hadoop/app/hbase-1.2.0-cdh5.7.0/lib/*.jar | tr ' ' ',')  
    // tr ' ' ','    ==》    空白处用 , 分隔 (把hbase的jar包用逗号拼起来)
    
    
    
    • 加入高级数据源的包 spark-streaming-kafka-0-8_2.11
    • 添加hbase的所有jar包

    提交作业时,注意事项: 1) --packages的使用 2) --jars的使用

    (将本地的项目跑到环境环境中) mac -> linux(spark集成环境)

  • 相关阅读:
    496. 下一个更大元素 I 力扣(简单) 单调栈
    240. 搜索二维矩阵 II 力扣(中等) Z字型查找
    638. 大礼包 力扣(中等) 记忆化搜索,弱点
    453. 最小操作次数使数组元素相等 力扣(简单) 没想出来
    传纸条
    同余方程
    花匠
    华容道
    货车运输
    火柴排队
  • 原文地址:https://www.cnblogs.com/suixingc/p/sparkstreaming-shi-zhan-shu-ju-ku-nosql.html
Copyright © 2011-2022 走看看