最近,用kettle把DB2的數據抽取到impala上,發現數據量異常,數據錯開等情況。
檢查發現DB2源表裏的數據某個字段中內容含有英文的逗號,而impala上建的表TERMINATED BY ','
也用英文逗號分隔的,所以造成數據錯亂;另外源表數據字段內容包含換行、回車符也會導致到impala數據分隔異常 數據錯亂。
解決方案:針對分隔符,
導致的 ;可以換一種分隔符 |
,重新建表
CREATE TABLE DB_NAME.TB_NAME (
ROW_ID DECIMAL(20,0),
SLOGAN STRING,
CREATED_TIME TIMESTAMP
)
ROW FORMAT DELIMITED FIELDS TERMINATED BY '|'
WITH SERDEPROPERTIES ('field.delim'='|', 'serialization.format'='|')
STORED AS TEXTFILE
LOCATION 'hdfs://IP:8020/user/hive/warehouse/XX.db/TB_NAME'
kettle 數據輸出組件上的分隔符也對應調整
或者不需要重建表,獲取數據時將字段中的英文逗號轉換成中文的replace(SLOGAN,',',',')
如果源數據中存在換行回車符,可以trim(replace(replace(SLOGAN ,CHAR(13),''),CHAR(10),' '))
如果都有直接都替換再傳到impala trim(replace(replace(replace(SLOGAN ,',',',') ,CHAR(13),''),CHAR(10),' '))
發現用kettle抽取DB2數據庫的數據到impala上的表(TEXTFILE格式存儲的表),源表中的字段例如ROW_ID是DECIMAL數值型的,impala上也是DECIMAL數值型的,如果不指定字段的長度和精度,hdfs文件裏有數據內容,但是impala表select時row_id顯示爲null;指定了BigNumber類型的長度和精度後(hdfs文件中該字段值不足20位會在前面用0補齊位數)則能select出來
例如源表字段CREATED_TIME是TIMESTAMP格式的, impala上對應字段也是TIMESTAMP的,hdfs文件裏的內容在時分秒後面有.000000000,則impala上查詢數據時顯示null;
源表日期數據要格式化轉換下to_char(CREATED_TIME,'YYYY-MM-DD HH24:MI:SS') as CREATED_TIME
再傳即可
所以 源表數據字段類型、長度等要匹配上Impala表的字段數據類型,否則select不出來,顯示null
備註:如果是mysql庫裏的TIMESTAMP的字段傳到impala上(impala對應字段類型也是TIMESTAMP),日期數據轉換下date_format(CREATED_TIME,'%Y-%m-%d %H:%i:%S')
or date_format(CREATED_TIME,'%Y-%m-%d %T')
impala常用數據類型: 源自官方文檔
數據類型 | 詳細說明 |
---|---|
BIGINT | Range:-9223372036854775808 - 9223372036854775807 ;用於建表或者sql中:CREATE TABLE t1(x BIGINT);SELECT CAST(1000 AS BIGINT) |
DOUBLE | 存儲4.94065645841246544e-324d 至 1.79769313486231570e+308 範圍內的浮點值 |
DECIMAL | 存儲十進制值 , Range:-10^38 +1 至 10^38 –1,最長的是DECIMAL(38, 0) |
INT | 存儲 -2147483648 至 2147483647範圍內的 4字節 整數 |
SMALLINT | 存儲 -32768至32767範圍內的 2字節 整數 |
TINYINT | 存儲 -128至127範圍內的 1字節 整數 |
FLOAT | 存儲 1.40129846432481707e-45 至 3.40282346638528860e+38 範圍內的單精度浮點值 |
STRING | 存儲 字符串值 |
VARCHAR | 存儲可變長度字符,最大長度爲65535,VARCHAR(max_length) |
CHAR | 存儲固定長度字符,最大長度爲255,CHAR(length) |
BOOLEAN | 只存儲true或false值 |
TIMESTAMP | 存儲時間格式的值,Range: 1400-01-01 to 9999-12-31,DATE_ADD (timestamp, INTERVAL interval time_unit) |
ARRAY | ARRAY < type >,存儲可變數量的有序元素,Complex Types (CDH 5.5 or higher only) |
MAP | MAP < primitive_type, type >,存儲可變數量的鍵值對,Complex Types (CDH 5.5 or higher only) |
STRUCT | STRUCT < name : type [COMMENT ‘comment_string’], … > ,表示單個項目的多個字段,Complex Types (CDH 5.5 or higher only) |
REAL | 是DOUBLE類型的一個別名,REAL and DOUBLE interchangeably(可交換的) |
www:
有張表的記錄數據有創建時間和更新時間 TIMESTAMP
格式,而且數據量較大;而記錄在創建以後可能N天之後會進行更新(大於1次),每天要從DB2數據庫更新數據到impala上;
創建TEXTFILE
格式存儲數據的臨時表和PARQUET
格式的正式表;每天根據臨時表的數據 overwrite 正式表 insert overwrite table XX.XXXX partition(dt_month_id,dt_day_id) select * from XX.XXXX_tmp;
一開始我根據創建時間或者更新時間的年月日創建分區,後面直接獲取最近幾天更新記錄數據,到最後 impala上總記錄數據總是或多(根據更新時間創建分區)或少(根據創建時間創建),因爲獲取的數據量肯定比實際分區文件中的文件或多或少。
最終的解決辦法是:截取創建時間的年月日創建分區cast(to_char(CREATED_TIME,'YYYYMMDD') as int) as dt_day_id
,每天獲取最近幾天更新記錄的創建時間最小值,獲取大於等於最小創建時間的記錄數據 更新那些天的文件: where CREATED_TIME >= (select substr(min(CREATED_TIME),1,10) || ' 00:00:00' from XX.TB_NAME where to_char(LAST_UPD_TIME,'YYYYMMDD') >= to_char(current date - 2 day,'YYYYMMDD') )