本文介紹CSV、TSV格式的OSS外部表格的建立、讀取及寫入方法。
適用範圍
OSS外部表格不支援cluster屬性。
單個檔案大小不能超過2GB,如果檔案過大,建議拆分。
MaxCompute需要與OSS部署在同一地區。
支援資料類型
MaxCompute資料類型詳情請參見1.0資料類型版本、2.0資料類型版本。
更多有關SmartParse的說明,請參見Smart Parse更靈活的類型相容能力
資料類型 | com.aliyun.odps.CsvStorageHandler/ TsvStorageHandler (內建文本資料解析器) | org.apache.hadoop.hive.serde2.OpenCSVSerde (內建開來源資料解析器) |
TINYINT | ||
SMALLINT | ||
INT | ||
BIGINT | ||
BINARY | ||
FLOAT | ||
DOUBLE | ||
DECIMAL(precision,scale) | ||
VARCHAR(n) | ||
CHAR(n) | ||
STRING | ||
DATE | ||
DATETIME | ||
TIMESTAMP | ||
TIMESTAMP_NTZ | ||
BOOLEAN | ||
ARRAY | ||
MAP | ||
STRUCT | ||
JSON |
支援壓縮格式
當讀寫壓縮屬性的OSS檔案時,需要在建表語句中添加with serdeproperties屬性配置,詳情請參見with serdeproperties屬性參數。
壓縮格式 | com.aliyun.odps.CsvStorageHandler/ TsvStorageHandler (內建文本資料解析器) | org.apache.hadoop.hive.serde2.OpenCSVSerde (內建開來源資料解析器) |
GZIP | ||
SNAPPY | ||
LZO |
支援Schema Evolution
操作類型 | 是否支援 | 說明 |
添加列 |
| |
刪除列 | 不建議使用,會出現Schema和資料不對應的問題。 | |
修改列順序 | 不建議使用,會出現Schema和資料不對應的問題。 | |
更改列資料類型 | 資料類型支援轉換表見更改列資料類型。 | |
修改列名 | ||
修改列注釋 | 注釋內容為長度不超過1024位元組的有效字串,否則報錯。 | |
修改列的非空屬性 | 不支援此操作,預設為Nullable。 |
參數配置
CSV和TSV外表的Schema和檔案列之間按位置映射。當讀取的OSS檔案的檔案列數和外部表格的Schema列不一致時,可通過odps.sql.text.schema.mismatch.mode參數指定對於列數不一致行的處理方式。
當
odps.sql.text.schema.mismatch.mode=truncate時,修改列操作後符合修改後的Schema結構的資料,可以正常讀取;
存量舊Schema資料沒有進行修改列操作,該表按新Schema讀。
例如,表添加列後,歷史資料沒有添加對應列,讀表時該列的歷史資料會補為NULL。
當
odps.sql.text.schema.mismatch.mode=ignore時,修改列操作後符合修改後的Schema結構的資料,可以正常讀取;
存量舊Schema資料沒有進行修改列操作,該表按新Schema讀。
例如,表添加列後,歷史資料沒有添加對應列,讀表時會把歷史資料整行丟棄。
當
odps.sql.text.schema.mismatch.mode=error時,修改列操作後符合修改後的Schema結構的資料,可以正常讀取;
存量舊Schema資料沒有進行修改列操作,該表按新Schema讀。
例如,表添加列後,歷史資料沒有添加對應列,讀表時會報錯。
建立外部表格
文法結構
內建文本資料解析器
CSV格式
CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name>
(
<col_name> <data_type>,
...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)]
STORED BY 'com.aliyun.odps.CsvStorageHandler'
[WITH serdeproperties (
['<property_name>'='<property_value>',...]
)]
LOCATION '<oss_location>'
[tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];TSV格式
CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name>
(
<col_name> <data_type>,
...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)]
STORED BY 'com.aliyun.odps.TsvStorageHandler'
[WITH serdeproperties (
['<property_name>'='<property_value>',...]
)]
LOCATION '<oss_location>'
[tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];內建開來源資料解析器
CREATE EXTERNAL TABLE [IF NOT EXISTS] <mc_oss_extable_name>
(
<col_name> <data_type>,
...
)
[COMMENT <table_comment>]
[PARTITIONED BY (<col_name> <data_type>, ...)]
ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde'
[WITH serdeproperties (
['<property_name>'='<property_value>',...]
)]
STORED AS TEXTFILE
LOCATION '<oss_location>'
[tblproperties ('<tbproperty_name>'='<tbproperty_value>',...)];公用參數
公用參數說明請參見基礎文法參數說明。
專屬參數
with serdeproperties屬性參數
適用解析器 | property_name | 使用情境 | 說明 | property_value | 預設值 |
內建文本資料解析器(CsvStorageHandler/TsvStorageHandler) | odps.text.option.gzip.input.enabled | 當需要讀取以GZIP方式壓縮的CSV或TSV檔案資料時,請添加該屬性。 | CSV、TSV壓縮屬性。配置該參數值為True時,MaxCompute才可以正常讀取壓縮檔,否則會讀取失敗。 |
| False |
odps.text.option.gzip.output.enabled | 當需要將資料以GZIP壓縮方式寫入OSS時,請添加該屬性。 | CSV、TSV壓縮屬性。配置該參數值為True時,MaxCompute才能將資料以GZIP壓縮方式寫入OSS,否則不壓縮。 |
| False | |
odps.text.option.header.lines.count | 當OSS資料檔案為CSV或TSV,且需要忽略OSS資料檔案中的前N行時,請添加該屬性。 | MaxCompute讀取OSS資料檔案時,會忽略指定的行數。 | 非負整數 | 0 | |
odps.text.option.null.indicator | 當OSS資料檔案為CSV或TSV,且需要定義OSS資料檔案中NULL的解析規則時,請添加該屬性。 | 通過該參數配置的字串會被解析為SQL中的NULL。 例如將檔案中 | 字串 | Null 字元串 | |
odps.text.option.ignore.empty.lines | 當OSS資料檔案為CSV或TSV,且需要定義OSS資料檔案中空行的處理規則時,請添加該屬性。 | 配置該參數值為True時,MaxCompute會忽略資料檔案中的空行,否則會讀取空行。 |
| True | |
odps.text.option.encoding | 當OSS資料檔案為CSV或TSV,且OSS資料檔案編碼規則非預設編碼規則時,請添加該屬性。 | 確保此處配置的編碼規則與OSS資料檔案編碼規則保持一致,否則MaxCompute無法成功讀取資料。 |
| UTF-8 | |
odps.text.option.delimiter | 當需要明確CSV或TSV資料檔案的資料行分隔符號時,請添加該屬性。 | 確保此處配置的資料行分隔符號可以正確讀取OSS資料檔案的每一列,否則MaxCompute讀取的資料會出現錯位問題。 | 單個字元 | 半形逗號(,) | |
odps.text.option.use.quote | 當CSV或TSV資料檔案中的欄位包含換行(CRLF)、雙引號或英文逗號時,請添加該屬性。 | 當CSV某個欄位中包含換行、雙引號(需要在 |
| False | |
odps.sql.text.option.flush.header | 在往OSS寫資料的時候,檔案塊的第一行為表頭。 | 只有針對CSV檔案格式生效。 |
| False | |
odps.sql.text.schema.mismatch.mode | 當讀取的OSS檔案的資料列數和外部表格的Schema列數不一致時。 | 指定對於列數不一致行的處理方式。 說明:odps.text.option.use.quote參數值為True時,該功能不生效。 |
| error | |
內建開來源資料解析器(OpenCSVSerde) | separatorChar | 當需要明確以TEXTFILE格式儲存的CSV資料的資料行分隔符號時,請添加該屬性。 | 指定CSV資料資料行分隔符號。 | 單個字串 | 半形逗號(,) |
quoteChar | 當以TEXTFILE格式儲存的CSV資料中的欄位包含換行、雙引號或英文逗號時,請添加該屬性。 | 指定CSV資料的引用符。 | 單個字串 | 無 | |
escapeChar | 當需要明確以TEXTFILE格式儲存的CSV資料的轉義規則時,請添加該屬性。 | 指定CSV資料的轉義符。 | 單個字串 | 無 |
tblproperties屬性參數
適用解析器 | property_name | 使用情境 | 說明 | property_value | 預設值 |
內建開來源資料解析器(OpenCSVSerde) | skip.header.line.count | 當需要忽略以TEXTFILE格式儲存的CSV檔案中的前N行資料時,請添加該屬性。 | MaxCompute讀取OSS資料時,會忽略從首行開始指定行數的資料。 | 非負整數 | 無 |
skip.footer.line.count | 當需要忽略以TEXTFILE格式儲存的CSV檔案中的後N行資料時,請添加該屬性。 | MaxCompute讀取OSS資料時,會忽略從尾行開始指定行數的資料。 | 非負整數 | 無 | |
mcfed.mapreduce.output.fileoutputformat.compress | 當需要將TEXTFILE資料檔案以壓縮方式寫入OSS時,請添加該屬性。 | TEXTFILE壓縮屬性。配置該參數值為True時,MaxCompute才可以將TEXTFILE資料檔案以壓縮方式寫入OSS,否則不壓縮。 |
| False | |
mcfed.mapreduce.output.fileoutputformat.compress.codec | 當需要將TEXTFILE資料檔案以壓縮方式寫入OSS時,請添加該屬性。 | TEXTFILE壓縮屬性。設定TEXTFILE資料檔案的壓縮方式。 說明:只支援 |
| 無 | |
io.compression.codecs | 當OSS資料檔案為Raw-Snappy格式時,請添加該屬性。 | 配置該參數值為True時,MaxCompute才可以正常讀取壓縮資料,否則MaxCompute無法成功讀取資料。 | com.aliyun.odps.io.compress.SnappyRawCodec | 無 | |
odps.text.option.bad.row.skipping | 當OSS資料檔案為CSV時,且需要跳過OSS資料檔案中的髒資料時,請添加該屬性。 | MaxCompute讀取OSS資料檔案時,可以選擇跳過或者不跳過髒資料。 |
| 無 |
寫入資料
MaxCompute寫入文法詳情,請參見寫入文法說明。
查詢分析
SELECT文法詳情,請參見查詢文法說明。
最佳化查詢計劃詳情,請參見查詢最佳化。
BadRowSkipping詳情,請參見BadRowSkipping。
BadRowSkipping
當CSV資料中出現髒資料時,可以通過BadRowSkipping功能,設定參數選擇跳過或者不跳過報錯資料。參數開啟與否,不影響理解底層資料格式。
參數配置
表層級參數
odps.text.option.bad.row.skippingrigid:一定要執行跳過邏輯,不能被session/project層面的配置覆蓋。flexible:資料層面開啟彈性跳過,但也可以被session/project層面的配置覆蓋。
session/project層級參數odps.sql.unstructured.text.bad.row.skipping,可以覆蓋flexible表參數,但不能覆蓋rigid表參數。on:主動開啟,如果表上未配置,自動開啟。off:主動關閉,如果表上配置成flexible,會執行主動關閉,其他情況以表參數為準。<null>/輸入不合法時:只看錶層級配置行為。
odps.sql.unstructured.text.bad.row.skipping.debug.num,表示允許列印出錯結果到Logview的Stdout中的條數。最大值只能為1000
值<=0時,表示關閉
輸入不合法時,表示關閉
Session層級參數和表層面參數互動關係
tbl property
session flag
result
rigid
on
開,強制開啟
off
<null>,或者不合法的值,或者不配置該參數值
flexible
on
開
off
關,被session關閉
<null>,或者不合法的值,或者不配置該參數值
開
沒有配置
on
開,session開啟
off
關
<null>,或者不合法的值,或者不配置該參數值
使用樣本
資料準備
將存在部分髒資料的測試資料csv_bad_row_skipping.csv上傳至OSS
oss-mc-test/badrow/。建立CSV外部表格
表層級參數和session層級flag不一樣,三種情況如下所示。
表參數:
odps.text.option.bad.row.skipping = flexible/rigid/<不填>session flag:
odps.sql.unstructured.text.bad.row.skipping = on/off/<不填>
表層級沒有配置參數
-- 表層級沒有配置參數,該報錯就報錯,靠session層級flag來控制 CREATE EXTERNAL TABLE test_csv_bad_data_skipping_flag ( a INT, b INT ) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole' ) location '<oss://databucketpath>';表層級參數跳過錯誤行,Session層級可以關閉
-- 表層級參數跳過錯誤行,不過session層級的flag可以主動關閉 CREATE EXTERNAL TABLE test_csv_bad_data_skipping_flexible ( a INT, b INT ) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole' ) location '<oss://databucketpath>' tblproperties ( 'odps.text.option.bad.row.skipping' = 'flexible' -- 彈性開啟,session層級可關閉 );表層級參數跳過錯誤行,Session層級無法關閉
-- 表層級參數強制開啟跳過錯誤,session層級無法關閉 CREATE EXTERNAL TABLE test_csv_bad_data_skipping_rigid ( a INT, b INT ) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole' ) location '<oss://databucketpath>' tblproperties ( 'odps.text.option.bad.row.skipping' = 'rigid' -- 強制開啟 );驗證查詢結果
表層級沒有配置參數
-- session層級開啟 SET odps.sql.unstructured.text.bad.row.skipping=on; -- session層級關閉,如果表層級配置為'flexible',則會被關閉,如果表層級配置'rigid'則不受影響; SET odps.sql.unstructured.text.bad.row.skipping=off; -- session層級列印有問題的行資料,最大1000條,小於等於0時,就關閉了錯誤資料列印 SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10; SELECT * FROM test_csv_bad_data_skipping_flag;返回報錯:FAILED: ODPS-0123131:User defined function exception
表層級參數跳過錯誤行,Session層級可以關閉
-- session層級開啟 SET odps.sql.unstructured.text.bad.row.skipping=on; -- session層級關閉,如果表層級配置為'flexible',則會被關閉,如果表層級配置'rigid'則不受影響; SET odps.sql.unstructured.text.bad.row.skipping=off; -- session層級列印有問題的行資料,最大1000條,小於等於0時,就關閉了錯誤資料列印 SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10; SELECT * FROM test_csv_bad_data_skipping_flexible;返回報錯:FAILED: ODPS-0123131:User defined function exception
表層級參數跳過錯誤行,Session層級無法關閉
-- session層級開啟 SET odps.sql.unstructured.text.bad.row.skipping=on; -- session層級關閉,如果表層級配置為'flexible',則會被關閉,如果表層級配置'rigid'則不受影響; SET odps.sql.unstructured.text.bad.row.skipping=off; -- session層級列印有問題的行資料,最大1000條,小於等於0時,就關閉了錯誤資料列印 SET odps.sql.unstructured.text.bad.row.skipping.debug.num=10; SELECT * FROM test_csv_bad_data_skipping_rigid;返回結果如下:
+------------+------------+ | a | b | +------------+------------+ | 1 | 26 | | 5 | 37 | +------------+------------+
Smart Parse更靈活的類型相容能力
針對CSV格式的OSS外部表格,MaxCompute SQL採用2.0資料類型進行讀寫,之前僅支援部分嚴格格式的值,並按照相應的資料類型進行讀寫。現已相容讀取CSV中各種類型的值。具體如下:
Type | Input as String | Output as String | Description |
BOOLEAN |
說明 解析時會對輸入執行 |
| 不在枚舉值範圍,則解析失敗。 |
TINYINT |
說明
|
| 8位整型,超出範圍範圍 |
SMALLINT | 16位整型,超出範圍範圍 | ||
INT | 32位整型,超出範圍範圍 | ||
BIGINT | 64位整型,超出範圍範圍 說明
| ||
FLOAT |
說明
|
| 特殊值(大小寫不敏感)包括:NaN、Inf、-Inf、Intifniy和-Intifniy。在超出範圍範圍時,將報錯;若精度超出,則進行四捨五入截斷。 |
DOUBLE |
說明
|
| 特殊值(大小寫不敏感)包括:NaN、Inf、-Inf、Intifniy和-Intifniy。在超出範圍範圍時,將報錯;若精度超出,則進行四捨五入截斷。 |
DECIMAL (precision, scale) 以DECIMAL(15,2)為例 |
說明
|
| 整數部分值超出 則會報錯;小數部分超出scale,則會進行四捨五入截斷。 |
CHAR(n) 以CHAR(7)為例 |
|
| 最大長度為255。長度不足則會填充空格,但空格不參與比較。長度超出n會截斷。 |
VARCHAR(n) 以VARCHAR(7)為例 |
|
| 最大長度為65535。長度超出n會截斷。 |
STRING |
|
| 長度限制為8 MB。 |
DATE |
說明 您也可以通過自訂 |
|
|
TIMESTAMP_NTZ 說明 OpenCsvSerde不支援此類型,因為該類型與Hive資料格式不相容。 |
|
|
|
DATETIME |
| 假設系統時區為Asia/Shanghai:
|
|
TIMESTAMP |
| (假設系統時區為Asia/Shanghai)
|
|
通用規則
對於任意類型,CSV資料檔案中的Null 字元串被讀入表中後,均會被解析為NULL。
不支援的資料類型
複雜類型 (STRUCT/ARRAY/MAP):不支援。因為這些複雜類型的值很容易和CSV的常見分隔字元(
,)發生衝突導致解析失敗。BINARY/INTERVAL 類型:暫不支援。如有需求請聯絡MaxCompute支援人員。
數實值型別 (INT、DOUBLE等)
對於資料類型INT/SMALLINT/TINYINT/BIGINT/FLOAT/DOUBLE/DECIMAL,預設的解析能力(DEFAULT)比較豐富。
如果只想解析基礎的數字串,可以在
tblproperties中將odps.text.option.smart.parse.level參數設定為naive,使解析器僅支援解析普通數字串,例如“123”、“123.456”,其他形態的字串在解析時會報錯。
日期與時間類型 (DATE, TIMESTAMP等)
對於四種日期或時間相互關聯類型
DATA/DATETIME/TIMESTAMP/TIMESTAMP_NTZ,在底層代碼中均使用java.time.format.DateTimeFormatter處理。預設格式:MaxCompute內建了若干的預設解析格式。
自訂格式:
通過在
tblproperties中設定odps.text.option.<date|datetime|timestamp|timestamp_ntz>.io.format來自訂多種解析格式與一種輸出格式。多個解析格式之間用
#分隔。自訂格式的優先順序高於MaxCompute的內建解析格式,輸出格式將採用第一個自訂格式。
樣本:若自訂DATE類型的格式串為
pattern1#pattern2#pattern3,則可以解析符合pattern1、pattern2或pattern3的字串,但輸出至檔案時會採用pattern1格式來輸出。詳情請參見DateTimeFormatter。
重要提醒:關於時區格式z的說明
不建議使用 'z' (time-zone name) 作為自訂的時區格式(尤其對於中國區使用者),因為 'z' 在某些上下文中可能存在歧義。
建議改用 'x' (zone-offset) 或 'VV' (time-zone ID) 作為時區模式。
樣本:'CST' 在中國語境下通常表示中國標準時間(UTC+8),然而當 'CST' 被
java.time.format.DateTimeFormatter解析時,會被識別為美國中部標準時間(UTC-6),這可能導致非預期的輸入或輸出結果。
使用樣本
前置準備
已準備好OSS儲存空間(Bucket)、OSS目錄。具體操作請參見建立儲存空間、管理目錄。
MaxCompute已支援在OSS側自動建立目錄,對於攜帶外部表格及UDF的SQL語句,可以通過一條SQL語句執行讀寫外部表格及UDF的操作。原手動建立目錄方式仍然支援。
由於MaxCompute只在部分地區部署,跨地區的資料連通性可能存在問題,因此建議Bucket與MaxCompute專案所在地區保持一致。
授權
已具備訪問OSS的許可權。阿里雲帳號(主帳號)、RAM使用者或RAMRole身份可以訪問OSS外部表格,授權資訊請參見OSS的STS模式授權。
已具備在MaxCompute專案中建立表(CreateTable)的許可權。表操作的許可權資訊請參見MaxCompute許可權。
通過內建文本資料解析器建立OSS外部表格
樣本一:非分區表
與樣本資料中的
Demo1/目錄建立映射關係。建立OSS外部表格的命令樣本如下。CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external1 ( vehicleId INT, recordId INT, patientId INT, calls INT, locationLatitute DOUBLE, locationLongtitue DOUBLE, recordTime STRING, direction STRING ) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole' ) LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo1/'; -- 可以執行desc extended mc_oss_csv_external1;命令查看建立好的OSS外部表格結構資訊。樣本中使用的角色為
aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。查詢非分區外表。
SELECT * FROM mc_oss_csv_external1;返回結果如下:
+------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | vehicleid | recordid | patientid | calls | locationlatitute | locationlongtitue | recordtime | direction | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | 1 | 1 | 51 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | S | | 1 | 2 | 13 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | NE | | 1 | 3 | 48 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | NE | | 1 | 4 | 30 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | W | | 1 | 5 | 47 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | S | | 1 | 6 | 9 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | S | | 1 | 7 | 53 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | N | | 1 | 8 | 63 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | SW | | 1 | 9 | 4 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | NE | | 1 | 10 | 31 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | N | +------------+------------+------------+------------+------------------+-------------------+------------+----------------+寫入資料至非分區外表,並查看資料是否已成功寫入。
INSERT INTO mc_oss_csv_external1 VALUES(1,12,76,1,46.81006,-92.08174,'9/14/2014 0:10','SW'); SELECT * FROM mc_oss_csv_external1 WHERE recordId=12;返回結果如下:
+------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | vehicleid | recordid | patientid | calls | locationlatitute | locationlongtitue | recordtime | direction | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | 1 | 12 | 76 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:10 | SW | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+查看OSS路徑
Demo1/下已產生新檔案。
樣本二:分區表
與樣本資料中的
Demo2/目錄建立映射關係。建立OSS外部表格並引入分區資料的命令樣本如下。CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external2 ( vehicleId INT, recordId INT, patientId INT, calls INT, locationLatitute DOUBLE, locationLongtitue DOUBLE, recordTime STRING ) PARTITIONED BY ( direction STRING ) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole' ) LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo2/'; -- 可以執行DESC EXTENDED mc_oss_csv_external2;命令查看建立好的外部表格結構資訊。樣本中使用的角色為
aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。引入分區資料。當建立的OSS外部表格為分區表時,需要額外執行引入分區資料的操作,更多操作請參見補全OSS外部表格分區資料文法。
MSCK REPAIR TABLE mc_oss_csv_external2 ADD PARTITIONS; -- 等效於如下語句。 ALTER TABLE mc_oss_csv_external2 ADD PARTITION (direction = 'N') PARTITION (direction = 'NE') PARTITION (direction = 'S') PARTITION (direction = 'SW') PARTITION (direction = 'W');查詢分區外表。
SELECT * FROM mc_oss_csv_external2 WHERE direction='NE';返回結果如下:
+------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | vehicleid | recordid | patientid | calls | locationlatitute | locationlongtitue | recordtime | direction | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | 1 | 2 | 13 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | NE | | 1 | 3 | 48 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | NE | | 1 | 9 | 4 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | NE | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+寫入資料至分區外表,並查看是否已成功寫入。
INSERT INTO mc_oss_csv_external2 PARTITION(direction='NE') VALUES(1,12,76,1,46.81006,-92.08174,'9/14/2014 0:10'); SELECT * FROM mc_oss_csv_external2 WHERE direction='NE' AND recordId=12;返回結果如下:
+------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | vehicleid | recordid | patientid | calls | locationlatitute | locationlongtitue | recordtime | direction | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+ | 1 | 12 | 76 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:10 | NE | +------------+------------+------------+------------+------------------+-------------------+----------------+------------+查看OSS路徑
Demo2/direction=NE下已產生新檔案。
樣本三:壓縮資料
本樣本建立以GZIP壓縮的CSV格式外表,進行資料讀取和寫入操作。
建立內部表並寫入測試資料,用來進行後續的寫入測試。
CREATE TABLE vehicle_test( vehicleid INT, recordid INT, patientid INT, calls INT, locationlatitute DOUBLE, locationlongtitue DOUBLE, recordtime STRING, direction STRING ); INSERT INTO vehicle_test VALUES (1,1,51,1,46.81006,-92.08174,'9/14/2014 0:00','S');建立以GZIP壓縮的CSV格式外表,與樣本資料中的
Demo3/(壓縮資料)目錄建立映射關係。建立OSS外部表格命令樣本如下。CREATE EXTERNAL TABLE IF NOT EXISTS mc_oss_csv_external3 ( vehicleId INT, recordId INT, patientId INT, calls INT, locationLatitute DOUBLE, locationLongtitue DOUBLE, recordTime STRING, direction STRING ) PARTITIONED BY (dt STRING) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ( 'odps.properties.rolearn'='acs:ram::<uid>:role/aliyunodpsdefaultrole', 'odps.text.option.gzip.input.enabled'='true', 'odps.text.option.gzip.output.enabled'='true' ) LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo3/'; -- 引入分區資料 MSCK REPAIR TABLE mc_oss_csv_external3 ADD PARTITIONS; -- 可以執行DESC EXTENDED mc_oss_csv_external3;命令查看建立好的外部表格結構資訊。樣本中使用的角色為
aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。使用MaxCompute用戶端,從OSS中讀取資料。命令樣本如下:
說明如果OSS壓縮資料為開來源資料格式,需要在SQL語句前添加
set odps.sql.hive.compatible=true;命令,與SQL語句一起提交執行。--開啟全表掃描,僅此Session有效。 SET odps.sql.allow.fullscan=true; SELECT recordId, patientId, direction FROM mc_oss_csv_external3 WHERE patientId > 25;返回結果如下:
+------------+------------+------------+ | recordid | patientid | direction | +------------+------------+------------+ | 1 | 51 | S | | 3 | 48 | NE | | 4 | 30 | W | | 5 | 47 | S | | 7 | 53 | N | | 8 | 63 | SW | | 10 | 31 | N | +------------+------------+------------+讀取內部表的資料寫入至OSS外表。
通過MaxCompute用戶端對外部表格執行
INSERT OVERWRITE或INSERT INTO命令,將資料寫入OSS。INSERT INTO TABLE mc_oss_csv_external3 PARTITION (dt='20250418') SELECT * FROM vehicle_test;執行成功後,可在OSS目錄下查看匯出的檔案。
建立OSS外部表格並指定對應OSS檔案的第一行為表頭
在樣本資料的oss-mc-testBucket下建立Demo11目錄,並執行如下語句:
--建立外部表格
CREATE EXTERNAL TABLE mf_oss_wtt
(
id BIGINT,
name STRING,
tran_amt DOUBLE
)
STORED BY 'com.aliyun.odps.CsvStorageHandler'
WITH serdeproperties (
'odps.text.option.header.lines.count' = '1',
'odps.sql.text.option.flush.header' = 'true'
)
LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/Demo11/';
--插入資料
INSERT OVERWRITE TABLE mf_oss_wtt VALUES (1, 'val1', 1.1),(2, 'value2', 1.3);
--查詢資料
--在建表的時候可以把所有欄位建成string,否則表頭讀取時會報錯。
--或者在建表的時候需要加跳過表頭的參數:'odps.text.option.header.lines.count' = '1'
SELECT * FROM mf_oss_wtt;樣本中使用的角色為aliyunodpsdefaultrole,如果使用其他角色,需要將aliyunodpsdefaultrole替換為目標角色名稱,並為目標角色授予訪問OSS的許可權。
返回結果如下:
+----------+--------+------------+
| id | name | tran_amt |
+----------+--------+------------+
| 1 | val1 | 1.1 |
| 2 | value2 | 1.3 |
+----------+--------+------------+建立OSS外部表格且外部表格列數與OSS資料列數不一致
在樣本資料的
oss-mc-testBucket下建立demo目錄,並上傳test.csv檔案。test.csv檔案內容如下。1,kyle1,this is desc1 2,kyle2,this is desc2,this is two 3,kyle3,this is desc3,this is three, I have 4 columns建立外部表格。
指定對於列數不一致的行的處理方式為
TRUNCATE。-- 刪除表 DROP TABLE test_mismatch; -- 建立外部表格 CREATE EXTERNAL TABLE IF NOT EXISTS test_mismatch ( id string, name string, dect string, col4 string ) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ('odps.sql.text.schema.mismatch.mode' = 'truncate') LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/';指定對於列數不一致的行的處理方式為
IGNORE。-- 刪除表 DROP TABLE test_mismatch01; -- 建立外部表格 CREATE EXTERNAL TABLE IF NOT EXISTS test_mismatch01 ( id STRING, name STRING, dect STRING, col4 STRING ) STORED BY 'com.aliyun.odps.CsvStorageHandler' WITH serdeproperties ('odps.sql.text.schema.mismatch.mode' = 'ignore') LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/';查詢表資料。
查詢test_mismatch表。
SELECT * FROM test_mismatch; --返回結果 +----+-------+---------------+---------------+ | id | name | dect | col4 | +----+-------+---------------+---------------+ | 1 | kyle1 | this is desc1 | NULL | | 2 | kyle2 | this is desc2 | this is two | | 3 | kyle3 | this is desc3 | this is three | +----+-------+---------------+---------------+查詢test_mismatch01表。
SELECT * FROM test_mismatch01; --返回結果 +----+-------+----------------+-------------+ | id | name | dect | col4 | +----+-------+----------------+-------------+ | 2 | kyle2 | this is desc2 | this is two +----+-------+----------------+-------------+
通過內建開源解析器建立OSS外部表格
通過內建開源解析器建立OSS外部表格讀取以逗號為分隔字元的檔案,並忽略首行和尾行的資料。
在樣本資料的
oss-mc-testBucket下建立demo-test目錄,並上傳測試檔案test.csv。測試檔案包含的資料資訊如下。
1,1,51,1,46.81006,-92.08174,9/14/2014 0:00,S 1,2,13,1,46.81006,-92.08174,9/14/2014 0:00,NE 1,3,48,1,46.81006,-92.08174,9/14/2014 0:00,NE 1,4,30,1,46.81006,-92.08174,9/14/2014 0:00,W 1,5,47,1,46.81006,-92.08174,9/14/2014 0:00,S 1,6,9,1,46.81006,-92.08174,9/15/2014 0:00,S 1,7,53,1,46.81006,-92.08174,9/15/2014 0:00,N 1,8,63,1,46.81006,-92.08174,9/15/2014 0:00,SW 1,9,4,1,46.81006,-92.08174,9/15/2014 0:00,NE 1,10,31,1,46.81006,-92.08174,9/15/2014 0:00,N建立外部表格,並指定分隔字元為逗號,設定忽略首行和尾行參數。
CREATE EXTERNAL TABLE ext_csv_test08 ( vehicleId INT, recordId INT, patientId INT, calls INT, locationLatitute DOUBLE, locationLongtitue DOUBLE, recordTime STRING, direction STRING ) ROW FORMAT serde 'org.apache.hadoop.hive.serde2.OpenCSVSerde' WITH serdeproperties ( "separatorChar" = "," ) stored AS textfile location 'oss://oss-cn-hangzhou-internal.aliyuncs.com/***/' -- 設定忽略首行和尾行參數。 TBLPROPERTIES ( "skip.header.line.COUNT"="1", "skip.footer.line.COUNT"="1" ) ;讀取外部表格。
SELECT * FROM ext_csv_test08; -- 返回結果,唯讀了8條,忽略了首行和尾行。 +------------+------------+------------+------------+------------------+-------------------+------------+------------+ | vehicleid | recordid | patientid | calls | locationlatitute | locationlongtitue | recordtime | direction | +------------+------------+------------+------------+------------------+-------------------+------------+------------+ | 1 | 1 | 51 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | S | | 1 | 2 | 13 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | NE | | 1 | 3 | 48 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | NE | | 1 | 4 | 30 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | W | | 1 | 5 | 47 | 1 | 46.81006 | -92.08174 | 9/14/2014 0:00 | S | | 1 | 6 | 9 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | S | | 1 | 7 | 53 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | N | | 1 | 8 | 63 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | SW | | 1 | 9 | 4 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | NE | | 1 | 10 | 31 | 1 | 46.81006 | -92.08174 | 9/15/2014 0:00 | N | +------------+------------+------------+------------+------------------+-------------------+------------+------------+
建立CSV格式的OSS外部表格-自訂各種時間資料類型
CSV自訂時間類型的解析與輸出格式詳情,請參見Smart Parse更靈活的類型相容能力。
建立各時間資料類型的CSV外表(datetime/timestamp/timestamp_ntz)。
CREATE EXTERNAL TABLE test_csv ( col_date DATE, col_datetime DATETIME, col_timestamp TIMESTAMP, col_timestamp_ntz TIMESTAMP_NTZ ) STORED BY 'com.aliyun.odps.CsvStorageHandler' LOCATION 'oss://oss-cn-hangzhou-internal.aliyuncs.com/oss-mc-test/demo/' TBLPROPERTIES ( 'odps.text.option.date.io.format' = 'MM/dd/yyyy', 'odps.text.option.datetime.io.format' = 'yyyy-MM-dd-HH-mm-ss x', 'odps.text.option.timestamp.io.format' = 'yyyy-MM-dd HH-mm-ss VV', 'odps.text.option.timestamp_ntz.io.format' = 'yyyy-MM-dd HH:mm:ss.SS' ); INSERT OVERWRITE test_csv VALUES(DATE'2025-02-21', DATETIME'2025-02-21 08:30:00', TIMESTAMP'2025-02-21 12:30:00', TIMESTAMP_NTZ'2025-02-21 16:30:00.123456789');插入資料後,CSV檔案的內容為:
02/21/2025,2025-02-21-08-30-00 +08,2025-02-21 12-30-00 Asia/Shanghai,2025-02-21 16:30:00.12再次讀資料,可以看到結果。
SELECT * FROM test_csv;返回結果如下:
+------------+---------------------+---------------------+------------------------+ | col_date | col_datetime | col_timestamp | col_timestamp_ntz | +------------+---------------------+---------------------+------------------------+ | 2025-02-21 | 2025-02-21 08:30:00 | 2025-02-21 12:30:00 | 2025-02-21 16:30:00.12 | +------------+---------------------+---------------------+------------------------+
常見問題
讀取CSV/TSV資料時會報錯“列數不匹配”
問題現象
若CSV/TSV檔案中的列數與外表DDL中的列數量的不一致,讀取CSV/TSV資料時會報錯“列數不匹配”,例如
FAILED: ODPS-0123131:User defined function exception - Traceback:java.lang.RuntimeException: SCHEMA MISMATCH:xxx。解決方案
通過在Session層級設定
odps.sql.text.schema.mismatch.mode參數,可以控制輸出結果:SET odps.sql.text.schema.mismatch.mode=error:表示列數不一致時,系統直接報錯。SET odps.sql.text.schema.mismatch.mode=truncate:表示列數不一致時,超過外表DDL中的列數部分將被丟棄;少於外表DDL中的列數部分,列值將被補充為NULL。