HBase版本:hbase-1.2.6
现有hbase表"user"如下:
我们知道,在对Hbase表中的数据进行全表扫描时,可以指定rowkey的范围,比如:
public static void main(String[] args) throws Exception {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "192.168.21.100:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("user"));
Scan scan = new Scan();
scan.setStartRow(Bytes.toBytes("0001"));
scan.setStopRow(Bytes.toBytes("0005"));
ResultScanner scanner = table.getScanner(scan);
HBasePrintUtil.printResultScanner(scanner);
}
这样查询出来的结果为:
0001 cf1 name 1515064512439 Jed
0002 cf1 name 1515064824770 Aiden
0003 cf1 name 1515064825023 Jacob
0004 cf1 name 1515064825025 Ethan
现在的需求是,我指定 StartRow 和 StopRow后,可以得到包括 StopRow 在内的那些行的记录,即:
0001 cf1 name 1515064512439 Jed
0002 cf1 name 1515064824770 Aiden
0003 cf1 name 1515064825023 Jacob
0004 cf1 name 1515064825025 Ethan
0005 cf1 name 1515064825034 Matthew
有这么一种想法,我要取0001-0005的记录,我写成0001-0006不就可以了吗?问题是,在大数据量的表中,你不能这么直观的看出一个rowkey的下一个rowkey是什么,例如我们这张表,0005的下一列rowkey是0005001,如果你事先不知道有这样一个rowkey的存在,把 StopRow设置为0006,那么得到结果是:
0001 cf1 name 1515064512439 Jed
0002 cf1 name 1515064824770 Aiden
0003 cf1 name 1515064825023 Jacob
0004 cf1 name 1515064825025 Ethan
0005 cf1:name 1515064825034 Matthew
0005001 cf1:name 1515064934573 value=Benjamin
这样还是没有实现我们的需求,指定 StartRow 和 StopRow后,可以得到包括 StopRow 在内的那些行的记录
实现思路:
代码:
public static void main(String[] args) throws Exception {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "192.168.21.100:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("user"));
Scan scan = new Scan();
scan.setStartRow(Bytes.toBytes("0001"));
byte[] StopRow = Bytes.toBytes("0005");
byte[] StopRowExtended = Bytes.add(StopRow, new byte[]{0X00});
scan.setStopRow(StopRowExtended);
ResultScanner scanner = table.getScanner(scan);
HBasePrintUtil.printResultScanner(scanner);
}
结果:
0001 cf1 name 1515064512439 Jed
0002 cf1 name 1515064824770 Aiden
0003 cf1 name 1515064825023 Jacob
0004 cf1 name 1515064825025 Ethan
0005 cf1 name 1515064825034 Matthew
HBase Java API 提供了分页过滤器的操作,如下
public static void main(String[] args) throws Exception {
Configuration conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", "192.168.21.100:2181");
Connection conn = ConnectionFactory.createConnection(conf);
Table table = conn.getTable(TableName.valueOf("user"));
Scan scan = new Scan();
// 设置起始rowkey
scan.setStartRow(Bytes.toBytes("0004"));
// 设置每页显示3行
Filter filter = new PageFilter(3);
scan.setFilter(filter);
ResultScanner scanner = table.getScanner(scan);
HBasePrintUtil.printResultScanner(scanner);
}
结果:
0004 cf1 name 1515064825025 Ethan
0005 cf1 name 1515064825034 Matthew
0005001 cf1 name 1515064934573 Benjamin
需求是,实现一个ResultScanner getPageData(long pageIndex, long pageSize)
方法,pageIndex代表起始页,pageSzie为每页显示几行,返回该页的所有数据,比如调用getPageData(3, 4)
,应该按照每页4行来分页,并且得到第3页的全部行。
代码:
import java.io.IOException;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Connection;
import org.apache.hadoop.hbase.client.ConnectionFactory;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.PageFilter;
import org.apache.hadoop.hbase.util.Bytes;
import com.aura.hbase.utils.HBasePrintUtil;
public class MyTest {
public static final String ZOOKEEPER_LIST = "192.168.21.100:2181";
public static final String TABLE_NAME = "user";
public static Configuration conf = null;
public static Table table = null;
static {
conf = HBaseConfiguration.create();
conf.set("hbase.zookeeper.quorum", ZOOKEEPER_LIST);
try {
Connection conn = ConnectionFactory.createConnection(conf);
table = conn.getTable(TableName.valueOf(TABLE_NAME));
} catch (IOException e) {
e.printStackTrace();
}
}
/*
* 最原始的获取一页数据的方法
*/
public static ResultScanner getPageData(String startRow, long pageSize) throws Exception {
Scan scan = new Scan();
Filter filter = new PageFilter(pageSize);
if(!StringUtils.isBlank(startRow)) {
scan.setStartRow(startRow.getBytes());
}
scan.setFilter(filter);
return table.getScanner(scan);
}
/*
* 把 pageIndex 转换为 startRow 的方法
*/
public static String getStartRowByPageIndex(long pageIndex, long pageSize) throws Exception {
String startRow = null;
if(pageIndex > 1) {
// 获取到某一页的最后一个 rowkey 就能加一个极小量的字节数组得到下一页的 startRow
for(int i = 1; i <= pageIndex-1; i++) {
ResultScanner pageData = getPageData(startRow, pageSize);
Result result = null;
for(Result s : pageData) {
result = s;
}
// 当前页的最后一个 rowkey
byte[] lastCurrentRowKey = result.getRow();
// 下一页的 startRow
byte[] pageFirstRowKey = Bytes.add(lastCurrentRowKey, new byte[]{0X00});
startRow = Bytes.toString(pageFirstRowKey);
}
}else {
startRow = null;
}
// 最后返回的就是 pageIndex 页的起始 startRow
return startRow;
}
/*
* 最终满足需求的方法
*/
public static ResultScanner getPageData(long pageIndex, long pageSize) throws Exception {
String startRow = getStartRowByPageIndex(pageIndex, pageSize);
return getPageData(startRow, pageSize);
}
/*
* 测试
*/
public static void main(String[] args) throws Exception {
HBasePrintUtil.printResultScanner(getPageData(3,4));
}
}
结果:
0008 cf1 name 1515064825071 Joshua
0009 cf1 name 1515064825073 Michael
0010 cf1 name 1515064825075 Ryan
0011 cf1 name 1515064825078 Andrew
说明:
本文用到的HBasePrintUtil.printResultScanner()方法,请查看:
HBase Java API 01:基础操作中的HBasePrintUtil.java中的内容