大数据学习29:Spark Core编程案例

案例一:分析tomcat的访问日志,求访问量最高的两个网页

	1、对每个jps的访问量求和
	2、排序
	3、取前两条记录
	结果:ArrayBuffer((oracle.jsp,9), (hadoop.jsp,9))

代码:

package log

import org.apache.spark.{SparkConf, SparkContext}


object AnalizeLog {
  def main(args: Array[String]): Unit = {
    //创建一个Context对象
    val conf = new SparkConf().setAppName("MyTomcatLogCount").setMaster("local");
    val sc = new SparkContext(conf)

    /**
      *
      * 读入日志,解析每行日志,找到访问的jsp网页
      *
      * */
    val rdd1 =  sc.textFile("D:\\BigData\\sc\\localhost_access_log.2017-07-30.txt").map(
      line => {
        //解析字符串,找到jsp的名字
        //1、得到两个双引号的位置
        //192.168.88.1 - - [30/Jul/2017:12:53:43 +0800] "GET /MyDemoWeb/ HTTP/1.1" 200 259
        //192.168.88.1 - - [30/Jul/2017:12:54:37 +0800] "GET /MyDemoWeb/oracle.jsp HTTP/1.1" 200 242
        val index1 = line.indexOf("\"") //需要转义
        val index2 = line.lastIndexOf("\"")
        val line1 = line.substring(index1+1,index2)  //得到两个空格的位置 GET /MyDemoWeb/oracle.jsp HTTP/1.1
        val index3 = line1.indexOf(" ")
        val index4 = line1.lastIndexOf(" ")
        val line2 = line1.substring(index3+1,index4) //  /MyDemoWeb/oracle.jsp

        //得到jsp的名字
        val jspName = line2.substring(line2.lastIndexOf("/")+1) //得到xxx.jsp

        //返回
        (jspName,1)

        //("hadoop.jsp",1)
      }
    )
    //按照jsp的名字进行聚合操作 类似wordcount
    val rdd2 = rdd1.reduceByKey(_+_)

    //排序,按照value进行排序
    val rdd3 = rdd2.sortBy(_._2,false)
    //取出访问量最大的两个网页
    println("访问量最大的两个网页是:"+rdd3.take(2).toBuffer)
    sc.stop()
  }
}

案例二:分析tomcat的访问日志,根据网页的名字进行分区(类似MapReduce中的自定义分区)

	结果: 网页的名字    访问日志
	       oracle.jsp    192.168.88.1 - - [30/Jul/2017:12:54:37 +0800] "GET /MyDemoWeb/oracle.jsp HTTP/1.1" 200 242
           oracle.jsp    192.168.88.1 - - [30/Jul/2017:12:54:53 +0800] "GET /MyDemoWeb/oracle.jsp HTTP/1.1" 200 242

代码

package log
import org.apache.spark.{Partitioner, SparkConf, SparkContext}
import scala.collection.mutable.HashMap

object AnalizeLog {
  def main(args: Array[String]): Unit = {
    //创建一个Context对象
    val conf = new SparkConf().setAppName("MyTomcatLogCount").setMaster("local");
    val sc = new SparkContext(conf)

    /**
      *
      * 读入日志,解析每行日志,找到访问的jsp网页
      *
      * */
    val rdd1 =  sc.textFile("D:\\BigData\\sc\\localhost_access_log.2017-07-30.txt").map(
      line => {
        //解析字符串,找到jsp的名字
        //1、得到两个双引号的位置
        //192.168.88.1 - - [30/Jul/2017:12:53:43 +0800] "GET /MyDemoWeb/ HTTP/1.1" 200 259
        //192.168.88.1 - - [30/Jul/2017:12:54:37 +0800] "GET /MyDemoWeb/oracle.jsp HTTP/1.1" 200 242
        val index1 = line.indexOf("\"") //需要转义
        val index2 = line.lastIndexOf("\"")
        val line1 = line.substring(index1+1,index2)  //得到两个空格的位置 GET /MyDemoWeb/oracle.jsp HTTP/1.1
        val index3 = line1.indexOf(" ")
        val index4 = line1.lastIndexOf(" ")
        val line2 = line1.substring(index3+1,index4) //  /MyDemoWeb/oracle.jsp

        //得到jsp的名字
        val jspName = line2.substring(line2.lastIndexOf("/")+1) //得到xxx.jsp

        //返回
        (jspName,line)
      }
    )
    
    val rdd2 = rdd1.map(_._1).distinct().collect()//去重,聚合

    //创建分区规则
    val myPartitioner = new MyWebPartitioner(rdd2)

    //对rdd1 进行分区
    val rdd3 = rdd1.partitionBy(myPartitioner)

    //输出
    rdd3.saveAsTextFile("D:\\BigData\\sc\\tmp")
    sc.stop()

  }

  class  MyWebPartitioner(jspList:Array[String]) extends Partitioner{
    //定义一个集合来保存分区的条件
    //String :代表jsp的名字,Int 代表对应的分区号
    val partitionMap = new HashMap[String ,Int]()
    var partID = 0 //分区号
    for (jsp <- jspList){
      //有一个jsp 建立一个分区
      partitionMap.put(jsp,partID)

      partID += 1 //分区号
    }

    //返回多少个分区
    override def numPartitions: Int = partitionMap.size

    //根据jsp的名字,得到对应的分区
    override def getPartition(key: Any): Int = {
      partitionMap.getOrElse(key.toString,0)
    }
  }
}

使用JdbcRdd

package jdbcdemo
import java.sql.DriverManager
import org.apache.spark.rdd.JdbcRDD
import org.apache.spark.{SparkConf, SparkContext}
object MyMySQLJdbcRDD {
  //注册驱动,获取连接
  val connection = () =>{
    Class.forName("com.mysql.jdbc.Driver")
    DriverManager.getConnection("jdbc:mysql://10.1.255.130:3306/info","root","root")
  }

  def main(args: Array[String]): Unit = {
    //创建一个Context对象
    val conf = new SparkConf().setAppName("MyJdbcDriverLogCount").setMaster("local");
    val sc = new SparkContext(conf)
    //创建一个jdbc,执行查询
    val jdbcRDD = new JdbcRDD(sc,connection,"select * from student where sid > ? and sid <?",
      1,10,2,
      r=>{
        //create table student(sid int,sname varchar(5),age int);
        //返回学生的姓名
        val sname = r.getString(1)
        val sage = r.getString(2)
        (sname,sage)
      })
    val result = jdbcRDD.collect().toList
    println(result)
    sc.stop()
  }

}

操作数据库(在for循环里创建操作数据库对象)

package log
import java.sql.{Connection, DriverManager, PreparedStatement}
import org.apache.spark.{Partitioner, SparkConf, SparkContext}
import scala.collection.mutable.HashMap

object AnalizeLog {
  var count :Int = 0
  def main(args: Array[String]): Unit = {
    //创建一个Context对象
    val conf = new SparkConf().setAppName("MyTomcatLogCount").setMaster("local");
    val sc = new SparkContext(conf)

    /**
      *
      * 读入日志,解析每行日志,找到访问的jsp网页
      *
      **/
    val rdd1 = sc.textFile("D:\\BigData\\sc\\localhost_access_log.2017-07-30.txt").map(
      line => {
        //解析字符串,找到jsp的名字
        //1、得到两个双引号的位置
        //192.168.88.1 - - [30/Jul/2017:12:53:43 +0800] "GET /MyDemoWeb/ HTTP/1.1" 200 259
        //192.168.88.1 - - [30/Jul/2017:12:54:37 +0800] "GET /MyDemoWeb/oracle.jsp HTTP/1.1" 200 242
        val index1 = line.indexOf("\"") //需要转义
        val index2 = line.lastIndexOf("\"")
        val line1 = line.substring(index1 + 1, index2) //得到两个空格的位置 GET /MyDemoWeb/oracle.jsp HTTP/1.1
        val index3 = line1.indexOf(" ")
        val index4 = line1.lastIndexOf(" ")
        val line2 = line1.substring(index3 + 1, index4) //  /MyDemoWeb/oracle.jsp

        //得到jsp的名字
        val jspName = line2.substring(line2.lastIndexOf("/") + 1) //得到xxx.jsp

        //返回
        (jspName, line)
      }
    )

    val rdd2 = rdd1.map(_._1).distinct().collect() //去重,聚合

    //创建分区规则
    val myPartitioner = new MyWebPartitioner(rdd2)

    //对rdd1 进行分区
    val rdd3 = rdd1.partitionBy(myPartitioner)

    //输出
    // rdd3.saveAsTextFile("D:\\BigData\\sc\\tmp")

    //把每个数据写到mysql中

    //第一种修改方式
    rdd1.foreach(f => {
      var pst : PreparedStatement = null
      var connection: Connection = null
      try {
        //把Rdd1中的数据保存到Mysql,创建一个表 create table mydata(jsname varchar(40),countNumber varchar(500));
        connection= DriverManager.getConnection("jdbc:mysql://10.1.255.130:3306/info?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "root")
        pst = connection.prepareStatement("insert into mydata values(?,?)")

        pst.setString(1, f._1) //网页的名字
        pst.setString(2, f._2) //计一次数
        //执行
        pst.executeUpdate()
      }catch {
        case e1:Exception =>println("mysql操作错误 count:"+e1.printStackTrace())
      }finally {
        if(pst != null)pst.close()
        if(connection != null )connection.close()
      }
    })
    sc.stop()
  }

  class  MyWebPartitioner(jspList:Array[String]) extends Partitioner{
    //定义一个集合来保存分区的条件
    //String :代表jsp的名字,Int 代表对应的分区号
    val partitionMap = new HashMap[String ,Int]()
    var partID = 0 //分区号
    for (jsp <- jspList){
      //有一个jsp 建立一个分区
      partitionMap.put(jsp,partID)

      partID += 1 //分区号
    }

    //返回多少个分区
    override def numPartitions: Int = partitionMap.size

    //根据jsp的名字,得到对应的分区
    override def getPartition(key: Any): Int = {
      partitionMap.getOrElse(key.toString,0)
    }
  }
}

为了减少对象的创建

主函数添加

rdd1.foreachPartition(saveToOracle)
sc.stop()


//定义一个函数,针对分区进行操作,把分区中的数据保存到mysql中
  def saveToOracle(it:Iterator[(String ,Int)])={
    var pst : PreparedStatement = null
    var connection: Connection = null
    try {
      //把Rdd1中的数据保存到Mysql,创建一个表 create table mydata(jsname varchar(40),countNumber varchar(500));
      connection= DriverManager.getConnection("jdbc:mysql://10.1.255.130:3306/info?useUnicode=true&characterEncoding=utf-8&useSSL=false", "root", "root")
      pst = connection.prepareStatement("insert into mydata values(?,?)")

      //把分区中的元素保存到MySql
      it.foreach(data=>{
        pst.setString(1,data._1)
        pst.setInt(2,data._2)
        pst.executeUpdate()
      })
    }catch {
      case e1:Exception =>println("mysql操作错误 count:"+e1.printStackTrace())
    }finally {
      if(pst != null)pst.close()
      if(connection != null )connection.close()
    }
  }

案例三:把上面分析的结果,保存到Oracle中(知识点:在哪里建立Connection?): 对于非序列化的对象,如何处理?

1、create table result(jspname varchar2(20), count number);
2、开发JDBC程序(Scala),包含Oracle的驱动
3、操作RDD的时候,尽量针对分区,避免序列化问题

  • 6
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值