HBase自定义过滤器

本文最新更新, 请访问作者个人主页, 后续也会更新一些HBase高级特性相关的文章.

本文首先结合HBase过滤器部分的源码, 讲述HBase过滤器抽象基类Filter中各个函数的作用. 最终给出一个简单的自定义过滤器的案例, 在此基础上分析了Filter中各个方法的执行流程, 读者在理解该案例的基础上可以编写任何个性化的过滤器. 本文涉及的源码基于HBase 1.4.x这一Stable Release版本. 为方便读者复现本文的案例, 相关代码已经发布到GitHub, 连接可由本人个人主页中获取.

HBase自定义过滤器能够在RegionServer上, 执行更加复杂和个性化的过滤操作. 例如, 在利用HBase存储时空数据时, 可以将时空范围的过滤操作放到过滤器中. 使用过滤器主要有以下两个优点: 一是通过使用过滤器将过滤逻辑放到RegionServer上执行, 可以使客户端代码更加简洁; 二是将过滤操作放到RegionServer上执行可以减少网络传输, 提升查询效率. 当然, 使用自定义过滤器也存在一定的缺点: 过滤器对象需要在HBase的Client和RegionServer之间通过网络传输, 对于用户自定义过滤器, 需要重写序列化和反序列化操作, 不同于Go语言, Java语言并没有提供原生的高效序列化支持, HBase预定义的过滤器使用了Protocol Buffers进行序列化与反序列化. 本文给出的案例使用了Java的NIO进行自定义过滤器对象的序列化和反序列化, 在生产环境中建议使用Protocol Buffers.

HBse自定义过滤器概览

HBase过滤器属于客户端API, 相关的源码均在hbase-client模块的org.apache.hadoop.hbase.filter包下. 对于设定了过滤器的scan, 在每个Region上过滤器都会起作用.

自定义HBase过滤器需要继承抽象类Filter或抽象类FilterBase. Filter是FilterBase的基类, FilterBase为我们提供了一些方法的默认实现, 在自定义过滤器时可先继承FilterBase, 实现其抽象方法, 在需要更进一步的个性化操作时再考虑按需实现Filter提供的方法. 为了更好的演示Filter中各个方法的作用, 本文的案例在实现时继承了抽象类Filter.

在具体探讨HBase过滤器之前, 我们将首先探讨抽象类Filter中各个函数的作用, 理解这些函数的具体作用是我们进行后续研究的基础. 类Filter的定义如下, 这里为每个属性和函数添加了详细的注释, 解释其作用.

public abstract class Filter {
   
  /**
   * 是否逆序扫描的标志. true表示当前以字节序从大到小扫描, false表示当前以字节序从小到大扫描.
   */
  protected transient boolean reversed;

  /**
   * 在每行扫描结束时调用, 一般用于重置过滤标志
   */
  abstract public void reset() throws IOException;

  /**
   * 真正开始过滤的第一步, 用于对row key进行过滤. 若过滤当前行, 返回true, 若保留当前行返回false.
   * @param buffer 包含row key的字节数组
   * @param offset row key在buffer数组中的开始位置
   * @param length row key的长度
   */
  abstract public boolean filterRowKey(byte[] buffer, int offset, int length) 
  throws IOException;

  /**
   * 用于判断是否需要继续进行过滤操作, 在调用filterRowKey(), filterKeyValue(), transformCell(),
   * reset()函数之后都会调用. 返回true表示不需要继续进行过滤, 将结束包含当前过滤器的scan操作, 
   * 返回false表示需要继续进行后续过滤操作. 
   */
  abstract public boolean filterAllRemaining() throws IOException;

  /**
   * 真正开始过滤的第二步, 用于对每个cell进行过滤, 其返回值的含义参考枚举ReturnCode
   * @param v 当前行中的每个cell
   */
  abstract public ReturnCode filterKeyValue(final Cell v) throws IOException;

  /**
   * 对于filterKeyValue()中通过的cell调用, 用于对cell进行一定的转换操作, 一般直接返回传入的参数即可
   * @param v 经过filterKeyValue()决定保留的cell
   */
  abstract public Cell transformCell(final Cell v) throws IOException;

  /**
   * 弃用, 使用transformCell()代替
   */
  @Deprecated
  abstract public KeyValue transform(final KeyValue currentKV) throws IOException;
 
  public enum ReturnCode {
   
    // 包含当前cell
    INCLUDE,
    // 包含当前cell, 查询下一列
    INCLUDE_AND_NEXT_COL, // 与INCLUDE的区别是会忽略旧版本数据
    // 跳过当前cell
    SKIP,
    // 跳过当前列, 查询当前行的下一列
    NEXT_COL, // 与SKIP仅有细微差别, 如果序遍历所有列使用NEXT_COL, 如果不需要查询当前cell之后的列使用SKIP
    // 查询当前column family中的下一行. 注意: 当前行的其他column family在之后仍可能被查询
    NEXT_ROW,
    // 调用getNextCellHint()决定下一个需要查询的cell
    SEEK_NEXT_USING_HINT,
    // 包含当前cell并查询下一行, 当前行中所有剩余的cell都将不会被查询
    INCLUDE_AND_SEEK_NEXT_ROW,
  }

  /**
   * 对该函数的具体作用尚未完全明了. 根据源码中的解释, 该函数是对需要提交的的cell进行进行原地更改.
   * 一般情况下无需重载该函数.
   */
  abstract public void filterRowCells(List<Cell> kvs) throws IOException;

  /**
   * 主要用于检查冲突的scans(例如不一次读取整行的scan)
   */
  abstract public boolean hasFilterRow();

  /**
   * 最后用于决定是否过滤当前行的机会, 若返回true过滤当前行, 否则保留当前行
   */
  abstract public boolean filterRow() throws IOException;

  /**
   * 弃用, 使用getNextCellHint()代替
   */
  @Deprecated
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值