#timestamp #hbase #hbase-shell
#временная метка #hbase #hbase-оболочка
Вопрос:
Я пытаюсь удалить все данные из таблицы HBase, временная метка которой старше указанной временной метки. Это содержит все семейства столбцов и строки.
Есть ли способ, которым это можно сделать, используя оболочку, а также Java API?
Ответ №1:
В HBase нет понятия маркеров удаления диапазона. Это означает, что если вам нужно удалить несколько ячеек, вам нужно поместить маркер удаления для каждой ячейки, что означает, что вам придется сканировать каждую строку либо на стороне клиента, либо на стороне сервера. Это означает, что у вас есть два варианта:
- BulkDeleteProtocol : при этом используется конечная точка сопроцессора, что означает, что полная операция будет выполняться на стороне сервера. По ссылке приведен пример того, как ее использовать. Если вы выполните поиск в Интернете, вы можете легко найти, как включить конечную точку сопроцессора в HBase.
-
Сканировать и удалять: это чистый и самый простой вариант. Поскольку вы сказали, что вам нужно удалить все семейства столбцов старше определенной временной метки, операцию сканирования и удаления можно значительно оптимизировать, используя фильтрацию на стороне сервера для чтения только первого ключа каждой строки.
Scan scan = new Scan(); scan.setTimeRange(0, STOP_TS); // STOP_TS: The timestamp in question // Crucial optimization: Make sure you process multiple rows together scan.setCaching(1000); // Crucial optimization: Retrieve only row keys FilterList filters = new FilterList(FilterList.Operator.MUST_PASS_ALL, new FirstKeyOnlyFilter(), new KeyOnlyFilter()); scan.setFilter(filters); ResultScanner scanner = table.getScanner(scan); List<Delete> deletes = new ArrayList<>(1000); Result [] rr; do { // We set caching to 1000 above // make full use of it and get next 1000 rows in one go rr = scanner.next(1000); if (rr.length > 0) { for (Result r: rr) { Delete delete = new Delete(r.getRow(), STOP_TS); deletes.add(delete); } table.delete(deletes); deletes.clear(); } } while(rr.length > 0);
Ответ №2:
Yes, this can be done easily by setting time range to scanner and then deleting the returned result set.
public class BulkDeleteDriver {
//Added colum family and column to lessen the scan I/O
private static final byte[] COL_FAM = Bytes.toBytes("<column family>");
private static final byte[] COL = Bytes.toBytes("column");
final byte[] TEST_TABLE = Bytes.toBytes("<TableName>");
public static void main(final String[] args) throws IOException,
InterruptedException {
//Create connection to Hbase
Configuration conf = null;
Connection conn = null;
try {
conf = HBaseConfiguration.create();
//Path to HBase-site.xml
conf.addResource(new Path(hbasepath));
//Get the connection
conn = ConnectionFactory.createConnection(conf);
logger.info("Connection created successfully");
}
catch (Exception e) {
logger.error(e "Connection Unsuccessful");
}
//Get the table instance
Table table = conn.getTable(TableName.valueOf(TEST_TABLE));
List<Delete> listOfBatchDeletes = new ArrayList<Delete>();
long recordCount = 0;
// Set scanCache if required
logger.info("Got The Table : " table.getName());
//Get calendar instance and get proper start and end timestamps
Calendar calStart = Calendar.getInstance();
calStart.add(Calendar.DAY_OF_MONTH, day);
Calendar calEnd = Calendar.getInstance();
calEnd.add(Calendar.HOUR, hour);
//Get timestamps
long starTS = calStart.getTimeInMillis();
long endTS = calEnd.getTimeInMillis();
//Set all scan related properties
Scan scan = new Scan();
//Most important part of code set it properly!
//here my purpose it to delete everthing Present Time - 6 hours
scan.setTimeRange(starTS, endTS);
scan.setCaching(scanCache);
scan.addColumn(COL_FAM, COL);
//Scan the table and get the row keys
ResultScanner resultScanner = table.getScanner(scan);
for (Result scanResult : resultScanner) {
Delete delete = new Delete(scanResult.getRow());
//Create batches of Bult Delete
listOfBatchDeletes.add(delete);
recordCount ;
if (listOfBatchDeletes.size() == //give any suitable batch size here) {
System.out.println("Firing Batch Delete Now......");
table.delete(listOfBatchDeletes);
//don't forget to clear the array list
listOfBatchDeletes.clear();
}}
System.out.println("Firing Final Batch of Deletes.....");
table.delete(listOfBatchDeletes);
System.out.println("Total Records Deleted are.... " recordCount);
try {
table.close();
} catch (Exception e) {
e.printStackTrace();
logger.error("ERROR", e);
}}}
Комментарии:
1. В таблице около 20 миллионов строк. Получение каждой строки повлияет на производительность. Возможно ли это каким-либо образом, если мы передадим только имя таблицы и временную метку и все данные до удаления временной метки без необходимости фактически передавать строку?
2. Является ли временная метка вашим ключом строки или частью ключа строки? Если нет, то как вы узнаете, какую строку удалить. Вы должны сверить временную метку с чем-то правильным, временной меткой ключа строки или любой другой временной меткой столбца. Если да: тогда просто передайте RowKey (Timestamp) в качестве параметра сканирования диапазона или используйте нечеткие фильтры, чтобы найти эти ключи. Что бы вы ни делали, сканирование произойдет. Чтобы ускорить сканирование, вы можете посмотреть на сопроцессоры, но не пробуйте их, если вы не являетесь экспертом в HBase
Ответ №3:
Если вы хотите удалить данные из оболочки и не хотите писать Java-клиент, вы можете поступить следующим образом:
#!/bin/bash
start_time=1607731200000
end_time=1607817600000
row_key_file="/tmp/$start_time-$end_time.rowkey"
touch $row_key_file
now=$(date '%Y-%m-%d:%H-%M-%S')
echo "$now: scanning records from date range $start_time to $end_time"
echo -e "scan 'YOUR_TABLE_NAME', {TIMERANGE => [$start_time, $end_time]}" | hbase shell -n | awk -F ' ' '{if(length($1) > 20){print $1}}' > $row_key_file
rows_scanned=$(wc -l $row_key_file | cut -d' ' -f1)
echo "Rows scanned: $rows_scanned"
echo "deleting rows"
echo -e "File.foreach('$row_key_file') { |line| key=line.strip; deleteall 'extract_job_results', key; }" | hbase shell -n
now=$(date '%Y-%m-%d:%H-%M-%S')
echo "$now: Data truncation completed"
start_time и end_time — это эпоха в миллисекундах для вашего начального и конечного временного диапазона. Это приведет к удалению всех строк в диапазоне времени.