HBase踩坑筆記 - 使用 MR 集成Hbase 報錯 IllegalArgumentException: No columns to insert ⭐️⭐️⭐️⭐️

錯誤描述

今天在 使用 MapReduce 將 Person 表中的 name 字段 的數據 寫入到 Person_mr 表中 報錯
代碼 如下 :
Mapper

package com.wangt.habse.mr01;

import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableMapper;
import org.apache.hadoop.hbase.util.Bytes;

import java.io.IOException;

/**
 * 從 Person 表中讀取數據 寫到 Person_mr 表中
 *
 * @author 王天賜
 * @create 2019-08-02 20:08
 */
public class PersonMapper extends TableMapper<ImmutableBytesWritable, Put> {
    //  輸出類型是 ImmutableBytesWritable(序列化的Byte 數組) 和  Put

    /**
     * 從 Hbase 的 Person 表中讀取數據
     *
     * @param key     rowkey
     * @param value   從 Hbase 表中讀取數據的 Result 對象
     * @param context
     * @throws IOException
     * @throws InterruptedException
     */
    @Override
    protected void map(ImmutableBytesWritable key, Result value, Context context)
            throws IOException, InterruptedException {

        // 構建 Put 對象
        // 注意 : 這個key是序列化的 rowkey
        Put put = new Put(key.get());
        System.out.println(Bytes.toString(key.get()));
        // 遍歷數組
        Cell[] cells = value.rawCells();
        for (Cell cell : cells) {
            // 獲取 HBase 的列
           String qualifier = Bytes.toString(CellUtil.cloneQualifier(cell));
           //  列族
           String family =  Bytes.toString(CellUtil.cloneFamily(cell));
           switch (qualifier) {
                // 判斷字段 是否是 name
                // 如果是 name 列 ,則將 name列的數據 添加到 Put 對象中 注意 一個 map 只讀一條數據
                case "name":
                    put.add(cell);
                    break;
           }
        }
            context.write(key, put);
        }
    }

Reducer

package com.wangt.habse.mr01;

import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.mapreduce.TableReducer;
import org.apache.hadoop.io.NullWritable;

import java.io.IOException;

/**
 * 將數據寫入到 Person_mr 表中
 *
 * @author 王天賜
 * @create 2019-08-02 20:12
 */
public class PersonReducer extends TableReducer<ImmutableBytesWritable, Put, ImmutableBytesWritable> {

    @Override
    protected void reduce(ImmutableBytesWritable key, Iterable<Put> values, Context context) throws IOException, InterruptedException {

        // 將 put 直接輸出即可
        // put 中封裝了 存入新表的數據
        for (Put value : values) {
            context.write(key, value);
        }
    }
}

然後就 報錯
Error: java.lang.IllegalArgumentException: No columns to insert
一開我以爲 是沒讀到數據 ,但是我看了下 打印的日誌
在這裏插入圖片描述
發現讀到數據了 , 又檢查下代碼 ,怎麼想都想不明白 明明讀入數據了 , 但是還是不明白 爲什麼會報這種錯誤 .,然後我根據報錯位置查了下這個報錯觸發的原因
在這裏插入圖片描述
在這裏插入圖片描述
當 滿足 Put.isEmpty 爲 true 的時候 則會拋出異常 ,然後我看了下 put 爲 空的條件
在這裏插入圖片描述
找到 familyMap
在這裏插入圖片描述
可以看到這裏存儲的 是 Cell 對象 ,
如下 圖 , 可以看到 我們使用 put 添加的數據最終都添加到 familyMap
在這裏插入圖片描述
familymap的k是 列族 , KeyValue 是 Cell的 子類 KeyValue 的集合
在這裏插入圖片描述

那麼接下來 分析我們的代碼 , 這裏已經可以確定報錯的大致原因 :

  1. Map 階段是 從 Person 中讀取數據 Person 表中有 兩個列 分別是 name 和 age 我現在需要把 Person 表中的Name列的數據輸出到 Person_mr 表中, 報錯,出現讀取的某一個 Cell 或者 某幾個 不存在 name 字段
  2. 猜測 : 可能是 某一條數據中沒有 name 字段

然後 我仔細檢查了下 之前的數據 , 然後果然發現問題
在這裏插入圖片描述
可以看到 : 最後一條數據沒有 name 列 ,在 讀取的時候 是讀取不到的 ,又因爲 一個 put 只添加了 一條 name 列的數據, 所以 出現問題

所以 只需要在 輸出到 Reduce 時檢查下 put 是否爲空 即可

 if(!put.isEmpty()){
            // 輸出
            context.write(key, put);
        }

補充 :

如果 你遇到和 我相同的問題 , 建議不要上來直接拿我的解決辦法 , 可以參考我的思路找到自己的問題所在, 這樣才能解決問題

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章