Удалить все данные из таблицы HBase в соответствии с диапазоном времени?

#timestamp #hbase #hbase-shell

#временная метка #hbase #hbase-оболочка

Вопрос:

Я пытаюсь удалить все данные из таблицы HBase, временная метка которой старше указанной временной метки. Это содержит все семейства столбцов и строки.

Есть ли способ, которым это можно сделать, используя оболочку, а также Java API?

Ответ №1:

В HBase нет понятия маркеров удаления диапазона. Это означает, что если вам нужно удалить несколько ячеек, вам нужно поместить маркер удаления для каждой ячейки, что означает, что вам придется сканировать каждую строку либо на стороне клиента, либо на стороне сервера. Это означает, что у вас есть два варианта:

  1. BulkDeleteProtocol : при этом используется конечная точка сопроцессора, что означает, что полная операция будет выполняться на стороне сервера. По ссылке приведен пример того, как ее использовать. Если вы выполните поиск в Интернете, вы можете легко найти, как включить конечную точку сопроцессора в HBase.
  2. Сканировать и удалять: это чистый и самый простой вариант. Поскольку вы сказали, что вам нужно удалить все семейства столбцов старше определенной временной метки, операцию сканирования и удаления можно значительно оптимизировать, используя фильтрацию на стороне сервера для чтения только первого ключа каждой строки.

     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 — это эпоха в миллисекундах для вашего начального и конечного временного диапазона. Это приведет к удалению всех строк в диапазоне времени.