记录一次HBase的scan的分页查询

您所在的位置:网站首页 hbase查询数据前十条 记录一次HBase的scan的分页查询

记录一次HBase的scan的分页查询

2024-01-17 09:58| 来源: 网络整理| 查看: 265

修改前任bug,Hbase查询过于慢了,以至于都查不出来了,看了代码发现使用的Scan只设置了withStartRow、withEndRow、setCaching扫描,拿到全部数据后存入集合再subList进行分页,但是HBase中存在某些数据有几百万条,根本scan不出来了。

前任设置如下: 其中start 和 end 拼接0和z是因为HBase中RowKey按照字典顺序排序,

String start = rowKey + "0"; String end = rowKey + "z"; Scan scan = new Scan(); scan.withStartRow(start.getBytes()); scan.withStopRow(end.getBytes()); scan.setCaching(1000); scan.setCacheBlocks(false); 先根据业务逻辑找他的问题,首先没限定时间戳,然后这样分页数据量大就出现问题了。 1.加上时间戳限定范围

时间根据自己的时间来定,我这里是查询前一天的数据,所以就是零点到末尾

try { scan.setTimeRange(getStartOfDay("2021-11-23"), getEndOfDay("2021-11-23")); } catch (IOException e) { e.printStackTrace(); }

日期代码网上找的,一搜一堆

// 获取指定日期 的 零点时间戳 public static Long getStartOfDay(String date) { if (StringUtils.isEmpty(date)) { date = date2String(new Date(), "yyyy-MM-dd"); } DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.CHINA); LocalDate parse = LocalDate.parse(date, ofPattern); return parse.atStartOfDay().toInstant(ZoneOffset.of("+8")).toEpochMilli(); } // 获取指定日期 的 末尾时间戳 public static Long getEndOfDay(String date) { if (StringUtils.isEmpty(date)) { date = date2String(new Date(), "yyyy-MM-dd"); } DateTimeFormatter ofPattern = DateTimeFormatter.ofPattern("yyyy-MM-dd", Locale.CHINA); LocalDate parse = LocalDate.parse(date, ofPattern); return LocalDateTime.of(parse, LocalTime.MAX).toInstant(ZoneOffset.of("+8")).toEpochMilli(); } public static String date2String(Date date, String format) { SimpleDateFormat yyyy_MM_dd = new SimpleDateFormat(format); return yyyy_MM_dd.format(date); } //获取前多少小时到现在的时间范围 //可以将 cal1.add(11, -(hour + 2))进行修改,我这里是当前时间往前走俩小时,hour是前多少小时 public static long[] getHourTimeLimit(int hour) { Calendar cal1 = Calendar.getInstance(); Date date = new Date(); cal1.setTime(date); cal1.add(11, -(hour + 2)); Date d = cal1.getTime(); return new long[]{d.getTime(), date.getTime()}; } 2.修改分页查询 1.网上找到的实现方式

Hbase有一个PageFilter(x),设置一个数,往后查询多少个 但是有个问题就是需要设置具体的withStartRow,从withStartRow开始往后查询x个,需要先找到startrow,每次根据startrow往后查x,感觉有点冗余就没用,自己想了个思路。 链接贴上:想了解可以看看 https://blog.csdn.net/HANLIPENGHANLIPENG/article/details/53203646

2.自己实现的思路

scan的设置:

public Scan getScan(String rowKey){ Scan scan = new Scan(); String start = rowKey + "0"; scan.withStartRow(start.getBytes()); scan.setCaching(6000); scan.setCacheBlocks(false); scan.setMaxResultSize(2 * 1024 * 1024 * 100); try { scan.setTimeRange(getStartOfDay("2021-11-23"), getEndOfDay("2021-11-23")); } catch (IOException e) { e.printStackTrace(); } scan.setFilter(new PrefixFilter(rowKey)); return scan; } 大概意思就是:使用scanner.next(pageSize)根据页数来轮询,轮询到当前页就将数据进行解析,结束循环返回。数据量大估计也需要挺长时间,测试了一下每页20条,1000页以内都还挺快的 前提是将scan.setCaching(6000);这个参数调到适合自己的集群,这将决定你多页查询的速度,或者将他设置为一个范围,根据当前页大小来做判断设置不同的大小,页数小就设置小点,页数大就相对大一些,尽量一次缓存能查找到,这样速度就会更快。 scan.setCaching(pageSize * currentPage > 6000 ? 6000 : pageSize * currentPage); Scan scan = getScan(rowKey); //设置上要查询的列 for (int i = 0; i Long.valueOf(hour)}).getBytes()); } List alls = new ArrayList(); long count = 0L; String startRow; try (Table table = this.hbaseConnection.getTable(TableName.valueOf("table")); ResultScanner scanner = table.getScanner(scan)) { Result[] results; int pageCount = 0; while ((results = scanner.next(pageSize)).length != 0) { pageCount++; if (pageCount //在此处解析获取数据 alls.add(xxxx) } break; } } catch (Exception e) { log.error("", e); }

我查询第600页每页10个,算上解析,用时2278ms,速度还可以吧,只能说相比前任已经是可以查出来了,后面在做优化吧,第一种方法没尝试,感觉上来讲第一种也是一个一个扫描的,不知道速度如何,有时间的时候在做下测试吧。

[root@11 scanHbaseTest]# java -jar scanHbaseTest-1.0-SNAPSHOT.jar xxxxxx 600 10 today get Results time = 2278ms Hbase分页查询还真不太好弄,除非能缓存一下每页的第一条数据,这样速度会快很多吧,但是不太现实。 目前也没想到特别好的办法,如果有可以分享给我。 HBase查询优化续集HBase并发查询


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3