HBase扫描数据 #

一、SCAN语法 #

1.1 基本语法 #

ruby
# 基本语法
scan '表名'

# 示例
scan 'user'

1.2 完整语法 #

ruby
# 完整语法
scan '表名', {选项}

# 示例
scan 'user', {STARTROW => 'user001', STOPROW => 'user010', LIMIT => 10}

二、基本扫描操作 #

2.1 全表扫描 #

ruby
# 全表扫描
scan 'user'

# 输出示例
ROW                      COLUMN+CELL
 user001                 column=info:age, timestamp=1704067200000, value=25
 user001                 column=info:name, timestamp=1704067200000, value=张三
 user002                 column=info:age, timestamp=1704067200000, value=30
 user002                 column=info:name, timestamp=1704067200000, value=李四

2.2 扫描指定列族 #

ruby
# 扫描指定列族
scan 'user', {COLUMN => 'info'}

# 输出示例
ROW                      COLUMN+CELL
 user001                 column=info:age, timestamp=1704067200000, value=25
 user001                 column=info:name, timestamp=1704067200000, value=张三

2.3 扫描指定列 #

ruby
# 扫描指定列
scan 'user', {COLUMN => 'info:name'}

# 扫描多列
scan 'user', {COLUMN => ['info:name', 'info:age']}

2.4 扫描命名空间中的表 #

ruby
# 扫描命名空间中的表
scan 'myapp:user'

三、范围查询 #

3.1 指定行范围 #

ruby
# 指定起始行
scan 'user', {STARTROW => 'user001'}

# 指定结束行
scan 'user', {STOPROW => 'user010'}

# 指定范围
scan 'user', {STARTROW => 'user001', STOPROW => 'user010'}

# 注意:STARTROW包含,STOPROW不包含
# [user001, user010)

3.2 行范围示例 #

ruby
# 数据
# user001, user002, user003, user010, user011, user020

# 查询 user001 到 user010 之间的数据
scan 'user', {STARTROW => 'user001', STOPROW => 'user010'}
# 返回:user001, user002, user003
# 不包含 user010

# 查询 user010 到 user020 之间的数据
scan 'user', {STARTROW => 'user010', STOPROW => 'user020'}
# 返回:user010, user011
# 不包含 user020

3.3 反向扫描 #

ruby
# 反向扫描
scan 'user', {STARTROW => 'user010', STOPROW => 'user001', REVERSED => true}

# 注意:反向扫描时,STARTROW > STOPROW

3.4 前缀扫描 #

ruby
# 扫描特定前缀的行
scan 'user', {STARTROW => 'user001', STOPROW => 'user002'}

# 使用RowFilter进行前缀过滤
scan 'user', {FILTER => "PrefixFilter('user00')"}

四、限制结果 #

4.1 限制返回行数 #

ruby
# 限制返回行数
scan 'user', {LIMIT => 10}

4.2 限制返回版本 #

ruby
# 限制返回版本数
scan 'user', {VERSIONS => 3}

4.3 限制返回列数 #

ruby
# 每行返回的列数限制
scan 'user', {COLUMN => 'info', LIMIT => 10}

五、时间范围查询 #

5.1 指定时间戳 #

ruby
# 查询指定时间戳的数据
scan 'user', {TIMESTAMP => 1704067200000}

5.2 指定时间范围 #

ruby
# 查询时间范围内的数据
scan 'user', {TIMERANGE => [1704067200000, 1704067300000]}

# 注意:时间范围 [start, end),start包含,end不包含

5.3 时间范围示例 #

ruby
# 查询最近1小时的数据
now = Time.now.to_i * 1000
one_hour_ago = now - 3600000
scan 'user', {TIMERANGE => [one_hour_ago, now]}

六、过滤器 #

6.1 过滤器语法 #

ruby
# 过滤器语法
scan '表名', {FILTER => "过滤器类型(比较器)"}

6.2 常用过滤器 #

RowFilter(行键过滤器) #

ruby
# 行键等于
scan 'user', {FILTER => "RowFilter(=, 'binary:user001')"}

# 行键前缀
scan 'user', {FILTER => "RowFilter(=, 'binaryprefix:user00')"}

# 行键正则
scan 'user', {FILTER => "RowFilter(=, 'regexstring:user00.*')"}

PrefixFilter(前缀过滤器) #

ruby
# 前缀过滤
scan 'user', {FILTER => "PrefixFilter('user00')"}

ValueFilter(值过滤器) #

ruby
# 值等于
scan 'user', {FILTER => "ValueFilter(=, 'binary:张三')"}

# 值前缀
scan 'user', {FILTER => "ValueFilter(=, 'binaryprefix:张')"}

# 值正则
scan 'user', {FILTER => "ValueFilter(=, 'regexstring:张.*')"}

QualifierFilter(列限定符过滤器) #

ruby
# 列名等于
scan 'user', {FILTER => "QualifierFilter(=, 'binary:name')"}

# 列名前缀
scan 'user', {FILTER => "QualifierFilter(=, 'binaryprefix:na')"}

FamilyFilter(列族过滤器) #

ruby
# 列族等于
scan 'user', {FILTER => "FamilyFilter(=, 'binary:info')"}

SingleColumnValueFilter(单列值过滤器) #

ruby
# 单列值过滤
scan 'user', {FILTER => "SingleColumnValueFilter('info', 'age', =, 'binary:25')"}

# 过滤不匹配的行
scan 'user', {FILTER => "SingleColumnValueFilter('info', 'age', >, 'binary:20')"}

# 如果列不存在也返回
scan 'user', {FILTER => "SingleColumnValueFilter('info', 'age', >=, 'binary:20', true, true)"}

ColumnPrefixFilter(列前缀过滤器) #

ruby
# 列前缀过滤
scan 'user', {FILTER => "ColumnPrefixFilter('na')"}

MultipleColumnPrefixFilter(多列前缀过滤器) #

ruby
# 多列前缀过滤
scan 'user', {FILTER => "MultipleColumnPrefixFilter('na', 'ag')"}

PageFilter(分页过滤器) #

ruby
# 分页查询
scan 'user', {FILTER => "PageFilter(10)"}

6.3 过滤器组合 #

ruby
# AND组合
scan 'user', {FILTER => "RowFilter(=, 'binaryprefix:user00') AND ValueFilter(=, 'binary:张三')"}

# OR组合
scan 'user', {FILTER => "ValueFilter(=, 'binary:张三') OR ValueFilter(=, 'binary:李四')"}

# NOT组合
scan 'user', {FILTER => "NOT ValueFilter(=, 'binary:张三')"}

# 复杂组合
scan 'user', {FILTER => "(RowFilter(=, 'binaryprefix:user00') AND ValueFilter(=, 'binary:张三')) OR ValueFilter(=, 'binary:李四')"}

6.4 比较器 #

比较器 说明 示例
binary 二进制比较 ‘binary:value’
binaryprefix 二进制前缀比较 ‘binaryprefix:pre’
regexstring 正则表达式 ‘regexstring:pattern’
substring 子字符串匹配 ‘substring:sub’

6.5 比较运算符 #

运算符 说明
= 等于
!= 不等于
> 大于
>= 大于等于
< 小于
<= 小于等于

七、扫描示例 #

7.1 用户信息扫描 #

ruby
# 扫描所有用户
scan 'user', {COLUMN => 'info'}

# 扫描特定用户范围
scan 'user', {STARTROW => 'user001', STOPROW => 'user010', COLUMN => 'info'}

# 扫描年龄大于20的用户
scan 'user', {FILTER => "SingleColumnValueFilter('info', 'age', >, 'binary:20')"}

# 分页扫描
scan 'user', {STARTROW => 'user001', LIMIT => 10}

7.2 订单信息扫描 #

ruby
# 扫描用户订单
scan 'order', {STARTROW => 'user001_', STOPROW => 'user001_~'}

# 扫描最近订单
scan 'order', {STARTROW => 'user001_', STOPROW => 'user001_~', LIMIT => 10}

# 扫描已支付订单
scan 'order', {FILTER => "SingleColumnValueFilter('detail', 'status', =, 'binary:paid')"}

7.3 时序数据扫描 #

ruby
# 扫描设备数据
scan 'sensor', {STARTROW => 'device001_', STOPROW => 'device001_~'}

# 扫描最近数据
scan 'sensor', {STARTROW => 'device001_', STOPROW => 'device001_~', LIMIT => 100}

# 扫描时间范围数据
scan 'sensor', {TIMERANGE => [1704067200000, 1704067300000]}

八、Java API扫描 #

8.1 基本扫描 #

java
import org.apache.hadoop.hbase.client.*;
import org.apache.hadoop.hbase.util.Bytes;

public class ScanExample {
    public static void main(String[] args) throws Exception {
        Connection connection = ConnectionFactory.createConnection();
        Table table = connection.getTable(TableName.valueOf("user"));
        
        // 创建Scan对象
        Scan scan = new Scan();
        
        // 执行扫描
        ResultScanner scanner = table.getScanner(scan);
        
        // 遍历结果
        for (Result result : scanner) {
            String rowKey = Bytes.toString(result.getRow());
            String name = Bytes.toString(
                result.getValue(Bytes.toBytes("info"), Bytes.toBytes("name"))
            );
            System.out.println("RowKey: " + rowKey + ", Name: " + name);
        }
        
        scanner.close();
        table.close();
        connection.close();
    }
}

8.2 范围扫描 #

java
// 创建Scan对象
Scan scan = new Scan();

// 设置范围
scan.setStartRow(Bytes.toBytes("user001"));
scan.setStopRow(Bytes.toBytes("user010"));

// 设置列
scan.addColumn(Bytes.toBytes("info"), Bytes.toBytes("name"));

// 执行扫描
ResultScanner scanner = table.getScanner(scan);

8.3 使用过滤器 #

java
import org.apache.hadoop.hbase.filter.*;

// 创建过滤器
Filter filter = new PrefixFilter(Bytes.toBytes("user00"));

// 设置过滤器
Scan scan = new Scan();
scan.setFilter(filter);

// 执行扫描
ResultScanner scanner = table.getScanner(scan);

8.4 分页扫描 #

java
// 分页扫描
byte[] lastRow = null;
int pageSize = 100;

while (true) {
    Scan scan = new Scan();
    scan.setLimit(pageSize);
    
    if (lastRow != null) {
        scan.setStartRow(lastRow);
    }
    
    ResultScanner scanner = table.getScanner(scan);
    int count = 0;
    
    for (Result result : scanner) {
        // 处理结果
        lastRow = result.getRow();
        count++;
    }
    
    scanner.close();
    
    if (count < pageSize) {
        break;  // 没有更多数据
    }
}

九、性能优化 #

9.1 扫描优化建议 #

text
扫描优化建议
├── 指定列族和列
│   └── 减少数据传输
│
├── 使用范围限制
│   └── STARTROW/STOPROW
│
├── 使用过滤器
│   └── 服务端过滤减少传输
│
├── 设置缓存大小
│   └── 合理设置scanner caching
│
├── 使用分页
│   └── 避免一次扫描大量数据
│
└── 关闭BlockCache
    └── 一次性扫描场景

9.2 缓存配置 #

xml
<!-- hbase-site.xml -->

<!-- Scanner缓存大小 -->
<property>
    <name>hbase.client.scanner.caching</name>
    <value>100</value>
</property>

<!-- Scanner超时时间 -->
<property>
    <name>hbase.client.scanner.timeout.period</name>
    <value>60000</value>
</property>

9.3 Java API缓存设置 #

java
// 设置Scanner缓存
Scan scan = new Scan();
scan.setCaching(100);  // 每次RPC返回100行
scan.setCacheBlocks(false);  // 关闭BlockCache(一次性扫描)

十、常见问题 #

10.1 扫描超时 #

ruby
# 问题:扫描大量数据超时
# 解决:设置超时时间或分页扫描

# 分页扫描
scan 'user', {LIMIT => 1000}

10.2 内存溢出 #

ruby
# 问题:扫描大量数据内存溢出
# 解决:使用分页或限制返回列

# 限制返回列
scan 'user', {COLUMN => 'info:name', LIMIT => 1000}

10.3 扫描慢 #

ruby
# 问题:扫描速度慢
# 解决:使用过滤器、范围限制

# 使用过滤器
scan 'user', {FILTER => "PrefixFilter('user00')"}

# 使用范围限制
scan 'user', {STARTROW => 'user001', STOPROW => 'user010'}

十一、最佳实践 #

11.1 扫描设计 #

text
扫描设计建议
├── 避免全表扫描
├── 使用范围限制
├── 使用过滤器
├── 指定需要的列
└── 合理设置缓存

11.2 性能优化 #

text
性能优化建议
├── 使用StartRow/StopRow
├── 使用过滤器减少传输
├── 设置合理的caching值
├── 分页处理大数据量
└── 关闭BlockCache(一次性扫描)

11.3 数据一致性 #

text
数据一致性建议
├── 理解MVCC机制
├── 注意时间范围查询
└── 关注版本数设置

十二、总结 #

本节介绍了HBase扫描数据:

操作 语法
全表扫描 scan ‘表’
范围扫描 scan ‘表’,
列扫描 scan ‘表’,
过滤器 scan ‘表’,
分页 scan ‘表’,
时间范围 scan ‘表’,

下一步,让我们学习高级特性!

最后更新:2026-03-27