SparkSQL自定义bitmap udf操作函数

本文介绍了如何将RoaringBitmap封装为SparkSQL的用户自定义函数(UDF),以实现精确的基数统计。通过源码实现,包括rbm_init、rbm_merge和rbm_cardinality三个函数,来处理和聚合bitmap数据。并在SparkSQL中展示了使用这些函数的示例。
摘要由CSDN通过智能技术生成

简介

Bitmap是用来实现基数统计的一种常用方法,它可以实现精确的基数统计。为了提高bitmap对稀疏位图的压缩率,提出了RoaringBitmap(RBM)对稀疏位图进行压缩,减少了内存占用并提高了使用效率。

在Java中实现RBM的常用库是RoaringBitmap,其已经在Spark、Kylin和Druid等系统中得到了应用。那是不是可以将RoaringBitmap库封装成SparkSQL的udf函数,从而可以对bitmap结构数据进行方便的计算操作,实现精确快速地基数统计。

源码实现

参考HLLFunctions的源码实现了三个函数功能:a. rbm_init,初始构造一个RoaringBitmap中间数据,其只支持对Int型的数据进行构建;b. rbm_merge,对rbm_init构造的中间数据进行聚合得到一个聚合后的中间数据;c. rbm_cardinality,求RoaringBitmap中间数据的基数值。

import java.io.{
  ByteArrayInputStream,
  ByteArrayOutputStream,
  DataInputStream,
  DataOutputStream
}

import org.apache.spark.sql.EncapsulationViolator.createAnalysisException
import org.apache.spark.sql.catalyst.{FunctionIdentifier, InternalRow}
import org.apache.spark.sql.catalyst.analysis.{
  FunctionRegistry,
  TypeCheckResult
}
import org.apache.spark.sql.catalyst.expressions.aggregate.{
  AggregateFunction,
  TypedImperativeAggregate
}
import org.apache.spark.sql.catalyst.expressions.codegen.CodegenFallback
import org.apache.spark.sql.catalyst.expressions.{
  ExpectsInputTypes,
  Expression,
  ExpressionDescription,
  ExpressionInfo,
  RuntimeReplaceable,
  UnaryExpression
}
import org.apache.spark.sql.functions.col
import org.apache.spark.sql.types._
import org.apache.spark.sql.{Column, SparkSession}
import org.roaringbitmap.RoaringBitmap

import scala.reflect.ClassTag
import scala.util.{Failure, Success, Try}

trait NullableSketchAggregation
    extends TypedImperativeAggregate[Option[RoaringBitmap]] {

  override def createAggregationBuffer(): Option[RoaringBitmap] = None

  override def merge(buffer: Option[RoaringBitmap],
                     other: Option[RoaringBitmap]): Option[RoaringBitmap] =
    (buffer, other) match {
      case (Some(a), Some(b)) =>
        a.or(b)
        Some(a)
      case (a, None) => a
      case (None, b) => b
      case _         => None
    }

  override def eval(buffer: Option[RoaringBitmap]): Any = {
    buffer
      .map(rbm => {
        val bos = new ByteArrayOutputStream
        rbm.serialize(new DataOutputStream(bos))
        bos.toByteArray
      })
      .orNull
  }

  def child: Expressio
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值