Spark Core之ip地址分析

在互联网中,我们经常会见到城市热点图这样的报表数据,例如在百度统计中,会统计今年的热门旅游城市、热门报考学校等,会将这样的信息显示在热点图中。
在这里插入图片描述
因此,我们需要通过日志信息(运行商或者网站自己生成)和城市ip段信息来判断用户的ip段,统计热点经纬度。

ip日志信息
在ip日志信息中,我们只需要关心ip这一个维度就可以了,其他的不做介绍
在这里插入图片描述

城市ip段信息
在这里插入图片描述

思路
1、 加载城市ip段信息,获取ip起始数字和结束数字,经度,维度
2、 加载日志数据,获取ip信息,然后转换为数字,和ip段比较
3、 比较的时候采用二分法查找,找到对应的经度和维度
4、 然后对经度和维度做单词计数

代码如下

 //todo:创建sparkconf 设置参数
    val sparkConf: SparkConf = new SparkConf().setAppName("IPLocaltion").setMaster("local[2]")

    //todo:创建SparkContext
    val sc = new SparkContext(sparkConf)

    //todo:读取基站数据
    val data: RDD[String] = sc.textFile(args(0))

    //todo:对基站数据进行切分 ,获取需要的字段 (ipStart,ipEnd,城市位置,经度,纬度)
    val jizhanRDD = data.map(_.split("\\|")).map(
      x => (x(2), x(3), x(4) + "-" + x(5) + "-" + x(6) + "-" + x(7) + "-" + x(8), x(13), x(14)))

    //todo:获取RDD的数据
    val jizhanData = jizhanRDD.collect()

    //todo:广播变量,一个只读的数据区,所有的task都能读到的地方
    val jizhanBroadcast = sc.broadcast(jizhanData)

    //todo:读取目标数据
    val destData = sc.textFile("d:\\data\\ip.format")

    //todo:获取数据中的ip地址字段
    val ipData: RDD[String] = destData.map(_.split("\\|")).map(x=>x(1))

    //todo:把IP地址转化为long类型,然后通过二分法去基站数据中查找,找到的维度做wordCount

    val result=ipData.mapPartitions(iter=>{
      //获取广播变量中的值
      val valueArr = jizhanBroadcast.value

      //todo:操作分区中的itertator
      iter.map(ip=>{
        //将ip转化为数字long
        val ipNum:Long=ipToLong(ip)

        //拿这个数字long去基站数据中通过二分法查找,返回ip在valueArr中的下标
        val index:Int=binarySearch(ipNum,valueArr)

        //根据下标获取对一个的经纬度
        val tuple = valueArr(index)
        //返回结果 ((经度,维度),1)
        ((tuple._4,tuple._5),1)

      })

    })

    //todo:分组聚合
    val resultFinal: RDD[((String, String), Int)] = result.reduceByKey(_+_)

    //todo:打印输出
    resultFinal.foreach(tuple => println(tuple))

    //todo:将结果保存到mysql表中

    resultFinal.map(x=>(x._1._1,x._1._2,x._2)).foreachPartition(data2Mysql)
    sc.stop()

  }

  //todo:ip转为long类型
  def ipToLong(ip: String): Long = {
    //todo:切分ip地址。
    val ipArray: Array[String] = ip.split("\\.")
    var ipNum=0L

    for(i <- ipArray){
      ipNum=i.toLong | ipNum << 8L
    }
    ipNum
  }

  //todo:通过二分查找法,获取ip在广播变量中的下标
  def binarySearch(ipNum: Long, valueArr: Array[(String, String, String, String, String)]): Int ={

    //开始下标
    var start=0
    //结束下标
    var end=valueArr.length-1

    while(start<=end){
      val middle=(start+end)/2
      if(ipNum>=valueArr(middle)._1.toLong && ipNum<=valueArr(middle)._2.toLong){
        return middle
      }

      if(ipNum > valueArr(middle)._2.toLong){
        start=middle
      }

      if(ipNum<valueArr(middle)._1.toLong){
        end=middle
      }
    }

    -1
  }

  //todo:数据保存到mysql表中
  def data2Mysql(iterator:Iterator[(String,String, Int)]):Unit = {
    //todo:创建数据库连接Connection
    var conn:Connection=null
    //todo:创建PreparedStatement对象
    var ps:PreparedStatement=null
    //todo:采用拼占位符问号的方式写sql语句。
    var sql="insert into ip_location(longitude,latitude,total_count) values(?,?,?)"
    //todo:获取数据连接
    conn=DriverManager.getConnection("jdbc:mysql://hadoop-senior.test.com:3306/spark","root","123456")

    //todo:  选中想被try/catch包围的语句 ctrl+alt+t 快捷键选中try/catch/finally
    try {
      iterator.foreach(line=> {

        //todo:预编译sql语句
        ps = conn.prepareStatement(sql)

        //todo:对占位符设置值,占位符顺序从1开始,第一个参数是占位符的位置,第二个参数是占位符的值。
        ps.setString(1, line._1)
        ps.setString(2, line._2)
        ps.setLong(3, line._3)
        //todo:执行
        ps.execute()
      })
    } catch {
      case e:Exception =>println(e)
    } finally {
      if(ps!=null){
        ps.close()
      }
      if (conn!=null){
        conn.close()
      }
    }

  

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值