spark-core 实战 通过spark实现ip地址查询

spark-core 实战 通过spark实现ip地址查询

需求

在互联网中,我们经常会见到城市热点图这样的报表数据,例如在百度统计中,会统计今年的热门旅游城市、热门报考学校等,会将这样的信息显示在热点图中。

因此,我们需要通过日志信息(运行商或者网站自己生成)和城市ip段信息来判断用户的ip段,统计热点经纬度

日志信息介绍

涉及到两个文件ip.txt 和 20090121000132.394251.http.format

在这里插入图片描述

  • ip.txt 字段介绍
    • ip段起始位置 和 ip段结束位置
    • 起始ip地址hash 和 结束ip地址hash
    • 地址
    • 通信商
    • 邮编
    • 国家 和 国家缩写
    • 经纬度

在这里插入图片描述

  • 字段介绍
    • id
    • ip地址
    • 网址
    • 浏览器信息

思路

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

代码

#导入环境
import os
JAVA_HOME = '/root/bigdata/jdk'
PYSPARK_PYTHON = "/miniconda2/envs/py365/bin/python"
os.environ["PYSPARK_PYTHON"]= PYSPARK_PYTHON
os.environ["PYSPARK_DRIVER_PYTHON "]= PYSPARK_PYTHON
os.environ['JAVA_HOME'] = JAVA_HOME
from pyspark import SparkContext

#将ip转换为特殊的数字形式  223.243.0.0|223.243.191.255|  255 2^8
#‭11011111‬
#00000000
#1101111100000000
#‭        11110011‬
#11011111111100110000000000000000
def get_ip_hash(ip): 
	ans = 0
	ip_list = ip.split('.')
	for ip_num in ip_list:
		ans = int(ip_num) | ans<<8
	return ans

#二分法查找ip对呀的行索引
def binary_search(ip_num,cvb):
	start = 0
	end = len(cvb)-1
	while(start <= end):
		mid = int((start+end)/2)
		if(ip_num >= int(cvb[mid][0]) && ip_num <= int(cvb[mid][1])):
			return mid
		else if(ip_num< int(cvb[mid][0])):
			end = mid
		else
			start = mid

if __name__ == '__main__':
	#创建spark context 第一个参数master的位置 第二个参数为名称
	sc = SparkContext('loacl[2]','ipTopN')
	city_id_rdd = sc.textFile('file:///root/tmp/ip.txt').\
				map(lambda x:x.spilt('|')).\
				map(lambda x:x[2],x[3],x[13],x[14])
	dest_data = sc.textFile('file:///root/tmp/20090121000132.394251.http.format').\
				map(lambda x:x.spilt('|')[1])
	temp = city_id_rdd.collect()
	#创建广播变量,避免数据反复复制
	city_broadcast = sc.broadcast(temp)

	def get_pos(x):
		cvb = city_broadcast.value
		def get_result(ip):
			ip_num = get_ip_hash(ip)#取到IP地址hash
			index = binary_search(ip_num,cvb)#匹配IP库找到索引
			return ((cvb[index][2],cvb[index][3]),1) #返回经纬度
		result = map(tuple,[get_result(ip) for ip in x])
		return result
	# 用mappartition一部分一部分传给函数 减少连接资源的使用 反正频繁连接断开 
	data_rdd = dest_data.mappartition(lambda x:get_pos(x))#得到((经度,纬度),1)的集合
	# 相同经度纬度的合并并排序
	result_rdd = dest_data.reduceByKey(lambda a,b:a+b).sortby(lambda x:x[1],ascending=False)
	print(result_rdd.collect())

关键点

  1. 广播变量的使用
    • 要统计IP所对应的经纬度, 每一条数据都会去查询ip表
    • 每一个task 都需要这一个ip表, 默认情况下, 所有task都会去复制ip表(ip.txt)
    • 实际上 每一个Worker上会有多个task, 数据也是只需要进行查询操作的, 所以这份数据可以共享,没必要每个task复制一份
    • 可以通过广播变量, 通知当前worker上所有的task, 来共享这个数据,避免数据的多次复制,可以大大降低内存的开销
    • sparkContext.broadcast(要共享的数据)
  2. mapPartitions
    • transformation操作
    • 类似map 但是map是一条一条传给里面函数的 mapPartitions 数据是一部分一部分传给函数的
    • 应用场景 数据处理的时候 需要连接其它资源 如果一条一条处理 会处理一条连一次, 一份一份处理可以很多条数据连一次其它资源 可以提高效率
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值