HBase过滤器(二)

专用过滤器非常多,初学阶段我们不可能将所有的过滤器都掌握的非常清楚。我们只需要掌握常用的就可以,掌握了常用的过滤器,其他过滤器的使用也大同小异,所以其他的过滤器咱们大致了解就行。

前缀过滤器

前缀过滤器PrefixFilter,在构造过滤器时传入一个前缀,所有与前缀匹配的行都会被返回到客户端。该过滤器的构造函数如下:

public PrefixFilter(byte[] prefix)

使用过滤器返回行键前缀为row-1的数据:

Filter filter = new PrefixFilter(Bytes.toBytes("row-1"));
Scan scan = new Scan();
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for (Result result : scanner) {
        for(Cell cell : result.listCells()){
            String family = Bytes.toString(CellUtil.cloneFamily(cell));
            String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
            String value = Bytes.toString(CellUtil.cloneValue(cell));
            System.out.println(family + ":" + qualifier + " " + value);
            }
}
scanner.close();

这段代码搜索出来数据的行键都是以row-1开头的。

分页过滤器

我们知道如果数据库中有非常多的数据,比如100万条,一次性将所有数据全都查询出来肯定是不理智的,所以分页查询就很有必要了,分页查询也是最常用的查询方式之一。

分页过滤器PageFilter,是常用的过滤器之一,用户可以使用这个过滤器对结果进行分页。构造函数为:PageFilter(long pageSize)当用户创建当前过滤器实例时,需要指定pageSize参数,这个参数可以控制每页数据的行数

使用分页过滤器的时候客户端代码会记录本次扫描的最后一行,并在下一次获取数据时把记录的上次扫描的最后一行设为本次扫描的起始行,同时保留相同的过滤属性,然后依次进行迭代。

分页时对依次返回的行数设定了严格的限制,一次扫描所覆盖的行数很可能是多于分页大小的,一旦这种情况发生,过滤器有一种机制通知region服务器停止扫描。

接下来我们通过示例体验一下:

byte[] POSTFIX = new byte[] { 0x00 };
Table table = conn.getTable(tableName);
Filter filter = new PageFilter(15);//构建过滤器并设置每页数据量

int totalRows = 0;
byte[] lastRow = null;

while(true){
    Scan scan = new Scan();
    //添加过滤器
    scan.setFilter(filter);
    //设置查询的起始行
    if(lastRow != null){
          byte[] startRow = Bytes.add(lastRow, POSTFIX);
            System.out.println("start row: " +
                Bytes.toStringBinary(startRow));
        scan.withStartRow(startRow);
    }

    ResultScanner scanner = table.getScanner(scan);
    int localRows = 0;
    Result result;
    while ((result = scanner.next()) != null) {
        System.out.println(localRows++ + ": " + result);
            totalRows++;
            lastRow = result.getRow();
    }
    scanner.close();
    if (localRows == 0) break;
}

这样就能实现分页查询了。

列分页过滤器

列分页过滤器ColumnPaginationFilter,与PageFilter类似,这个过滤器可以对一行的所有列进行分页。它的构造器需要两个参数:

ColumnPaginationFilter(int limut,int offset)

它将跳过所有偏移量小于offset的列,并包括之后所有偏移量在limit之前(包含limit)的列。

我们来通过一个例子来了解一下如何使用:


Filter filter = new ColumnPaginationFilter(5,15);

Scan scan = new Scan();
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
for(Result result : scanner){
    System.out.println(result);
}


查询结果:

image.png
其他过滤器
过滤器 描述 构造函数
单列值过滤器 用一列的值决定是否一行数据被过滤 SingleColumnValueFilter(family, qualifier, op, value)
单列排除过滤器 查询的结果会排除,该过滤器设置的列 SingleColumnValueExcludeFilter(family, qualifier, op, value)
行键过滤器 可以通过convertTokeyOnly(boolean)方法帮助调用只返回键不返回值 KeyOnlyFilter(boolean lenAsVal)
首次行键过滤器 过如果用户需要访问同一行中的第一列,则这种过滤器可以满足需求 FirstKeyOnlyFilter()
包含结束的过滤器 扫描操作中的开始行被包含到结果中,但终止行被排除在外 InclusiveByteRange(Long first, Long last)
时间戳过滤器 当用户需要在扫描结果中对版本进行细粒度的控制时 TimeStampsFilter(List<Long>) timestamps
列计数过滤器 用户可以使用这个过滤器来限制每行最多取回多少列 ColumnCountGetFilter(int n)
列前缀过滤器 通过对列名称进行前缀匹配过滤 ColumnPrefixFilter(byte[] prefix)
随机行过滤器 可以让结果中包含随机航 RandomRowFilter(float chance)
跳转过滤器 可以过滤特定数据,当过滤器发现某一行中的一列需要过滤时,会过滤掉整行的数据 SkipFilter(Filter filter)

实际应用中用户可能需要多个过滤器共同限制返回到客户端的结果,我们应该怎么做呢?

FilterList

我们可以使用FilterList(过滤器列表)来组合多个过滤器,实现单个过滤器不能实现的功能。

过滤器列表提供了组合各个过滤器的功能。

与其他单一功能的过滤器一样,FilterList类实现了Filter接口,所以它可以通过组合多个过滤器的功能来实现某种效果。

要使用FilterList,我们需要先知道它有哪些构造方法:

FilterList(List<Filter> rowFilters)
FilterList(Operator operator)
FilterList(Operator operator,List<Filter> rowFilters)

参数rowFilters以列表的形式创建过滤器,参数operator(操作符)决定了组合他们的结果,第一个参数很简单,第二个参数我们没有见过,它总共有两种取值,默认值是MUST_PASS_ALL

FilterList.Operator 的可选枚举值

操作 描述
MUST_PASS_ALL 当所有过滤器都允许包含这个值时,这个值才会被包含在结果中,也就是说没有过滤器会忽略这个值
MUST_PASS_ONE 只要有一个过滤器允许包括这个值,那这个值就会包含在结果中

当我们创建了 FilterList 实例之后,可以用以下方法添加过滤器:

void addFilter(Filter filter)

每个FilterList只能添加一个操作符,但用户可以随意地向已经存在的FilterList实例中添加FilterList实例,这样可以构造一组多级的过滤器,同时它们可以与用户需要的操作符进行组合。

用户也可以通过控制List中过滤器的顺序来进一步精确地控制过滤器的执行顺序。例如,使用 ArrayList 可以保证过滤器的执行顺序与它们添加到列表中的顺序一致。

示例:

List<Filter> filters = new ArrayList<>();

Filter rowFilter1 = new RowFilter(CompareOperator.GREATER_OR_EQUAL,
        new BinaryComparator(Bytes.toBytes("row-3")));
filters.add(rowFilter1);

Filter rowFilter2 = new RowFilter(CompareOperator.LESS_OR_EQUAL, new BinaryComparator(Bytes.toBytes("row-6")));
filters.add(rowFilter2);

Filter rowFilter3 = new RowFilter(CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("row-3")));
filters.add(rowFilter3);

FilterList filterList1 = new FilterList(filters);

Scan scan = new Scan();

scan.setFilter(filterList1);

ResultScanner scanner = table.getScanner(scan);

for (Result result : scanner) {
    for(Cell cell : result.listCells()){
        String family = Bytes.toString(CellUtil.cloneFamily(cell));
        String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
        String value = Bytes.toString(CellUtil.cloneValue(cell));
        System.out.println("\t" + family + ":" + qualifier + " " + value);
    }
}

scanner.close();

FilterList filterList2 = new FilterList(FilterList.Operator.MUST_PASS_ONE,filters);

scan.setFilter(filterList2);

ResultScanner scanner2 = table.getScanner(scan);

for (Result result : scanner2) {
    for(Cell cell : result.listCells()){
        String family = Bytes.toString(CellUtil.cloneFamily(cell));
        String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
        String value = Bytes.toString(CellUtil.cloneValue(cell));
        System.out.println("\t" + family + ":" + qualifier + " " + value);
    }
}

conn.close();


第一个扫描中的过滤器过滤了许多数据,正是由于列表中任意一个过滤器过滤了该数据,该数据就会被丢弃,只有当数据经过了所有过滤器的筛选才会被传回客户端。

第一种模式(MUST_PASS_ALL)的FilterList的作用可以类比净水器的滤芯。

image.png

数据必须通过所有滤网才能到达客户端。

第二种模式(MUST_PASS_ONE)的FilterList允许数据只需要通过一种过滤器的过滤就可以被返回。

执行上述代码我们会发现,使用filterList1扫描不到任何结果,而使用filterList2,却可以扫描到表中所有的数据(假设表的数据是从row-0 - row-100),是为什么呢? 需要自己思考哦。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,802评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,109评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,683评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,458评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,452评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,505评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,901评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,550评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,763评论 1 296
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,556评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,629评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,330评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,898评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,897评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,140评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,807评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,339评论 2 342

推荐阅读更多精彩内容