需求:
对用户日志数据标记用户是新用户还是老用户
方案:
由于用户量比较大,直接根据用户账号去匹配历史出现的用户,需要的内存比较大。此处使用布隆过滤器解决
布隆过滤器是一种以bitmap集合为基础的排重算法,用来判断一个字符串是否存在于一个集合中(有一定的误判率,有可能出现不存在判断成存在),占用内存较小
代码:
测试代码:
import org.apache.hadoop.util.bloom.{BloomFilter, Key}
import org.apache.hadoop.util.hash.Hash
object BloomFilterTest {
def main(args: Array[String]): Unit = {
/**
* 参数1,布隆过滤器容量长度
* 参数2,hash算法个数
* 参数3,hash算法类型
*/
val filter = new BloomFilter(200000000, 3, Hash.MURMUR_HASH)
filter.add(new Key("aaa".getBytes()))
filter.add(new Key("bbb".getBytes()))
filter.add(new Key("ccc".getBytes()))
filter.add(new Key("ee".getBytes()))
println(filter.membershipTest(new Key("aaa".getBytes()))) //true
}
}
正式代码:
import org.apache.hadoop.util.bloom.{BloomFilter, Key}
import org.apache.spark.SparkConf
import org.apache.spark.sql.SparkSession
object SparkBloomFilter {
def main(args: Array[String]): Unit = {
val conf = new SparkConf()
val spark = SparkSession.builder().config(conf)
.appName("判断新老访客")
.master("local")
.getOrCreate()
import spark.implicits._
// 加载历史上出现过的所有deviceid
val his = spark.createDataset(Seq("deviceid_01", "deviceid_05", "deviceid_15", "deviceid_35", "deviceid_66"))
// 收集历史id数据到driver段
val hisIds = his.collect()
val filter = new BloomFilter(200000000, 4, 1)
for(id <- hisIds){
filter.add(new Key(id.getBytes()))
}
// 广播
val bc = spark.sparkContext.broadcast(filter)
// 处理当天日志,标记新老访客
val log = spark.createDataset(Seq("deviceid_01", "deviceid_05", "deviceid_15", "deviceid_25", "deviceid_16"))
val res = log.map(s=>{
val f = bc.value
var isnew = 1
if(f.membershipTest(new Key(s.getBytes()))) isnew = 0
(s,isnew)
}).toDF("device_id","isnew")
res.show(100,false)
spark.close()
}
}
运行后报错:
布隆过滤器未序列化
此处使用kryo序列化
解决代码:conf设置kryo序列化
val conf = new SparkConf()
// 如果不设置,那么spark默认使用jdk的序列化器(ObjectOutputStream,而这个类对被序列化的对象要求实现Serializable标记接口)
conf.set("spark.serializer","org.apache.spark.serializer.KryoSerializer")
// 如果显式注册了需要用kryo序列化的类型,那么kryo在序列化对象时,不需要为每个对象都带上类的元信息,效率更高
conf.registerKryoClasses(Array(classOf[BloomFilter]))
布隆过滤器误判率计算公式:
布隆过滤器参考链接:https://zhuanlan.zhihu.com/p/72378274