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中的行为不一样