【spark】三 python 用RDD.reduceByKey 方法实现 count(value),count(distinct value) [待验证]

版权声明:转载请标明出处。 https://blog.csdn.net/u010720408/article/details/89363089

需求

zeppelin的pyspark中 DataFrame.groupBy(*cols).agg()操作大数据量会爆内存。
推荐用RDD.reduceByKey()但是这个只能对两列,以第一列为key,第二列为value。
而且在同一个task上,同partition的数据先是同key的valfue进行合并操作,以此大大减少后面shuff的数据量。
本来想实现select groupkey,count(value),count(distinct value) from table group by groupkey的sql语句,
但是spark-sql机制跟dataframe/rdd操作不一样,调优也是各种问题导致失败;
只得用dataframe的算子,但是到了数据量太大,groupby也是不行;
只得再想办法用RDD.reduceByKey

网上全是千篇一律的operator.add 操作,然后发现operator是一个运算模块,根本不是给PipelinedRDD的配套运算

实现 select key,count(value) from table group by key

rdd = sc.parallelize(List(("0", "v1"), ("0", "v2"), ("1", "v1"), (2, "v2")), 2)
result=rdd.countByKey()
print(result)

defaultdict(<type 'int'>, {u'2': 1, u'1': 1, u'0': 2})

注意:结果是是defaultdict,是输入的是两列,内部调用的是x[0].countByValue() ,即对相同key计算值出现总个数countByValue

经一亿条数据测试,countByKey()还是会内存不够,跟reduceByKey不同,换一种实现思路:

from operation import *
sc.parallelize(List((“0”, “v1”), (“0”, “v2”), (“1”, “v1”), (2, “v2”)), 2).toDF([“key”,“value”]).rdd.mapPartitions(lamdba x:(x[0],1)).reduceByKey(add).toDF([“key”,“value”]).show(20,False) ==
== 实现同样的countByKey功能,内存占用因为merge大大减少,语句中间写了不少废操作,也只是DataFrame与RDD/PipelinedRDD间的转化而已,练习可以拆开使用查看变化

实现 select key,count(distinct value) from table group by key

法一 已实验:#基于两列的rdd直接distinct去除重复行,再统计相同key个数,就是不同的value个数了
rdd.distinct().countBuKey() 
==同样亿级数据 也要转换成reduceByKey(add)操作==

法二:未测试
	rdd.map { row => (row.groupbykey, row.value) }
	.distinct()
	.map { line => (line._1, 1) }
	.reduceByKey(_ + _)

法二: 未测试
rdd.map { row => (row.groupbykey, row.value) }
	.distinct()
	.mapValues{ _ => 1 }
	.reduceByKey(_ + _)

法三:未测试
rdd.map { row => (row.groupbykey, row.value) }
	.distinct()
	.map(_._1)
	.countByValue()

数据量大考虑使用dataframe.repartition(num).rdd.mapPartitions(lambda x:(x[0],x[1])).distinct().countByKey()实现

mapPartitons区别于map,map会foreach每一行,而mapPartitons则是分布式按分区每一个partition自己去map操作自己数据,提高效率

非精确实现 select key,count (distinct value) from table group by key

基于HyperLogLog算法,海量数据非精确场景下使用

rdd.map { row => (row.groupbykey, row.value) }
	.countApproxDistinctByKey(0.001)

0.001表示精确度,越小越准确,应该是千分之一误差的意思

猜你喜欢

转载自blog.csdn.net/u010720408/article/details/89363089