package com.spark.core
import java.sql.{Connection, DriverManager, PreparedStatement}
import org.apache.spark.rdd.RDD
import org.apache.spark.{SparkConf, SparkContext}
/**
* ip地址查询
*/
object IPLocation {
System.setProperty("hadoop.home.dir","D:\\soft\\hadoop\\hadoop-2.9.2")
def main(args: Array[String]): Unit = {
//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("G:\\data\\ip.txt")
//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("G:\\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://star.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()
}
}
}
}
Spark 的IP 地址查询
最新推荐文章于 2021-10-22 22:28:30 发布