发生了什么
由于系统中的错误,上个月的所有数据均已损坏。因此,我们必须手动删除并重新输入这些记录。基本上,我想删除在一定时间内插入的所有行。但是,我发现很难在HBase中扫描和删除数百万行。
可能的解决方案
我发现了两种批量删除的方法:
第一个是设置TTL,以便系统将自动删除所有过时的记录。但是我想保留上个月之前插入的记录,因此该解决方案对我不起作用。
第二个选项是使用Java API编写客户端:
public static void deleteTimeRange(String tableName, Long minTime, Long maxTime) {
Table table = null;
Connection connection = null;
try {
Scan scan = new Scan();
scan.setTimeRange(minTime, maxTime);
connection = HBaseOperator.getHbaseConnection();
table = connection.getTable(TableName.valueOf(tableName));
ResultScanner rs = table.getScanner(scan);
List<Delete> list = getDeleteList(rs);
if (list.size() > 0) {
table.delete(list);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (null != table) {
try {
table.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if (connection != null) {
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
private static List<Delete> getDeleteList(ResultScanner rs) {
List<Delete> list = new ArrayList<>();
try {
for (Result r : rs) {
Delete d = new Delete(r.getRow());
list.add(d);
}
} finally {
rs.close();
}
return list;
}
但是在这种方法中,所有记录都存储在ResultScanner rs
中,因此堆大小将很大。如果程序崩溃了,则必须从头开始。
那么,有没有更好的方法可以达到目标呢?
答案 0 :(得分:2)
不知道您的表中要处理多少个“百万”,但简单的事情是不要尝试一次将它们全部放入List
中,而是通过更易于管理的步骤来完成使用.next(n)
函数。像这样:
for (Result row : rs.next(numRows))
{
Delete del = new Delete(row.getRow());
...
}
这样,您可以通过RPC
参数控制通过单个numRows
从服务器返回多少行。确保它足够大,以免与服务器进行过多往返,但同时又不要太大以至于无法杀死您的堆。您还可以使用BufferedMutator
一次对多个Delete
进行操作。
希望这会有所帮助。
答案 1 :(得分:0)
我建议进行两项改进:
BufferedMutator
批量删除,它完全满足您的需要–保留突变的内部缓冲区,并在缓冲区填满时将其刷新到HBase,因此您不必担心保留自己的列表,调整大小并冲洗它。KeyOnlyFilter
–因为您不需要这些值,所以无需检索它们scan.setCacheBlocks(false)
-由于您执行全表扫描,因此在区域服务器上缓存所有块没有多大意义scan.setCaching(N)
和scan.setBatch(N)
– N将取决于密钥的大小,您应该在缓存更多和所需的内存之间保持平衡;但由于您只转移密钥,我想N
可能会很大。这是您代码的更新版本:
public static void deleteTimeRange(String tableName, Long minTime, Long maxTime) {
try (Connection connection = HBaseOperator.getHbaseConnection();
final Table table = connection.getTable(TableName.valueOf(tableName));
final BufferedMutator mutator = connection.getBufferedMutator(TableName.valueOf(tableName))) {
Scan scan = new Scan();
scan.setTimeRange(minTime, maxTime);
scan.setFilter(new KeyOnlyFilter());
scan.setCaching(1000);
scan.setBatch(1000);
scan.setCacheBlocks(false);
try (ResultScanner rs = table.getScanner(scan)) {
for (Result result : rs) {
mutator.mutate(new Delete(result.getRow()));
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
请注意“尝试资源”的使用-如果您忽略了这一点,请确保.close()
mutator
,rs
,table
和connection