项目问题:布隆过滤器与kyro序列化

需求:

对用户日志数据标记用户是新用户还是老用户

方案:

由于用户量比较大,直接根据用户账号去匹配历史出现的用户,需要的内存比较大。此处使用布隆过滤器解决

布隆过滤器是一种以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

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值