Hbase中通用的查询方法

发布于 2020-06-02  191 次阅读



    /**
     * 根据行键读取内容
     *
     * @param key
     * @param tablename
     * @param connection
     * @return
     */
    public Map<String, Object> fetchbykey(String key, String tablename, Connection connection) {
        Map<String, Object> tempMap = new HashMap<String, Object>(); //用于逐列存储数据 ,按照 family:qualifier value的形式存储
        Map<String, Object> resMap = new HashMap<String, Object>();  //返回值
        String rowname = null; //列名
        List<String> familynamelist = new ArrayList<String>();  //用于存储列族
        try {
            //取得表对象
            Table table = connection.getTable(TableName.valueOf(tablename));
            //根据keyrow查询结果
            Result result = table.get(new Get(Bytes.toBytes(key)));
            //列出所有单元格
            List<Cell> cells = result.listCells();
            for (Cell cell : cells) {
                byte[] rowArray = cell.getRowArray();
                byte[] familyArray = cell.getFamilyArray();
                byte[] qualifierArray = cell.getQualifierArray();
                byte[] valueArray = cell.getValueArray();
                int rowoffset = cell.getRowOffset();
                int familyoffset = cell.getFamilyOffset();
                int qualifieroffset = cell.getQualifierOffset();
                int valueoffset = cell.getValueOffset();
                int rowlength = cell.getRowLength();
                int familylength = cell.getFamilyLength();
                int qualifierlength = cell.getQualifierLength();
                int valuelength = cell.getValueLength();
                // 通过复制取得一个rowkey
                byte[] temprowarray = new byte[rowlength];
                System.arraycopy(rowArray, rowoffset, temprowarray, 0, rowlength);
                String temprow = Bytes.toString(temprowarray);
//            System.out.println(Bytes.toString(temprowarray));
                // 取得列键
                byte[] tempqulifierarray = new byte[qualifierlength];
                System.arraycopy(qualifierArray, qualifieroffset, tempqulifierarray, 0, qualifierlength);
                String tempqulifier = Bytes.toString(tempqulifierarray);
//            System.out.println(Bytes.toString(tempqulifierarray));
                // 取得列族
                byte[] tempfamilyarray = new byte[familylength];
                System.arraycopy(familyArray, familyoffset, tempfamilyarray, 0, familylength);
                String tempfamily = Bytes.toString(tempfamilyarray);
//            System.out.println(Bytes.toString(tempfamilyarray));
                //取得值
                byte[] tempvaluearray = new byte[valuelength];
                System.arraycopy(valueArray, valueoffset, tempvaluearray, 0, valuelength);
                String tempvalue = Bytes.toString(tempvaluearray);
//            System.out.println(Bytes.toString(tempvaluearray));
                // 把信息以 family : qulifier value 的形式放在map中
                tempMap.put(tempfamily + ":" + tempqulifier, tempvalue);
//            long t= cell.getTimestamp();
//            tempMap.put("timestamp",t);
                //把列键作为列名
                rowname = temprow;
                String familyname = tempfamily;
                //如果列族list中没有这一项,则添加进去
                if (familynamelist.indexOf(familyname) < 0) {
                    familynamelist.add(familyname);
                }
            }
            //把rowname放在map中
            resMap.put("rowname", rowname);
            for (String familyname : familynamelist) {  //在列族list中进行遍历
                HashMap<String, Object> tempFilterMap = new HashMap<String, Object>(); //新建一个Map,用于存放不同的列族
                for (String newkey : tempMap.keySet()) {  //对每列数据进行遍历,下一步为分割
                    String[] keyArray = newkey.split(":");  //分割之前存储的列键和列族
                    if (keyArray[0].equals(familyname)) {  //把列族和列键进行对比,如果相同,则把数据放在这个列族中
                        tempFilterMap.put(keyArray[1], tempMap.get(newkey));
                    }
                }
                resMap.put(familyname, tempFilterMap);  //针对不同的列键进行分类
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        Gson gson = new Gson();
        String s = gson.toJson(resMap);
        System.out.println(s);
        return resMap;
    }

让我们逐段逐段的解析这个方法

        Map<String, Object> tempMap = new HashMap<String, Object>(); //用于逐列存储数据 ,按照 family:qualifier value的形式存储
        Map<String, Object> resMap = new HashMap<String, Object>();  //返回值
        String rowname = null; //列名
        List<String> familynamelist = new ArrayList<String>();  //用于存储列族

此处声明了四个变量,除了rowname为字符以外,其余的皆为容器,用途在下文会讲到

            //取得表对象
            Table table = connection.getTable(TableName.valueOf(tablename));
            //根据keyrow查询结果
            Result result = table.get(new Get(Bytes.toBytes(key)));
            //列出所有单元格
            List<Cell> cells = result.listCells();

根据形参所提供的连接对象,可以得到表对象,而通过表对象的get(Get get)方法,则可以拿到对应着形参中rowkey(行键)的信息,而通过这个行键,则可以获得整行单元格的信息。这是一个【三段式】的调用,没啥技术含量,但是必不可少

            for (Cell cell : cells) {
                byte[] rowArray = cell.getRowArray();
                byte[] familyArray = cell.getFamilyArray();
                byte[] qualifierArray = cell.getQualifierArray();
                byte[] valueArray = cell.getValueArray();
                int rowoffset = cell.getRowOffset();
                int familyoffset = cell.getFamilyOffset();
                int qualifieroffset = cell.getQualifierOffset();
                int valueoffset = cell.getValueOffset();
                int rowlength = cell.getRowLength();
                int familylength = cell.getFamilyLength();
                int qualifierlength = cell.getQualifierLength();
                int valuelength = cell.getValueLength();

在遍历整行单元格的过程中,通过【每个】单元格提供的方法,可以获得该单元格的基础信息,有这四项值得注意:

Family(列族)、qualifier(列键)、value(值)、Row(行键),而由于hbase中用char存储信息,所以每一项基础信息又分别拥有两种属性:offset(偏移量)、length(长度),通过这两种属性,下一步我们将会把字节流char转为String。

                // 通过复制取得一个rowkey
                byte[] temprowarray = new byte[rowlength];
                System.arraycopy(rowArray, rowoffset, temprowarray, 0, rowlength);
                String temprow = Bytes.toString(temprowarray);
//            System.out.println(Bytes.toString(temprowarray));
                // 取得列键
                byte[] tempqulifierarray = new byte[qualifierlength];
                System.arraycopy(qualifierArray, qualifieroffset, tempqulifierarray, 0, qualifierlength);
                String tempqulifier = Bytes.toString(tempqulifierarray);
//            System.out.println(Bytes.toString(tempqulifierarray));

通过byte数组的构造方法,创建一个空的byte数组,接着使用arraycopy方法,把前一步获得的例如family,value等值的信息赋给这个空的数组,arraycopy(Object src, int srcPos, Object dest, int destPos, int length)的五个形参分别为:

原始数组、偏移量、待赋值数组、开始位置(一般为0)、待赋值数组长度

赋值完毕之后,通过Bytes.tostring方法,把这个数组转为String字符

此步的意义在于:把获得的char数组转换为String字符

                tempMap.put(tempfamily + ":" + tempqulifier, tempvalue);
                //把列键作为列名
                rowname = temprow;
                String familyname = tempfamily;
                //如果列族list中没有这一项,则添加进去
                if (familynamelist.indexOf(familyname) < 0) {
                    familynamelist.add(familyname);
                }
       }

在最早事先声明的容器中,tempmap代表的是一个【临时存放除了行键外所有信息的容器】,在这里通过【family:qulifier-value】形式的【键值对】进行存放以备用 。而之前获得的行键,此处用于表示一行的名字用于做唯一的标识符。而之前获得的列族赋值给familyname,表示临时的列族名。随后判断下列族名列中是否含有这个列族,如果没有,则添加进去,此处的用意为【找到所有的列族】并记录下来,这一步结束,跳出循环

            resMap.put("rowname", rowname);
            for (String familyname : familynamelist) {  //在列族list中进行遍历
                HashMap<String, Object> tempFilterMap = new HashMap<String, Object>(); //新建一个Map,用于存放不同的列族
                for (String newkey : tempMap.keySet()) {  //对每列数据进行遍历,下一步为分割
                    String[] keyArray = newkey.split(":");  //分割之前存储的列键和列族
                    if (keyArray[0].equals(familyname)) {  //把列族和列键进行对比,如果相同,则把数据放在这个列族中
                        tempFilterMap.put(keyArray[1], tempMap.get(newkey));
                    }
                }
                resMap.put(familyname, tempFilterMap);  //针对不同的列键进行分类
            }

通过put方法,把【唯一标识符】行键以键值对的形式添加在【返回值】中。

遍历【临时变量】,通过分割拿到【列族】,通过对比判断列族是否等于列族列表中的某一项,如果相等,则把数据放在以此列族为键的map中,反之亦然

最终把结果返回回去


忍耐无法忍耐的事物,才是真正的忍耐。