初衷
对数据库来说,满足业务多样化的查询方式非常重要。如果说有人设计了一个KV数据库,只提供了Get/Put/Scan这三种接口,估计要被用户吐槽到死,毕竟现实的业务场景并不简单。就以订单系统来说,查询给定用户最近三个月的历史订单,这里面的过滤条件就至少有2个:1. 查指定用户的订单;2. 订单必须是最近是三个月的。此外,这里的过滤条件还必须是用AND来连接的。如果通过Scan先把整个订单表信息加载到客户端,再按照条件过滤,这会给数据库系统造成极大压力。因此,在服务端实现一个数据过滤器是必须的。
除了上例查询需求,类似小明或小黄最近三个月的历史订单这样的查询需求,同样很常见。这两个查询需求,本质上前者是一个AND连接的多条件查询,后者是一个OR连接的多条件查询,现实场景中AND和OR混合连接的多条件查询需求也很多。因此,HBase设计了Filter以及用AND或OR来连接Filter的FilterList。
例如下面的过滤器,表示用户将读到rowkey以abc为前缀且值为testA的那些cell。
fl = new FilterList(MUST_PASS_ALL,
new PrefixFilter("abc"),
new ValueFilter(EQUAL, new BinaryComparator(Bytes.toBytes("testA"))))
实际上,FilterList内部的子Filter也可以是一个FilterList。例如下面过滤器表示用户将读到那些rowkey以abc为前缀且值为testA或testB的f列cell列表。
fl = new FilterList(MUST_PASS_ALL,
new PrefixFilter("abc"),
new FamilyFilter(EQUAL, new BinaryComparator(Bytes.toBytes("f"))),
new FilterList(MUST_PASS_ONE,
new ValueFilter(EQUAL, new BinaryComparator(Bytes.toBytes("testA"))),
new ValueFilter(EQUAL, new BinaryComparator(Bytes.toBytes("testB")))));
因此,FilterList的结构其实是一颗多叉树。每一个叶子节点都是一个具体的Filter,例如PrefixFilter、ValueFilter等;所有的非叶子节点都是一个FilterList,各个子树对应各自的子filter逻辑。对应的图示如下:
当然,HBase还提供了NOT语义的SkipFilter,例如用户想拿到那些rowkey以abc为前缀但value既不等于testA又不等于testB的f列的cell列表,可用如下FilterList来表示:
fl = new FilterList(MUST_PASS_ALL,
new PrefixFilter("abc"),
new FamilyFilter(EQUAL, new BinaryComparator("f")),
new SkipFilter(
new FilterList(MUST_PASS_ONE,
new ValueFilter(EQUAL, new BinaryComparator(Bytes.toBytes("testA"))),
new ValueFilter(EQUAL, new BinaryComparator(Bytes.toBytes("testB"))))));