HBase 协处理器个别简单案例
协处理器,我个人的理解就是相当于数据库的触发器一样,可以在改变(增删改)数据的前后,做一些紧跟的动作
直接举例子
1.
//重写prePut方法,监听到向table1表插入数据时,执行向table2表插入数据的代码 public class MyProcessor extends BaseRegionObserver { @Override public void prePut(ObserverContext<RegionCoprocessorEnvironment> e, Put put, WALEdit edit, Durability durability) throws IOException { //把自己需要执行的逻辑定义在此处,向table2表插入数据,数据具体是什么内容与Put一样 //获取table2表table对象 final HTableInterface table2 = e.getEnvironment().getTable(TableName.valueOf("table2")); //解析table1表的插入对象put,列族是family,对应列是column1 final Cell cell = put.get(Bytes.toBytes("family"), Bytes.toBytes("column1")).get(0); //table对象.put final Put put1 = new Put(put.getRow()); put1.add(cell); table2.put(put1); //执行向table2表插入数据 table2.close(); } }
这是一个在put前执行其他方法的例子,案例的作用是监听到向table1表插入数据时,执行向table2表插入数据的代码
2.这是另一个例子,就是有一个关系表relative,a有b的好友,同样b有a的好友,需要a删除b的好友的同时,b好友中的a也应该删除
//删除好友关系表,a删除b的同时,b要删除a @Override public void preDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException { //把自己需要执行的逻辑定义在此处,向t2表插入数据,数据具体是什么内容与Put一样 //获取relative表table对象 final HTableInterface relative = e.getEnvironment().getTable(TableName.valueOf("relative")); List<Delete> deletes=new ArrayList<>(); //取得被删除人的keyid List<Cell> cells = delete.getFamilyCellMap().get(Bytes.toBytes("friends")); for (Cell cell : cells) { Delete appendDelete = new Delete(CellUtil.cloneRow(cell)); appendDelete.addColumn(CellUtil.cloneFamily(cell), CellUtil.cloneRow(cell)); deletes.add(appendDelete); } //执行批量删除 relative.delete(deletes); //关闭table对象 relative.close(); }
上面的代码思路是a删除b之前,写了一个协处理器,删除前处理事件,a删除b之前,先删除b中a的记录。
但是,上面的代码会造成死循环。协处理器对每一次删除都要触发。a要删除b,触发,需要b先删除a,触发,又需要a先删除b,死循环,hbase直接卡死。
后来,查看源码,确实应该有一个方法是delete之后触发的,postDelete,就报上面的方法名换了一下
//删除好友关系表,a删除b的同时,b要删除a @Override public void postDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException { //把自己需要执行的逻辑定义在此处,向t2表插入数据,数据具体是什么内容与Put一样 //获取relative表table对象 final HTableInterface relative = e.getEnvironment().getTable(TableName.valueOf("relative")); List<Delete> deletes=new ArrayList<>(); //取得被删除人的keyid List<Cell> cells = delete.getFamilyCellMap().get(Bytes.toBytes("friends")); for (Cell cell : cells) { Delete appendDelete = new Delete(CellUtil.cloneRow(cell)); appendDelete.addColumn(CellUtil.cloneFamily(cell), CellUtil.cloneRow(cell)); deletes.add(appendDelete); } //执行批量删除 relative.delete(deletes); //关闭table对象 relative.close(); }
当然,这还是不行,最好在删除前判断一下,是否有这条记录,如下
@Override public void postDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException { //获取relative表table对象 final HTableInterface relative = e.getEnvironment().getTable(TableName.valueOf("relative")); List deletes=new ArrayList<Delete>(); Scan scan = new Scan(); //取得被删除的所有cell List<Cell> cells = delete.getFamilyCellMap().get(Bytes.toBytes("friends")); for (Cell cell : cells) { //取得被删除的列 byte[] deletedColumn = CellUtil.cloneQualifier(cell); //取得当前的人 byte[] thisColumn = CellUtil.cloneRow(cell); //查询被删除者的名单中是否有当前人 scan.setStartRow(deletedColumn); ResultScanner resultScanner = relative.getScanner(scan); Result next = resultScanner.next(); //有的话,被删除者也删除当前人 if(next!=null&&!next.isEmpty()){ Cell[] cells2 = next.rawCells(); for (Cell cell2 : cells2) { if(new String(thisColumn).equals(new String(CellUtil.cloneQualifier(cell2)))){ Delete appendDelete = new Delete(deletedColumn); appendDelete.addColumn(CellUtil.cloneFamily(cell2), thisColumn); deletes.add(appendDelete); } } } } //执行批量删除 relative.delete(deletes); //关闭table对象 relative.close(); }
这样就可以了,实现删除relative中好友关系,a删除b,b也会自动删除a的好友记录。
记住,你得上传jar包到hadoop挂载到habase中relative表
代码打包成jar包 postdelete.jar
上传到hadoop
hdfs dfs -mkdir -p /processor
hdfs dfs -put processor.jar /processor
在hbase中执行
alter 'relative',METHOD => 'table_att','Coprocessor'=>'hdfs://linux121:9000/processor/postdelete.jar|com.test.hbase.processor.PostDelete|1001|'
表名 列属性名,可自定义 hadoop中jar包对应得位置信息 对应类的路径名包名+类名 优先级,多个触发器,优先级大的先触发