表中数据
hbase(main):018:0> scan 'test'
ROW COLUMN+CELL row1 column=cf:name, timestamp=1544414130937, value=tom row2 column=cf:name, timestamp=1544414140380, value=jon row3 column=cf:name, timestamp=1544414146003, value=wang row4 column=cf:name, timestamp=1544414151373, value=qiang row5 column=cf:name, timestamp=1544414159901, value=sam
5 row(s)
Took 0.0470 seconds
要求挑选出name中带a字母的name
public void valueFilter() throws IOException {
Connection connection = ConnectionFactory.createConnection();
Table table = connection.getTable(TableName.valueOf("default:test"));
Scan scan = new Scan();
//值过滤器
ValueFilter filter = new ValueFilter(CompareOperator.EQUAL, new SubstringComparator("a"));
scan.setFilter(filter);
ResultScanner results = table.getScanner(scan);
for (Result result : results) {
String value = Bytes.toString(result.getValue(Bytes.toBytes("cf"), Bytes.toBytes("name")));
System.out.println(value);
}
table.close();
connection.close();
}
结果
wang
qiang
sam
对于CompareOperator.EQUAL中的枚举有如下几个
LESS, 小于
/** less than or equal to */
LESS_OR_EQUAL, 小于或者等于
/** equals */
EQUAL, 等于
/** not equal */
NOT_EQUAL, 不等于
/** greater than or equal to */
GREATER_OR_EQUAL, 大于等于
/** greater than */
GREATER, 大于
/** no operation */
NO_OP, 无操作
这个代码比较了所有cell的value,当前只是有一个name列,如果在添加一个其他列是什么情况呢
hbase(main):019:0> put 'test','row1','cf:tmp','aaa'
再次扫描的结果
null
wang
qiang
sam
重复代码就不贴了,只需要将Filter换为SingleColumnValueFilter即可
SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("name"),
CompareOperator.EQUAL, new SubstringComparator("a"));
结果
wang
qiang
sam
要求,查找出name为wang的行,即name='wang'
SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("name"),
CompareOperator.EQUAL, new BinaryComparator(Bytes.toBytes("wang")));
我们已经清楚了,在HBase中是按字节比较的,我们表中的name按字典排序应该是这样的
jon
qiang
sam
tom
wang
所以现在的需求是取出大于som的即将比较枚举换为GREATER,然后结果为tom
和wang
SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("name"),
CompareOperator.GREATER, new BinaryComparator(Bytes.toBytes("som")));
之前我们操作过当使用HBase的shell保存数字的时候,他其实是按字符串保存进去的,如果你想保存真正的数字,就使用api,在使用api保存后,我们看到数字已经是一堆乱码了,其实这是数字保存为字节数组后的结果,所以如果我们要比较数字首先确保整个数字是按数字类型保存的,之后再使用BinaryComparator比较即可
Filter filter = new SingleColumnValueFilter(Bytes.toBytes("cf"),Bytes.toBytes("age"),
CompareOperator.GREATER,new BinaryComparator(Bytes.toBytes(15)));
HBase只能实现SQL中的limit的功能,如下代码
public void pageFilter() throws IOException {
Connection connection = ConnectionFactory.createConnection();
Table table = connection.getTable(TableName.valueOf("test"));
Scan scan = new Scan();
//设置分页大小
Filter filter = new PageFilter(2);
scan.setFilter(filter);
ResultScanner results = table.getScanner(scan);
for (Result result : results) {
for (Cell cell : result.listCells()) {
System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
}
}
table.close();
connection.close();
}
如果想实现limit n,n功能的话,只能是保存上一页中最后一个rowkey,然后从此rowkey的下一个开始扫描,比如这样
public void pageFilter() throws IOException {
...
byte[] rowkey = null;
for (Result result : results) {
for (Cell cell : result.listCells()) {
System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
rowkey = CellUtil.cloneRow(cell);
}
}
System.out.println("************************");
scan.withStartRow(Bytes.add(rowkey,new byte[1])); //这里设置了下一次的scan的起始key
ResultScanner results1 = table.getScanner(scan);
for (Result result : results1) {
for (Cell cell : result.listCells()) {
System.out.println(Bytes.toString(CellUtil.cloneValue(cell)));
}
}
...
}
要求过滤包含w子串的并取前两个结果显示,这很明显是单列过滤+分页显示
...
SingleColumnValueFilter filter = new SingleColumnValueFilter(Bytes.toBytes("cf"), Bytes.toBytes("name"), CompareOperator.EQUAL, new SubstringComparator("w"));
PageFilter pageFilter = new PageFilter(2);
FilterList list = new FilterList();
list.addFilter(pageFilter);
list.addFilter(filter);
scan.setFilter(list);
...
FilterList.Operator中包含两个枚举
public enum Operator {
/** !AND */
MUST_PASS_ALL,
/** !OR */
MUST_PASS_ONE
}
他们用在FilterList创建的对象的时候,比如
FilterList list = new FilterList(FilterList.Operator.MUST_PASS_ONE);
如何实现(1 and 2) or 3
的效果呢,我们可以将(1 and 2)
看做是一个过滤器集合,然后or 3
是一个,所以实现方式就是FilterList嵌套就好了
FilterList or = new FilterList(FilterList.Operator.MUST_PASS_ONE);
FilterList and = new FilterList(FilterList.Operator.MUST_PASS_ALL,or);
public void test() throws IOException {
// 表中列active=1并且名字包含wang的,或者名字中包含s的
Connection connection = ConnectionFactory.createConnection();
//包含wang的
SingleColumnValueFilter wangFilter = new SingleColumnValueFilter(Bytes.toBytes("cf"),
Bytes.toBytes("name"),CompareOperator.EQUAL,new SubstringComparator("Wang"));
//active==1的
SingleColumnValueFilter activeFilter = new SingleColumnValueFilter(Bytes.toBytes("cf"),
Bytes.toBytes("active"),CompareOperator.EQUAL,new BinaryComparator(Bytes.toBytes("1")));
//两个条件必须全部满足
FilterList one = new FilterList(FilterList.Operator.MUST_PASS_ALL);
one.addFilter(wangFilter);
one.addFilter(activeFilter);
//名字带s
SingleColumnValueFilter sFilter = new SingleColumnValueFilter(Bytes.toBytes("cf"),
Bytes.toBytes("name"),CompareOperator.EQUAL,new SubstringComparator("s"));
FilterList two = new FilterList();
two.addFilter(sFilter);
//两个过滤器是满足其中一个就好
FilterList three = new FilterList(FilterList.Operator.MUST_PASS_ONE,one,two);
Scan scan = new Scan();
scan.setFilter(three);
ResultScanner results = connection.getTable(TableName.valueOf("test")).getScanner(scan);
//正确结果是:名字带wang并且active==1 或者是名字带s,active没要求
for (Result result : results) {
for (Cell cell : result.listCells()) {
System.out.println(Bytes.toString(CellUtil.cloneRow(cell))+"=>"+
Bytes.toString(CellUtil.cloneQualifier(cell))+"=>"+Bytes.toString(CellUtil.cloneValue(cell)));
}
}
connection.close();
}
结果
row1=>active=>1
row1=>name=>billyWangpaul
row2=>active=>1
row2=>name=>sara
row3=>active=>0
row3=>name=>chris
row5=>active=>1
row5=>name=>andyWang
找出大于row3的行
RowFilter filter = new RowFilter(CompareOperator.GREATER,new BinaryComparator(Bytes.toBytes("row3")));
还有多范围行键过滤,即row1到row3和row5到row6之间的值
MultiRowRangeFilter.RowRange rowRange1 = new MultiRowRangeFilter.RowRange("row1",true,"row3",false);
MultiRowRangeFilter.RowRange rowRange2 = new MultiRowRangeFilter.RowRange("row4",true,"row6",false);
List rowRanges = Arrays.asList(rowRange1, rowRange2);
MultiRowRangeFilter filter = new MultiRowRangeFilter(rowRanges);
Scan scan = new Scan();
scan.setFilter(filter);
可以匹配行键前缀,现在表中的行键都是rowX,我们把它都扫描出来
PrefixFilter filter = new PrefixFilter(Bytes.toBytes("row"));
下面是一种rowkey的格式,2016年6月22日去了北京
2016_06_22_beijing
要求查找2016年什么时间去北京了和2012年什么时间去干什么了
Pair par1 = new Pair<>(Bytes.toBytes("2016_??_??_beijing"),new byte[]{
0,0,0,0,0,1,1,0,1,1,0,0,0,0,0,0,0,0
});
Pair par2 = new Pair<>(Bytes.toBytes("2012"),new byte[]{
0,0,0,0
});
List> fuzzy = Arrays.asList(par1,par2);
FuzzyRowFilter filter = new FuzzyRowFilter(fuzzy);
Scan scan = new Scan();
scan.setFilter(filter);
上面的Pair有两部分构成,一个是行键,一个行键掩码fuzzy info
使用scan返回的结果集并不会返回终止行,如果想返回终止行数据,可以在终止行rowkey上加一个字节的数据,然后作为stoprow的条件,或者使用这次介绍的过滤器
InclusiveStopFilter filter = new InclusiveStopFilter(Bytes.toBytes("2016_08_15_beijing"));
更简单的方式是在设置结束行键的时候指定一下参数
scan.withStopRow(Bytes.toBytes("2016_08_15_beijing"),true);
即抽取一部分数据的时候用
RandomRowFilter filter = new RandomRowFilter(0.5F);
即将符合规则的列族放入结果集,使用很简单
FamilyFilter filter = new FamilyFilter(CompareOperator.EQUAL,new BinaryComparator(Bytes.toBytes("cf")));
即将符合规则的列放入结果集
QualifierFilter filter = new QualifierFilter(CompareOperator.EQUAL,new BinaryComparator(Bytes.toBytes("namex")));
首先准备数据
Put put = new Put(Bytes.toBytes("row1")).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("name"), Bytes.toBytes("w1"))
.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("age"), Bytes.toBytes("14"));
Put put1 = new Put(Bytes.toBytes("row2")).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("name"), Bytes.toBytes("w2"))
.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("age"), Bytes.toBytes("23"));
然后我们使用这个过滤器,指定依赖的列为name
DependentColumnFilter filter = new DependentColumnFilter(Bytes.toBytes("cf"),Bytes.toBytes("name"));
结果
row1=>14
row1=>w1
row2=>23
row2=>w2
然后我们从新put一下row1的age,以更新age列的timestamp
hbase(main):014:0> put 'test','row1','cf:age','14'
所以现在row1的name列的时间戳是最新的,然后在执行这个过滤器
row1=>w1
row2=>23
row2=>w2
我们发现就只剩下了name列返回了,而row2是不受影响的,因为我们并没有改变row2的数据的时间戳,到这就可以知道了,这个过滤器是指定一行中的列,用指定的列的时间戳去比较这一行的其他列,如果时间戳一样就返回,否则就不返回,为了证明这一点,我们继续,这次将row1的name和age再从新put,设置为同一时间戳,用api更新
Put put = new Put(Bytes.toBytes("row1")).addColumn(Bytes.toBytes("cf"), Bytes.toBytes("name"), Bytes.toBytes("w1"))
.addColumn(Bytes.toBytes("cf"), Bytes.toBytes("age"), Bytes.toBytes("14"));
然后在执行这个过滤器,刚才消失的age就又出现了
row1=>14
row1=>w1
row2=>23
row2=>w2
过滤列前缀为ag的cell
ColumnPrefixFilter filter = new ColumnPrefixFilter(Bytes.toBytes("ag"));
跟多行区间过滤一样的,过滤多个列,下面是使用
byte[][] bytes = {Bytes.toBytes("age"),Bytes.toBytes("name")};
MultipleColumnPrefixFilter filter = new MultipleColumnPrefixFilter(bytes);
这个过滤器不过滤数据,只是把列名拿出来
KeyOnlyFilter filter = new KeyOnlyFilter();
求这个表中一共有多少行
FirstKeyOnlyFilter filter = new FirstKeyOnlyFilter();
跟过滤rowkey的范围一样,就是指定一下最小列名和最大列名就可以,然后取出给出范围内的列名,如果最小列名为ab,最大的为ad,那么ac,abc都可以被取出,而ag不可以
ColumnRangeFilter filter = new ColumnRangeFilter(Bytes.toBytes("ab"),true,Bytes.toBytes("ad"),false);
上面的过滤器都是针对scan使用的,而这个是用于get的,用处是取前n个列的值
...
ColumnCountGetFilter filter = new ColumnCountGetFilter(1);
Table table = connection.getTable(TableName.valueOf("test"));
Get get1 = new Get(Bytes.toBytes("row1"));
get1.setFilter(filter);
Get get2 = new Get(Bytes.toBytes("row2"));
get2.setFilter(filter);
List list = Arrays.asList(get1,get2);
Result[] result = table.get(list);
...
这个也是用于get的,是取一行列的范围的,比如第2列到第4列
ColumnPaginationFilter filter = new ColumnPaginationFilter(2,2);
这个过滤器同样适用get和scan,他的构造参数并不是时间戳的区间范围,而是准确值,所以这个过滤器更适合timestamp是自定义的情况
List list = Arrays.asList(1544512482917L,1544507404825L);
TimestampsFilter filter = new TimestampsFilter(list);
跳转过滤器SkipFilter
ValueFilter valueFilter = new ValueFilter(CompareOperator.NOT_EQUAL,new BinaryComparator(Bytes.toBytes("14")));
SkipFilter filter = new SkipFilter(valueFilter);
scan.setFilter(filter);
全匹配过滤器WhileMatchFilter
RowFilter filter = new RowFilter(CompareOperator.NOT_EQUAL,new BinaryComparator(Bytes.toBytes("row3")));
scan.setFilter(filter);
row1=>150
row2=>23
row2=>w2
row4=>w4
RowFilter filter = new RowFilter(CompareOperator.NOT_EQUAL,new BinaryComparator(Bytes.toBytes("row3")));
WhileMatchFilter whileMatchFilter = new WhileMatchFilter(filter);
scan.setFilter(whileMatchFilter);
row1=>14
row1=>nan
row1=>xx14
row1=>w1
row1=>150
row2=>23
row2=>w2