阶段一模块四(hbase)

Hbase作业

在社交网站,社交APP上会存储有大量的用户数据以及用户之间的关系数据,比如A用户的好友列表会展示出他所有的好友,现有一张Hbase表,存储就是当前注册用户的好友关系数据,如下

image.png

需求

  1. 使用Hbase相关API创建一张结构如上的表

  2. 删除好友操作实现(好友关系双向,一方删除好友,另一方也会被迫删除好友)

例如:uid1用户执行删除uid2这个好友,则uid2的好友列表中也必须删除uid1

思路分析

  1. 创建表。RelationDemo.java

    package com.lagou.hbase;
    
    import org.apache.hadoop.conf.Configuration;
    import org.apache.hadoop.hbase.HBaseConfiguration;
    import org.apache.hadoop.hbase.HColumnDescriptor;
    import org.apache.hadoop.hbase.HTableDescriptor;
    import org.apache.hadoop.hbase.TableName;
    import org.apache.hadoop.hbase.client.*;
    import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.junit.After;
    import org.junit.Before;
    import org.junit.Test;
    
    import java.io.IOException;
    import java.util.ArrayList;
    
    /**
     * hbase客户端
     */
    public class RelationDemo {
    
        //创建一张维护社交好友关系的hbase
        /*
        表名:relation
        rowkey:uid
        列族:friends
         */
        static Configuration conf = null;
        static Connection conn = null;
    
        static {
            conf = HBaseConfiguration.create();
    
            conf.set("hbase.zookeeper.quorum", "hadoop01,hadoop02");
            conf.set("hbase.zookeeper.property.clientPort", "2181");
            //通过conf获取到hbase集群的连接
            try {
                conn = ConnectionFactory.createConnection(conf);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    
        // 创建表方法
        public void createRelationTable() throws IOException {
            final Admin admin = conn.getAdmin();
            final HTableDescriptor relation = new HTableDescriptor(TableName.valueOf("relation"));
            final HColumnDescriptor cf = new HColumnDescriptor("friends");
            final HTableDescriptor hTableDescriptor = relation.addFamily(cf);
            admin.createTable(hTableDescriptor);
    
            System.out.println("relation表创建成功!!");
            admin.close();
        }
    
        //初始化部分数据
        public void initRelationData() throws IOException {
            final Table relation = conn.getTable(TableName.valueOf("relation"));
            //插入uid1用户
            final Put uid1 = new Put(Bytes.toBytes("uid1"));
            uid1.addColumn(Bytes.toBytes("friends"), Bytes.toBytes("uid2"), Bytes.toBytes("uid2"));
            uid1.addColumn(Bytes.toBytes("friends"), Bytes.toBytes("uid3"), Bytes.toBytes("uid3"));
            uid1.addColumn(Bytes.toBytes("friends"), Bytes.toBytes("uid4"), Bytes.toBytes("uid4"));
            //插入uid2用户
            final Put uid2 = new Put(Bytes.toBytes("uid2"));
            uid2.addColumn(Bytes.toBytes("friends"), Bytes.toBytes("uid1"), Bytes.toBytes("uid1"));
            uid2.addColumn(Bytes.toBytes("friends"), Bytes.toBytes("uid3"), Bytes.toBytes("uid3"));
            uid2.addColumn(Bytes.toBytes("friends"), Bytes.toBytes("uid4"), Bytes.toBytes("uid4"));
            //准备list集合
            final ArrayList<Put> puts = new ArrayList<Put>();
            puts.add(uid1);
            puts.add(uid2);
            //执行写入
            relation.put(puts);
            System.out.println("数据初始化成功!!");
        }
    
        //某个用户其中一个好友,
        public void deleteFriedns(String uid, String friend) throws IOException {
            /*
            1 需要根据传入用户删除其列族中对应好友的列
            2 其好友的列族对应需要删除该用户的列
             */
            final Table relation = conn.getTable(TableName.valueOf("relation"));
            final Delete delete = new Delete(Bytes.toBytes(uid));
            delete.addColumn(Bytes.toBytes("friends"), Bytes.toBytes(friend));//最好使用协处理器实现
    
            relation.delete(delete);
    
        }
    
        public static void main(String[] args) throws IOException {
            RelationDemo r = new RelationDemo();
            r.createRelationTable();//创建表
            r.initRelationData();//初始化数据
            //假设uid1用户删除了uid2这个好友,需要执行删除操作
    //        r.deleteFriedns("uid1", "uid2");
        }
    }
    
  2. 使用Observer协处理器,当执行删除操作的时候,触发另外删除一个操作。MyProcesser.java

    package com.lagou.hbase;
    
    import org.apache.hadoop.hbase.Cell;
    import org.apache.hadoop.hbase.CellUtil;
    import org.apache.hadoop.hbase.util.Bytes;
    import org.apache.hadoop.hbase.TableName;
    import org.apache.hadoop.hbase.client.*;
    import org.apache.hadoop.hbase.coprocessor.BaseRegionObserver;
    import org.apache.hadoop.hbase.coprocessor.ObserverContext;
    import org.apache.hadoop.hbase.coprocessor.RegionCoprocessorEnvironment;
    import org.apache.hadoop.hbase.regionserver.wal.WALEdit;
    
    import java.io.IOException;
    import java.util.List;
    import java.util.Map;
    import java.util.NavigableMap;
    import java.util.Set;
    
    /**
     * 协处理器
     * 当删除好友时,触发另外一个操作
     */
    public class MyProcessor extends BaseRegionObserver {
    
        //predelete
        //postdelete:通过判断数据是否已经删除来跳出递归
    
        @Override
        public void postDelete(ObserverContext<RegionCoprocessorEnvironment> e, Delete delete, WALEdit edit, Durability durability) throws IOException {
    
            HTableInterface relation = e.getEnvironment().getTable(TableName.valueOf("relation"));
            //获取rowkey
            byte[] rowkeyUid = delete.getRow();
            //获取到所有的cell对象
            NavigableMap<byte[], List<Cell>> familyCellMap = delete.getFamilyCellMap();
            Set<Map.Entry<byte[], List<Cell>>> entries = familyCellMap.entrySet();
            for (Map.Entry<byte[], List<Cell>> entry : entries) {
                //列族信息
                System.out.println(Bytes.toString(entry.getKey()));
                // 该列族中所有的单元格
                List<Cell> cells = entry.getValue();
                for (Cell cell : cells) {
                    //rowkey信息
                    byte[] rowkey = CellUtil.cloneRow(cell);
                    //列信息
                    byte[] column = CellUtil.cloneQualifier(cell);
    
                    //验证删除的目标数据是否存在,存在则执行删除否则不执行,必须有此判断否则造成协处理器被循环调用耗尽资源
                    boolean flag = relation.exists(new Get(column).addColumn(Bytes.toBytes("friends"), rowkey));
                    if(flag){
                        Delete myDelete = new Delete(column).addColumn(Bytes.toBytes("friends"), rowkey);
                        relation.delete(myDelete);
                    }
                }
            }
        }
    }
    
  3. 将项目打包上传到hdfs

    hadoop fs -put /root/jars/myprocessor.jar /processor
    
  4. 执行RelationDemo类,创建表,添加数据

    查看数据

  5. 添加协处理器

    alter 'relation',METHOD => 'table_att','Coprocessor'=>'hdfs://hadoop01:9000/processor/myprocessor.jar|com.lagou.hbase.MyProcessor|1001|
    

  6. 执行删除操作

    delete 'relation','uid1','friends:uid2'
    

posted @ 2021-01-23 10:38  凯尔哥  阅读(241)  评论(0编辑  收藏  举报