感谢博主:解决Hbase数据更新Phoenix对应索引表不更新问题_高矮-CSDN博客
问题描述:
首先感谢上面博主老师的指导。参考上面博主的讲解,得出:用户访问的数据接口直接走Phoenix,也就是往hbase存取数据的话,直接从phoenix走,没有什么问题(没有问题是指:Phoenix的表是映射hbase产生,Phoenix的表会建很多索引,正常通过接口直接写数据进Phoenix表,相应的索引表也是会更新的)。
但是如果直接往hbase中的表存数据,不走phoenix,会发现对应的索引表没有更新,也就是从phoenix上查不到数据,影响正常的访问。
解决方法:
首先,我也是强烈建议往hbase存取数据,还是直接走phoenix,这样就不会在后面采坑。
如果非要直接往hbase中的表存数据,不走phoenix,那么解决方法就是:
在往hbase主表插入的同时,在对应的索引表中也插入一份。
好了,解决方案上面博主也说了,然后也举出实例了,我主要是一方面记录我遇到此问题所解决的过程,另一方面也是对上面博主的进一步细致补充。
1.请看我的hbase表和phoenix映射表,都是一个名字:
2.对应的phoenix和hbase索引表:
3.刚才我们说了,要想在phoenix索引表上查到数据,就要在hbase主表上插完的同时,在对应的索引表上也插入一份。
4.插入主表的代码,我在这里简略写一下:
首先是获取rowkey,这里的rowkey在下面索引表插入中会用到。
//简写
Put put = new Put(Bytes.toBytes(rowKey));
dataMap.forEach((key, value) -> {
put.addColumn(Bytes.toBytes("data"), Bytes.toBytes(key),
Bytes.toBytes("" + value));
});
Result result = baseService.insertData(key, tableNameAndDataMap.get(key));
5.剩下的就是往索引表进行插入,这里面有两个坑:
一是拼接字符串坑。我们可以看下对应的索引表的主键是什么?看下图:
索引的主键是原表的字段组合而成的,索引表会把所有索引字段+rowkey拼接起来写进Hbase ,做为索引表的RowKey。并且组合的时候还要加上\x00这样的奇怪字段。所以我们要把字段进行拼接之后,往索引表里面插入。一开始我想到的是Stringbuilder中的append()方法,使用多次append()方法进行拼接,例如下图的方式:
但是最后我发现自己错了。这就是第二个坑。
二是‘\’转义的坑。起初以为直接以拼接字符串的形式往里插就可以,但是发现hbase会对\做二进制转译,‘\’会被转译为\x5c,如图:
那现在怎么做到拼接的时候,不会出现\x5c呢,也就说不被转义呢?
解决的方案就是:
在插入数据的时候直接以byte[] 的形式往hbase表插。
例子如下所示:
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.hadoop.hbase.util.Bytes;
import java.util.Map;
/**
* 插入hbase索引表 主键字段拼接
*/
public class RowKeyIndex {
public static byte[] rowKeyIndex(Map<String, String> dataMap, String rowKey) {
byte[] addFour;
byte[] modelIDS = Bytes.toBytes(dataMap.get("modelID"));
byte transformChar = (byte) 0;
byte[] transfromChars = new byte[]{transformChar};
byte[] addOne = ArrayUtils.addAll(modelIDS, transfromChars);
byte[] deviceIDS = Bytes.toBytes(dataMap.get("deviceID"));
byte[] addTwo = ArrayUtils.addAll(deviceIDS, transfromChars);
byte[] oneAddTwo = ArrayUtils.addAll(addOne, addTwo);
byte[] deviceTimes = Bytes.toBytes(dataMap.get("deviceTime"));
byte[] addThree = ArrayUtils.addAll(deviceTimes, transfromChars);
if (StringUtils.isBlank(dataMap.get("processState"))) {
addFour = ArrayUtils.addAll(null, transfromChars);
} else {
byte[] processStates = Bytes.toBytes(dataMap.get("processState"));
addFour = ArrayUtils.addAll(processStates, transfromChars);
}
byte[] threeAddFour = ArrayUtils.addAll(addThree, addFour);
byte[] oneToFour = ArrayUtils.addAll(oneAddTwo, threeAddFour);
byte[] rowKeyBytes = Bytes.toBytes(rowKey);
byte[] rowKeyIndex = ArrayUtils.addAll(oneToFour, rowKeyBytes);
return rowKeyIndex;
}
}
上面的代码是我对字段拼接的过程,要注意了:
每个字段都要以如下这样的形式获取,切记!:
byte[] modelIDS = Bytes.toBytes();
然后\x00就用下面的形式解决。
byte transformChar = (byte) 0;
byte[] transfromChars = new byte[]{transformChar};
剩下的就是把各个字段拼接在一起,可以用ArrayUtils.addAll进行拼接在一起,多用几次而已,最后返回自己的索引rowkey。
6.索引表插入的代码简写:
//调用RowKeyIndex类中的方法
byte[] rowKeyIndex = RowKeyIndex.rowKeyIndex(dataMap, rowKey);
//向表中插入数据
Put putIndex = new Put(rowKeyIndex);
//存入hbase索引表
Result resultIndex = baseService.insertData(key, tableNameAndDataMapIndex.get(key));
好了兄弟们,就到这里吧!!!!!