HBase JAVA API的scan使用小记

2023-05-10 23:50:26 浏览数 (2)

HBase是一个很流行kv数据库,特点是集群化,可水平扩容,基于lsm tree,写入非常快,集群化之后查询性能也不错,成本低,非常适合QPS要求不是特别高,但写入量很大的场景。

我们比较典型的就是用来做实时计算的维表join,一般就是根据rowkey查询数据,数据量小就一个个查,数据量大就攒一下批量查,基本能满足绝大部分需求。近期有个场景比较特殊,需要用scan。

scan在hbase shell里是这样执行的

代码语言:javascript复制
scan 'table',{ROWPREFIXFILTER => 'rowkey_prefix'}

上面的命令能获取到rowkey_prefix开头的所有数据。

但是通过JAVA API查询就不是这样的了,下面是chatGPT给出的案例

代码语言:javascript复制
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
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.Scan;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.PrefixFilter;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

public class HBasePrefixScanExample {

    public static void main(String[] args) throws IOException {

        Configuration config = HBaseConfiguration.create();
        Connection connection = ConnectionFactory.createConnection(config);
        TableName tablename = TableName.valueOf("mytable");
        Table table = connection.getTable(tablename);

        Scan scan = new Scan();
        byte[] prefix = Bytes.toBytes("prefix");
        Filter filter = new PrefixFilter(prefix);
        scan.setFilter(filter).withStartRow(prefix);

        // 查询结果
        ResultScanner scanner = table.getScanner(scan);
        for (Result result : scanner) {
            for (Cell cell : result.listCells()) {
                // 处理查询出来的数据
            }
        }
        scanner.close();
        table.close();
        connection.close();
    }
}

上面的代码用的api比较旧,新版本有更新

代码语言:javascript复制
 @deprecated since 2.5.0, will be removed in 4.0.0. The name of this method is considered to be
   *             confusing as it does not use a {@link Filter} but uses setting the startRow and
   *             stopRow instead. Use {@link #setStartStopRowForPrefixScan(byte[])} instead.
   */
  @Deprecated
  public Scan setRowPrefixFilter(byte[] rowPrefix) {
    return setStartStopRowForPrefixScan(rowPrefix);
  }

其实就是startRow和stopRow的设置方式变了

代码语言:javascript复制
 Scan scan = new Scan().withStartRow(Bytes.toBytes("prefixStart")).withStopRow(Bytes.toBytes("prefixStop"));

需要注意的是startRow和stopRow都必须设置,都不设置会进行全表scan,只设置startRow会从startRow扫码到表结尾,会得到很多不需要的数据,这点和shell中的行为不一样

0 人点赞