【hbase】——bulk load导入数据时value=\x00\x00\x00\x01问题解析

时间:2021-08-17 11:01:23

一、存入数据类型

Hbase里面,rowkey是按照字典序进行排序。存储的value值,当用filter进行数据筛选的时候,所用的比较算法也是字典序的。

1、当存储的value值是float类型的时候,录入数据可以录入,但是读取出来的数据会存在问题会出问题

例如:

存入数据的代码:

p = new Put(Bytes.toBytes(“66”));

p.add(Bytes.toBytes("value"),Bytes.toBytes("null"), (Long.valueOf(“668”) ), Bytes.toBytes(Float.valueOf(533.0)));

...

在hbase shell里面取出的数据:

hbase(main):007:0> get 'DATA‘, '66'
COLUMN                CELL
value:null           timestamp=668, value=D\x05@\x00
1 row(s) in 0.1100 seconds
可以看到取出来的value值是不可读的。

在java程序里面则没有返回结果,如果想强制类型转换读取这个数据,则会报错,说格式错误:

  try {
   Result rr = table.get(g);
   for (KeyValue kvv : rr.raw()) {
float f = Float.parseFloat(new String(kvv.getValue()));
    System.out.println(f);
    tempList.add(kvv.getTimestamp() + "," + new String(kvv.getValue()));
   }
  } catch (IOException e) {
   e.printStackTrace();
  }

java.lang.NumberFormatException: For input string: "D@"

根据hbase都是按照字典序进行排序的前提,(字典序多少针对字符串的),可以推测hbase不支持float类型数据的存储

2、如果把录入数据改成int型

存入数据的代码:

p = new Put(Bytes.toBytes(“66”));

p.add(Bytes.toBytes("value"),Bytes.toBytes("null"), (Long.valueOf(“668”) ), Bytes.toBytes(Integer.valueOf(533.0)));

...

取出的数据

hbase(main):007:0> get 'DATA‘, '66'

COLUMN CELL
value:null timestamp=668, value=\x00\x00\x00\x00\x00\x00\x02\x15
1 row(s) in 1.4510 seconds

在java程序里面则没有返回结果,当试图把取出的数据强制类型转换的时候,同样报错

3、 如果把录入数据改成long型

存入数据的代码:

p = new Put(Bytes.toBytes(“66”));

p.add(Bytes.toBytes("value"),Bytes.toBytes("null"), (Long.valueOf(“668”) ), Bytes.toBytes(Long.valueOf(533.0)));

...

取出的数据

hbase(main):007:0> get 'DATA‘, '66'

COLUMN                CELL
value:null           timestamp=668, value=\x00\x00\x00\x00\x00\x00\x02\x15
1 row(s) in 1.4510 seconds

同样不可读

4、如果把录入value格式改成String类型,则正常

存入数据的代码:

p = new Put(Bytes.toBytes(“66”));

p.add(Bytes.toBytes("value"),Bytes.toBytes("null"), (Long.valueOf(“668”) ), Bytes.toBytes("533.0"));

...

取出的数据

hbase(main):007:0> get 'DATA‘, '66'

COLUMN                CELL
value:null           timestamp=668, value=533.0
1 row(s) in 0.8500 seconds

在java程序里面也有可用的结果

通过上述测试说明,hbase现在只支持String类型数据的存取

二、 小的注意点

1、取value的时候一定要用 new String(kv[i].getValue())的格式

    System.out.println(kv[i].getValue().toString());     错误
    System.out.println(new String(kv[i].getValue()));    正确

2、用完ResultScanner 后一定要记得关掉:resultScanner.close();

3、当录入的数据已经使用了String类型

那么,进行比较的时候也要使用String类型。例如下面使用float类型的filter,则不会对结果产生任何影响

  Filter filter = new SingleColumnValueFilter(
             Bytes.toBytes("value"),Bytes.toBytes("null") , CompareOp.LESS,Bytes.toBytes(Float.valueOf((float) 5.0)));
  scan.setFilter(filter); 
如果换成

  Filter filter = new SingleColumnValueFilter(
             Bytes.toBytes("value"),Bytes.toBytes("null") , CompareOp.LESS,Bytes.toBytes("5.0"));

scan.setFilter(filter);

则会会结果产生影响,但是需要注意的是,这里的设置方式也是错误的

追踪原因:

hbase关于比较的相关源码如下:

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

 
  public static int compareTo(final byte [] left, final byte [] right) {
    return compareTo(left, 0, left.length, right, 0, right.length);
  }

 
  public static int compareTo(byte[] buffer1, int offset1, int length1,
      byte[] buffer2, int offset2, int length2) {
    // Bring WritableComparator code local
    int end1 = offset1 + length1;
    int end2 = offset2 + length2;
    for (int i = offset1, j = offset2; i < end1 && j < end2; i++, j++) {
      int a = (buffer1[i] & 0xff);
      int b = (buffer2[j] & 0xff);

      if (a != b) {
        return a - b;
      }
    }
    return length1 - length2;
  }

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

疑问:下面long型筛选,返回的结果并没有value值,但是,结果的数据条数却会发生变化,即使针对这个特定的时间戳读取数据也没有结果数据(曾试图用scan确定了那个rowkey的那个列簇的那个列的那个时间戳,任何通过这些信息用get进行取值,但是也不能返回value值),为什么结果的条数会发生变化呢?

1、filter

(1)录入的value是long型

如果想设置成数值型比较,则要进行数据类型设置,如下

Filter filter = new SingleColumnValueFilter(
             Bytes.toBytes("value"),Bytes.toBytes("null") , CompareOp.LESS,Bytes.toBytes(Long.valueOf(5)));
  scan.setFilter(filter);

resultScanner = table.getScanner(scan);

结果是:

rowkey                         列簇:列名 时间戳   value

115404869300388065  value:null     27

115404869300388065  value:null     26

但是如果设置成字符串行,如下:

Filter filter = new SingleColumnValueFilter(
Bytes.toBytes("value"),Bytes.toBytes("null") , CompareOp.LESS,Bytes.toBytes(”5“));
scan.setFilter(filter);

resultScanner = table.getScanner(scan);

则返回的是按照字典序比较的结果(ps:rowkey是按照字典序排列的,10000比2 “小”)

115404869300388065  value:null  27

115404869300388065  value:null  3

115404869300388065  value:null  2

115404869300388065  value:null  1

细心的话可以发现输出的几个也是按照降序的顺序排列的