背景:公司想做大数据相关的应用,招了一位大数据方面的美女攻城狮,我作为打杂的被分配到了底下.
1)关于scan中的startrow和stoprow
关于分页遇到的问题
在java上刚开始看到这两个方法的时候(setStartrow,setStoprow)我还以为是和截取字符串substring差不多的用法.一个代表起始rowkey,一个代表结束rowkey.但是,实际上还就是这个意思.不同的是这个rowkey是按照字符来进行排序的(我在hbase中保存的就是1,2,3..之类的rowkey).结果悲催了,我分别赋值为1和10,结果给我返回为空,百思不得其解.后来多看了几篇文章才知道原来是通过字符来排序的.如图, scan 'blogtable' , {STARTROW => '1',STOPROW => '8'} 查询的数据是1,17,18(PS:以前我这里只有1,2,3三条数据,查询不到数据的时候我还以为是因为数据不够角标越界.....后来多加了几条数据才看出来)
好了,上面知道问题出在了哪里,但是目前对于分页还是一无所知,继续查资料看看去
关于分页的处理:
通过查了一些文章,找到了一个比较简单易懂的处理分页的方法.下面分享一下
Table table = conn.getTable(TableName.valueOf(tableName));//这里的conn是 conn
// = ConnectionFactory.createConnection(conf); //conf是我们的配置信息,我这里对获取conn进行了封装
//分页相关主要代码在这里
Filter pageFilter = new PageFilter(pageSize);//分页查询在这里
Filter rowFilter = new RowFilter(CompareFilter.CompareOp.GREATER,
new BinaryComparator(Bytes.toBytes(lastRowKey)));//lastRowKey最 //后一个rowkey,上一次查询的,第一次查询的话这里可以为""
filterList.addFilter(pageFilter);//把pageFilter放进lists中
scan.setFilter(filterList);//添加进scan中
//后面的就是查询,以及对查询到的相关数据进行二次处理了
ResultScanner rs = table.getScanner(scan);
Result result;
int rowNum = 0;
while ((result = rs.next()) != null) {
if (rowNum >= pageSize) {//pageSize是要显示的内容数
break;
}
List<Cell> listCells = result.listCells();
Map<String,Object> map = new HashMap<String,Object>();
String row = "";
for (Cell cell : listCells) {
//下面是一些业务逻辑,不必在意
row =Bytes.toString( cell.getRowArray(), cell.getRowOffset(), cell.getRowLength());
String value =Bytes.toString( cell.getValueArray(), cell.getValueOffset(), cell.getValueLength());
String family = Bytes.toString(cell.getFamilyArray(),cell.getFamilyOffset(),cell.getFamilyLength());
String quali = Bytes.toString( cell.getQualifierArray(),cell.getQualifierOffset(),cell.getQualifierLength());
if(quali != null && quali.length() != 0) {
map.put(family+"_"+quali, value);
}else{
map.put(family, value);
}
/* E e = getDataByRowKey(e,tableName, get);
if (!StringUtils.isEmpty(generalNewsInfo.getRowkey())) {
dataList.add(generalNewsInfo);
rowNum++;
} else {
// LOGGER.error("##### rowkey not found {}", rowkey);
}*/
}
map.put("row",row );
dataLists.add(map);
rowNum++;
}
table.close();
其实这里主要就是对PageFilter的应用.
---------------------------------------------------------分割线-------------------------------
2019年8月20日补充:
现在贴上一个目前用的比较顺的分页+过滤的代码
/**
*
*
* @param tableName 表名
* @param filterList 过滤
* @param pageModel 一个实体类,
* @return
*/
public HBasePageModel getPage(String tableName, FilterList filterList, HBasePageModel pageModel) {
startRow = "";
int pageSize = pageModel.getPageSize();//获取分页大小
int pageNum = pageModel.getPageIndex();//获取当前页码
// 设置list过滤
if (filterList == null) {
filterList = new FilterList();
}
log.info("过滤器信息::" + filterList.toString());
long totalNum = 0L;
Table table;
List<Result> resultList = new ArrayList<Result>();
// 获取总条数
totalNum = HBaseTableDataUtil.getTotal(tableName, filterList);//这里使用的是协调器的方式进行获取的
pageModel.setQueryTotalCount(totalNum);//把总记录数放进model中
Filter page = new PageFilter(pageSize + 1);//分页设置
filterList.addFilter(page);
try {
table = HBaseTableDataUtil.getTable(TableName.valueOf(tableName));//封装的获取table的方法
// int totalSize = MyUtils.getTotal(filterList);
Scan scan = new Scan();
scan.setFilter(filterList);
for (int i = 0; i < pageNum; i++) {
ResultScanner rs = table.getScanner(scan);
int count = 0;
for (Result r : rs) {
count++;
//这里是设置开始rowkey,不过这步我自己也没有看明白,本来打算去掉的,但是去掉以后有问题
if (count == pageSize + 1) {
startRow = new String(r.getRow());
scan.setStartRow(startRow.getBytes());
System.out.println("startRow" + startRow);
break;
}
startRow = new String(r.getRow());
// 在这一步判断是否到达我们需要的页面,是的话进行数据保存
if (i == pageNum - 1) {
resultList.add(r);
}
}
if (count < pageSize) {
break;
}
}
} catch (IOException e) {
e.printStackTrace();
log.error("getPage:::error:::" + e.getMessage());
}
pageModel.setResultList(resultList);
return pageModel;
}
HBasePageModel
import java.io.Serializable;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.hbase.client.Result;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
//这个是借用了其他人写的model
public class HBasePageModel implements Serializable{
private static final Logger logger = LoggerFactory.getLogger(HBasePageModel.class);
private static final long serialVersionUID = 330410716100946538L;
private int pageSize = 25;
private int pageIndex = 0;
private int prevPageIndex = 1;
private int nextPageIndex = 1;
private int pageCount = 0;
private int pageFirstRowIndex = 1;
private byte[] pageStartRowKey = null;
private byte[] pageEndRowKey = null;
private boolean hasNextPage = true;
private long queryTotalCount = 0;
private long startTime = System.currentTimeMillis();
private long endTime = System.currentTimeMillis();
private List<Result> resultList = new ArrayList<Result>();
public HBasePageModel(int pageSize) {
this.pageSize = pageSize;
}
/**
* 获取分页记录数量
* @return
*/
public int getPageSize() {
return pageSize;
}
/**
* 设置分页记录数量
* @param pageSize
*/
public void setPageSize(int pageSize) {
this.pageSize = pageSize;
}
/**
* 获取当前页序号
* @return
*/
public int getPageIndex() {
return pageIndex;
}
/**
* 设置当前页序号
* @param pageIndex
*/
public void setPageIndex(int pageIndex) {
this.pageIndex = pageIndex;
}
/**
* 获取分页总数
* @return
*/
public int getPageCount() {
return pageCount;
}
/**
* 设置分页总数
* @param pageCount
*/
public void setPageCount(int pageCount) {
this.pageCount = pageCount;
}
/**
* 获取每页的第一行序号
* @return
*/
public int getPageFirstRowIndex() {
this.pageFirstRowIndex = (this.getPageIndex() - 1) * this.getPageSize() + 1;
return pageFirstRowIndex;
}
/**
* 获取每页起始行键
* @return
*/
public byte[] getPageStartRowKey() {
return pageStartRowKey;
}
/**
* 设置每页起始行键
* @param pageStartRowKey
*/
public void setPageStartRowKey(byte[] pageStartRowKey) {
this.pageStartRowKey = pageStartRowKey;
}
/**
* 获取每页结束行键
* @return
*/
public byte[] getPageEndRowKey() {
return pageEndRowKey;
}
/**
* 设置每页结束行键
* @param pageStartRowKey
*/
public void setPageEndRowKey(byte[] pageEndRowKey) {
this.pageEndRowKey = pageEndRowKey;
}
/**
* 获取上一页序号
* @return
*/
public int getPrevPageIndex() {
if(this.getPageIndex() > 1) {
this.prevPageIndex = this.getPageIndex() - 1;
} else {
this.prevPageIndex = 1;
}
return prevPageIndex;
}
/**
* 获取下一页序号
* @return
*/
public int getNextPageIndex() {
this.nextPageIndex = this.getPageIndex() + 1;
return nextPageIndex;
}
/**
* 获取是否有下一页
* @return
*/
public boolean isHasNextPage() {
//这个判断是不严谨的,因为很有可能剩余的数据刚好够一页。
if(this.getResultList().size() == this.getPageSize()) {
this.hasNextPage = true;
} else {
this.hasNextPage = false;
}
return hasNextPage;
}
/**
* 获取已检索总记录数
*/
public long getQueryTotalCount() {
return queryTotalCount;
}
/**
* 获取已检索总记录数
* @param queryTotalCount
*/
public void setQueryTotalCount(long queryTotalCount) {
this.queryTotalCount = queryTotalCount;
}
/**
* 初始化起始时间(毫秒)
*/
public void initStartTime() {
this.startTime = System.currentTimeMillis();
}
/**
* 初始化截止时间(毫秒)
*/
public void initEndTime() {
this.endTime = System.currentTimeMillis();
}
/**
* 获取毫秒格式的耗时信息
* @return
*/
public String getTimeIntervalByMilli() {
return String.valueOf(this.endTime - this.startTime) + "毫秒";
}
/**
* 获取秒格式的耗时信息
* @return
*/
public String getTimeIntervalBySecond() {
double interval = (this.endTime - this.startTime)/1000.0;
DecimalFormat df = new DecimalFormat("#.##");
return df.format(interval) + "秒";
}
/**
* 打印时间信息
*/
public void printTimeInfo() {
logger.info("起始时间:" + this.startTime);
logger.info("截止时间:" + this.endTime);
logger.info("耗费时间:" + this.getTimeIntervalBySecond());
}
/**
* 获取HBase检索结果集合
* @return
*/
public List<Result> getResultList() {
return resultList;
}
/**
* 设置HBase检索结果集合
* @param resultList
*/
public void setResultList(List<Result> resultList) {
this.resultList = resultList;
}
}
getTotal() //统计条数
public static long getTotal(String tableName,FilterList filterList){
long num = 0;
AggregationClient aggregationClient = new AggregationClient(getConfig());
try {
Scan scan = new Scan();
if(filterList.getFilters().size() > 0)
scan.setFilter(filterList);
scan.setMaxVersions(1);
Long rowCount = aggregationClient.rowCount(TableName.valueOf(tableName),
new LongColumnInterpreter(), scan);
aggregationClient.close();
num = rowCount.intValue();
} catch (Throwable e) {
e.printStackTrace();
}
return num;
}