之前我們是這樣獲取數(shù)據(jù)的:
Get get = new Get(Bytes.toBytes("row1"));//定義get對象
Result result = table.get(get);//通過table對象獲取數(shù)據(jù)
那么問題來了,我們想要獲取多條數(shù)據(jù),比如說查詢1萬條數(shù)據(jù)怎么辦呢屉符?
可能我們第一時間就會想到循環(huán),例如:
String tableName = "test";
Table table = connection.getTable( TableName.valueOf(tableName));// 獲取表
for (String rowkey : rowkeyList){
Get get = new Get(Bytes.toBytes(rowkey));
Result result = table.get(get);
for (Cell kv : result.rawCells()) {
String value = Bytes.toString(CellUtil.cloneValue(kv));
list.add(value);
}
}
這樣做是非常低效的,如果有10000
條數(shù)據(jù)那我們需要發(fā)送10000
次請求矗钟,這樣非常耗時唆香,如果在自己本機(jī)上嘗試,查詢時間可能在5
分鐘左右吨艇。
這樣肯定不行袋马,我們在HBase的Table
對象和子類的源碼中找找看有沒有解決辦法,忽然眼前一亮:
public Result[] get(List<Get> gets) throws IOException {
if (gets.size() == 1) {
return new Result[]{get(gets.get(0))};
}
try {
Object[] r1 = new Object[gets.size()];
batch((List<? extends Row>)gets, r1, readRpcTimeoutMs);
// Translate.
Result [] results = new Result[r1.length];
int i = 0;
for (Object obj: r1) {
// Batch ensures if there is a failure we get an exception instead
results[i++] = (Result)obj;
}
return results;
} catch (InterruptedException e) {
throw (InterruptedIOException)new InterruptedIOException().initCause(e);
}
}
使用get函數(shù)批量獲取數(shù)據(jù)
查看HBase的API秸应,我們可以發(fā)現(xiàn)Table
對象的get()
函數(shù)不僅可以接收Get
對象,也同樣可以接收Get
集合碑宴,現(xiàn)在我們試試get(List<Get> gets)
函數(shù)的效果如何软啼。
public List<String> getData(Table table, List<String> rows) throws Exception {
List<Get> gets = new ArrayList<>();
for (String str : rows) {
Get get = new Get(Bytes.toBytes(str));
gets.add(get);
}
List<String> values = new ArrayList<>();
Result[] results = table.get(gets);
for (Result result : results) {
System.out.println("Row:" + Bytes.toString(result.getRow()));
for (Cell kv : result.rawCells()) {
String family = Bytes.toString(CellUtil.cloneFamily(kv));
String qualifire = Bytes.toString(CellUtil.cloneQualifier(kv));
String value = Bytes.toString(CellUtil.cloneValue(kv));
values.add(value);
System.out.println(family + ":" + qualifire + "\t" + value);
}
}
return values;
}
根據(jù)這種批量的方法,10000
個row
進(jìn)行查詢延柠,時間穩(wěn)定在4s
之內(nèi)祸挪,
使用上述代碼查詢下表:
輸出結(jié)果:
Row:20001
data:1 value1
data:2 value2
data:3 value3
data:4 value4
Row:20002
data:1 name1
data:2 name2
data:3 name3
data:4 name4
代碼解釋:
-
table.get(gets)
會返回一個Result[]
結(jié)果數(shù)組,里面存放了本次查詢的所有數(shù)據(jù)贞间,我們可以通過這個數(shù)組來遍歷我們需要的數(shù)據(jù)贿条; -
result.rawCells()
,result
是單個結(jié)果增热,這里存放的是一行的所有數(shù)據(jù)整以,result
的rowCells()
方法會返回這一行所有的列(Cell
)的集合; -
Cell
對象是單個的列峻仇,要獲取列中的值可以通過CellUtil.cloneXXX()
方法公黑,如cloneValue(cell)
就會返回該列的值。
刪除單行數(shù)據(jù)
刪除一行數(shù)據(jù)很簡單摄咆,我們來看個示例:
Table table = conn.getTable(tableName); //獲取表
byte[] row = Bytes.toBytes("row1");//定義行
Delete delete = new Delete(row);//創(chuàng)建delete對象
table.delete(delete);//刪除
這段代碼就可以刪除行鍵為row1
的行凡蚜。
刪除多行數(shù)據(jù)
如何刪除多行數(shù)據(jù)呢?
相信你已經(jīng)猜到了吭从,既然get()
方法有重載方法朝蜘,那應(yīng)該delete()
方法也有,確實:
Table table = conn.getTable(tableName);
List<Delete> deletes = new ArrayList<>();
for(int i = 1 ; i < 5;i++){
byte[] row = Bytes.toBytes("row" + i);
Delete delete = new Delete(row);
deletes.add(delete);
}
table.delete(deletes);
這樣就可以刪除多行數(shù)據(jù)啦涩金。
每一次只添加一個數(shù)據(jù)顯然不像是大數(shù)據(jù)開發(fā)谱醇,在開發(fā)項目的時候也肯定會涉及到大量的數(shù)據(jù)操作。
使用Java進(jìn)行批量數(shù)據(jù)操作步做,其實就是循環(huán)的在Put
對象中添加數(shù)據(jù)最后在通過Table
對象提交枣抱。
如何進(jìn)行批量操作呢,講到批量操作辆床,相信大家肯定第一時間會想到循環(huán)佳晶?
沒錯,使用循環(huán)確實就可以添加多個數(shù)據(jù)了讼载,示例:
Table tableStep3 = connection.getTable(tableStep3Name);
// 循環(huán)添加數(shù)據(jù)
byte[] row = Bytes.toBytes("20001");
Put put = new Put(row);
for (int i = 1; i <= 4; i++) {
byte[] columnFamily = Bytes.toBytes("data");
byte[] qualifier = Bytes.toBytes(String.valueOf(i));
byte[] value = Bytes.toBytes("value" + i);
put.addColumn(columnFamily, qualifier, value);
}
tableStep3.put(put);
代碼執(zhí)行結(jié)果:
可以發(fā)現(xiàn)轿秧,這一段代碼向同一個行中添加了四列數(shù)據(jù)中跌。
我們要添加多行數(shù)據(jù)應(yīng)該如何處理呢,我猜你肯定想到了:使用集合菇篡!
List<Put> puts = new ArrayList<>();
// 循環(huán)添加數(shù)據(jù)
for (int i = 1; i <= 4; i++) {
byte[] row = Bytes.toBytes("row" + i);
Put put = new Put(row);
byte[] columnFamily = Bytes.toBytes("data");
byte[] qualifier = Bytes.toBytes(String.valueOf(i));
byte[] value = Bytes.toBytes("value" + i);
put.addColumn(columnFamily, qualifier, value);
puts.add(put);
}
Table table = connection.getTable(tableName);
table.put(puts);
上述代碼向HBase中添加了四行數(shù)據(jù)漩符,結(jié)合上次,可以發(fā)現(xiàn)table
對象的put()
方法是一個重載方法既可以接收Put
對象也可以接收Put
集合驱还。
添加完數(shù)據(jù)的表結(jié)構(gòu):