Hbase如何批量删除指定数据

一、背景:

  Hbase是一个列式存储,nosql类型的数据库,类似mongodb。

        我们都知道Hbase是一个Nosql的分布式存储数据引擎,它可以支持千万级别的QPS写入,但是有时候我们需要批量的删除他的数据, 目前似乎没有提供批量删除的方法,只有一个单行删除的命令:deleteall 'tablename', rowkey

二、删除方法:

  方法一:通过写 shell 脚本,从 hbase shell 查出需要删除的 rowkey ,拼成删除命令(deleteall 'tablename', rowkey),写到文本 del_temp.txt ;然后执行 hbase shell del_temp.txt 

  方法二:通过建映射表,比如在 hive 建一个映射表,然后写 hql 查出需要删除的 rowkey ,拼成删除命令(deleteall 'tablename', rowkey),写到文本 del_temp.txt ;然后执行 hbase shell del_temp.txt 

  方法三:通过python/ java 代码,调用 hbase 的单行删除方法,写个循环删除 

  方法四:通过建映射表,比如在 hive 建一个映射表,将 需要保留的数据 通过 hql 查询出来,备份到 hive 的一张临时表 ;然后 在hbase shell 里面 执行 truncate 'tablename' ,清空 hbase 的数据; 最后 在将数据 从 hive 的备份表 读出来,插入 映射表,写回 hbase;

  总结:

  前面3种方法,本质上都是在 hbase 中逐行删除;而第4种方法,是利用hive的map reduce倒数据。对于不熟悉 hbase 和 java 语法的开发人员而言,使用2/4方法,是灵活性最好的。

第二种删除方法为例:

  1、hive 建映射表:

CREATE EXTERNAL TABLE edw.test_turboway_hbase(
  `keyid` string COMMENT 'from deserializer',
  `title` string COMMENT 'from deserializer',
  `bizdate` string COMMENT 'from deserializer',
  `loginid` string COMMENT 'from deserializer')
ROW FORMAT SERDE
  'org.apache.hadoop.hive.hbase.HBaseSerDe'
STORED BY
  'org.apache.hadoop.hive.hbase.HBaseStorageHandler'
WITH SERDEPROPERTIES (
  'hbase.columns.mapping'=':key,cf:title,cf:bizdate,cf:loginid',
  'serialization.format'='1')
TBLPROPERTIES (
  'COLUMN_STATS_ACCURATE'='false',
  'hbase.table.name'='test_turboway',
  'numFiles'='0',
  'numRows'='-1',
  'rawDataSize'='-1',
  'totalSize'='0',
  'transient_lastDdlTime'='1543297130')

  2、记录hive查询要删除的数据,拼成命令:

hive -e 
"select concat('deleteall \'test_turboway\',\'',keyid,'\'') 
from edw.test_turboway_hbase 
where loginid = '20181122'"
 > del_temp.txt && echo 'exit' >> del_temp.txt

  3、hbase shell 执行删除命令

hbase shell del_temp.txt > del.log

二、

   由于从kafka消费过来写入hbase的数据量有点大,导致关联的外部hive表使用性能有点差,因此决定把已经导入hive的dwd层后的数据进行删除,删除脚本如下:

del_date=$1
filename=$(pwd)/rowkey.csv

beeline  
--incremental=true
--showHeader=false
--outputformat=dsv
--delimiterForDSV=$'\t'  
-e
"select  concat('deleteall \'default:monitorData\',\'',row_key,'\'')  
from  dw_ods.ods_api_msp_plan_point
where row_key like '%${del_date}'
">${filename}

sed -i '$d' ${filename}
hbase shell ${filename} > del.log


        以上脚本删除的逻辑是首先通过外部关联表查询出需要删除的rowkey,由于这个表的rowkey后缀是日期,因此通过模糊日期查询出需要删除的rowkey写入一个文件,由于写入文件后最后一行是无关的信息,因此这里需要用sed命令进行删除。

79ba3df3493780ee65c5dcddf91b84fd.png

        脚本编辑好后,写入del_hbase.sh文件,最后执行sh del_hbase.sh yyyyMMdd进行删除指定日期的数据 

三、方法三:比如我们要删除10号到13号的数据

我们可以利用Hbase的API先scan一定时间戳范围内的数据,然后在批量的删除,具体实现的代码如下:

 /**
  * 根据时间戳范围删除hbase的数据;
  */
object HbaseUtil {
  def main(args: Array[String]): Unit = {
    val s = System.currentTimeMillis()
    val conf = HBaseConfiguration.create()
    conf.set("hbase.zookeeper.quorum", PropertiesScalaUtils.loadProperties("zk_hbase")) //zk的地址;
    conf.set("hbase.zookeeper.property.clientPort", PropertiesScalaUtils.loadProperties("zk_port"))
    conf.set("hbase.master", PropertiesScalaUtils.loadProperties("hbase_master"))
    conf.set("hbase.defaults.for.version.skip", "true")
    conf.set("hhbase.rootdir", PropertiesScalaUtils.loadProperties("hbase_rootdir"))
    conf.set("zookeeper.znode.parent", PropertiesScalaUtils.loadProperties("zookeeper_znode_parent"))
    val connection = ConnectionFactory.createConnection(conf)
    val table = connection.getTable(TableName.valueOf(PropertiesScalaUtils.loadProperties("hbase_table")))
    val scan = new Scan()
    scan.setTimeRange(args(0).toLong,args(1).toLong)
    val rs = table.getScanner(scan)
    val it = rs.iterator()
    val list = new util.ArrayList[Delete]()
    while (it.hasNext){
      val delete = it.next()
      val d = new Delete(delete.getRow)
      list.add(d)
    }
    if(list.size()>0){
      println("一共有多少条数据:"+list.size())
      println("开始删除--------------------")
      table.delete(list)
      println("删除完成--------------------")
    }else{
      println("没有数据--------------------")
    }
    table.close()
    connection.close()
    val e = System.currentTimeMillis()
    println("总共用时:"+ (e-s) +"毫秒")
  }
} 

这么写虽然能实现对指定时间戳范围内的数据进行删除,但是这么写就没有问题吗,是有问题的,这样删除的效率是非常低的,因为需要先把需要删除的查出来放到一个list里面,然后在进行批量的删除,这个方法对于数据量小的时候是可以的,数据量大的话,就会非常的慢,一定要根据自己的实际情况而定

这两种方法还是推荐使用第一张设置TTL,让其自动过期,如果非要删除段时间范围内的,可以用第二种但是要考虑性能问题.
————————————————
 

Guess you like

Origin blog.csdn.net/qq_22473611/article/details/120019578