背景
由於新需求需要新建hbase表,將hdfs中給定的目錄下的文件導入到hbase表中,一種格式的文件(多種格式可能需要合併吧,目前沒有這個需求,但是也可以分多次導入到hbase中吧,除非rowkey的構成需要多個文件,目前沒有這種需求)。
下面總結一下,寫這個工具的過程和遇到的一些坑。
1.調研有什麼樣的方式導入
網上查了有很多種方式,比如數據少可以直接讀取插入,或者bulkload,在這不介紹沒中方式的優缺點,詳細的可以看
https://www.ibm.com/developerworks/cn/opensource/os-cn-data-import/index.html
介紹了導入到hbase的幾種方式
最後選擇的是bulkload的方式,下面介紹一下代碼和過程
2.格式化原始數據
1. 數據獲取
首先是原始數據的獲取,我們是從hdfs中直接獲取的文件,文件是採用deflate壓縮的,但是我們不需要自己去解壓,java api還是非常好用,會根據壓縮的格式獲取解壓的方法具體代碼如下:
讀取壓縮的文件主要參考這個文章,核心代碼如下
CompressionCodecFactory factory = new CompressionCodecFactory(conf);
InputStream stream = null;
CompressionCodec codec = factory.getCodec(file.getPath());
//判斷是否使用了壓縮編碼器
if (codec != null) {
stream = codec.createInputStream(inputFs.open(file.getPath()));
} else {
stream = inputFs.open(file.getPath());
}
最後會獲取到輸入流。
注意:1. 這裏的conf,一定要加上這個配置,不然會報錯的
// 不設置該代碼會出現錯誤:java.io.IOException: No FileSystem for scheme: hdfs
conf.set("fs.hdfs.impl", "org.apache.hadoop.hdfs.DistributedFileSystem");
2. 讀取本地的hdfs和讀取線上集羣是有區別的
如果是本地 fs.defaultFS
hdfs://master:8020改爲hdfs://xxx,我們不能直接在路徑上會報錯
Exception in thread "main" java.lang.IllegalArgumentException: java.net.UnknownHostException: xxx
xxx是自己定義的
需要配置一些參數,具體的配置可以參考,每一個配置項都寫好了
2. 格式化數據
上一步解壓之後我們的數據其實和用hadoop dfs -text輸出的格式是一樣的,不需要特殊處理,只要符合
1 0 1 1 107 1511856292918 1565700796561
每一行都是這種格式中間的分隔符不限制,可以在讀取的時候作爲參數輸入
格式化之後是輸出到另一個hdfs目錄,因爲hbase的bulkload的要以hdfs的目錄或文件作爲輸入,所以可以直接寫到另一個hdfs目錄
這裏可能hdfs不是同一個集羣,那麼我們不能使用一個 FileSystem,我們需要在創建新的對象,如果是一個我們可以直接用。(這裏說的有點不太清楚,但是公司的代碼不能全都粘貼出來,到時候可以自己試一下,或者評論問一下)。
直接用 FSDataOutputStream 類就可以輸出到具體文件
經過這一步數據的準備就好了,我們可以生成一個或多個文件
3.生成HFILE
具體代碼可以參考
這個代碼使用的hbase應該是1.0以下的,因爲HTable在我的版本中已經是廢棄的了,所以在某些步驟上我改了改。
我的Hbase是1.2.0,connectin類是org.apache.hadoop.hbase.client.Connection
HTable table = new HTable(conf, args[0]);
//更改成下面的
Table table = HBaseConfig.getConnection().getTable(tableName);
//HBaseConfig.getConnection() 是自己封裝的一個hbase的connection,這個應該和普通,
//在1.2.0適用connection來獲取表等,具體可以去看hbase的api
load.doBulkLoad(new Path(args[2]), table);
//這行代碼更改成調用新的接口
org.apache.hadoop.hbase.mapreduce.LoadIncrementalHFiles#doBulkLoad(org.apache.hadoop.fs.Path, org.apache.hadoop.hbase.client.Admin, org.apache.hadoop.hbase.client.Table, org.apache.hadoop.hbase.client.RegionLocator)
Admin=connection.getAdmin()
RegionLocator=connection.getRegionLocator(tableName)