云數據庫 SelectDB 版支持表函數功能TVF(Table-Value-Function),可以將S3、HDFS等常見遠端存儲中的文件數據,映射成云數據庫 SelectDB 版中的表,從而對這些文件數據進行分析。
S3表函數
S3表函數可以讓您像訪問關系型數據庫一樣,讀取并訪問S3兼容的對象存儲上的文件內容。目前支持CVS、CSV_with_names、CVS_with_names_and_types、Json、Parquet、ORC文件格式。
語法
s3(
"uri" = "..",
"s3.access_key" = "...",
"s3.secret_key" = "...",
"s3.region" = "...",
"format" = "csv",
"keyn" = "valuen",
...
);
參數說明
S3 TVF中的每一個參數都是一個"key"="value"
鍵值對。常用參數如下:
參數名稱 | 必選 | 參數取值 | 參數說明 |
uri | 是 | 字符串。 | 訪問S3的URI。 |
s3.access_key | 是 | 字符串。 | 訪問S3的用戶身份密鑰。 |
s3.secret_key | 是 | 字符串。 | 訪問S3的用戶加密認證字符串。 |
s3.region | 是 | 字符串。 | 訪問S3的對象存儲所在地域。默認值 |
s3.session_token | 否 說明 若啟用臨時會話驗證,則該參數必選。 | 字符串。 | 訪問S3的用戶臨時會話token。 |
use_path_style | 否 |
| S3 SDK默認使用Virtual-hosted Style方式。但某些對象存儲系統可能未開啟或不支持Virtual-hosted Style方式的訪問,此時您可以添加 默認為 說明 URI目前支持三種schema:
|
format | 是 |
| 訪問S3上的文件具體格式。 |
column_separator | 否 | 字符串。 | 列分割符,默認為 |
line_delimiter | 否 | 字符串。 | 行分割符,默認為 |
compress_type | 否 |
| 文件的壓縮格式,會根據uri的后綴自動推斷類型。默認值為UNKNOWN。 |
read_json_by_line | 否 |
| 是否以行為單位讀取JSON數據,默認為true。 |
num_as_string | 否 |
| 數字類型按照String處理,默認為false。 |
fuzzy_parse | 否 |
| 加速JSON數據的導入效率,默認為false。 |
jsonpaths | 否 | 字符串。 | 當導入數據格式為JSON時,可通過 格式: |
strip_outer_array | 否 |
| 當導入數據格式為JSON時, 格式: |
json_root | 否 | 字符串。 | 當導入數據格式為JSON時,可以通過 格式: |
path_partition_keys | 否 | 字符串。 | 指定文件路徑中攜帶的分區列名。例如/path/to/city=beijing/date="2023-07-09",則填寫path_partition_keys="city,date"。此時SelectDB將會自動從路徑中讀取相應列名和列值進行導入。 |
使用示例
讀取并訪問S3兼容的對象存儲上的CSV格式文件,示例如下。
SELECT * FROM s3("uri" = "http://127.0.0.1:9312/test2/student1.csv", "s3.access_key"= "minioadmin", "s3.secret_key" = "minioadmin", "format" = "csv", "use_path_style" = "true") ORDER BY c1;
配合
DESC FUNCTION
使用,示例如下。MySQL [(none)]> Desc FUNCTION s3("uri" = "http://127.0.0.1:9312/test2/student1.csv", "s3.access_key"= "minioadmin", "s3.secret_key" = "minioadmin", "format" = "csv", "use_path_style" = "true");
OSS的場合,需采用Virtual-hosted Style方式訪問,示例如下。
SELECT * FROM s3( "uri" = "http://example-bucket.oss-cn-beijing.aliyuncs.com/your-folder/file.parquet", "s3.access_key"= "ak", "s3.secret_key" = "sk", "format" = "parquet", "use_path_style" = "false");
設置了
"use_path_style"="true"
的場合,將采用path style方式訪問S3,示例如下。SELECT * FROM s3( "uri" = "https://endpoint/bucket/file/student.csv", "s3.access_key"= "ak", "s3.secret_key" = "sk", "format" = "csv", "use_path_style"="true");
設置了
"use_path_style"="false"
的場合,將采用virtual-hosted style方式訪問S3,示例如下。SELECT * FROM s3( "uri" = "https://bucket.endpoint/bucket/file/student.csv", "s3.access_key"= "ak", "s3.secret_key" = "sk", "format" = "csv", "use_path_style"="false");
HDFS表函數
HDFS表函數可以讓您像訪問關系表格式數據一樣,讀取并訪問HDFS上的文件內容。目前支持CVS、CSV_with_names、CVS_with_names_and_types、Json、Parquet、ORC文件格式。
語法
hdfs(
"uri" = "..",
"fs.defaultFS" = "...",
"hadoop.username" = "...",
"format" = "csv",
"keyn" = "valuen"
...
);
參數說明
HDFS TVF中的每一個參數都是一個"key"="value"
鍵值對。常用參數如下:
參數名稱 | 必選 | 參數取值 | 參數說明 |
uri | 是 | 字符串。 | 要訪問的HDFS的URI。如果URI路徑不存在或文件都是空文件,HDFS TVF將返回空集合。 |
fs.defaultFS | 是 | 字符串。 | 要訪問的HDFS的主機和端口號。 |
hadoop.username | 是 | 字符串。 | 要訪問的HDFS用戶名,可以是任意字符串,但不能為空。 |
hadoop.security.authentication | 否 |
| 要訪問的HDFS認證方式。可選Simple或者Kerberos。 |
hadoop.kerberos.principal | 否 | 字符串。 | 要訪問的HDFS啟用Kerberos驗證的場合,指定Principal。 |
hadoop.kerberos.keytab | 否 | 字符串。 | 要訪問的HDFS啟用Kerberos驗證的場合,指定Keytab。 |
dfs.client.read.shortcircuit | 否 |
| HDFS短路本地讀取開關。布爾類型。 |
dfs.domain.socket.path | 否 | 字符串。 | 一個指向UNIX域套接字的路徑,用于DataNode和本地HDFS客戶端通信。如果在該路徑中出現了字符串"_PORT",會被替換成DataNode的TCP端口。可選參數。 |
dfs.nameservices | 否 | 字符串。 | 提供服務的NS邏輯名稱,與core-site.xml里相應字段對應。 |
dfs.ha.namenodes.your-nameservices | 否 說明 采用Hadoop HA部署的場合為必選參數。 | 字符串。 | dfs.nameservices下的NameNode邏輯名稱。 |
dfs.namenode.rpc-address.your-nameservices.your-namenode | 否 說明 采用Hadoop HA部署的場合為必選參數。 | 字符串。 | 每個NameNode監聽的HTTP地址。 |
dfs.client.failover.proxy.provider.your-nameservices | 否 說明 采用Hadoop HA部署的場合為必選參數。 | 字符串。 | 客戶端連接可用狀態的NameNode所用的代理類。 |
read_json_by_line | 否 |
| 以行為單位讀取JSON數據,默認為true。 |
num_as_string | 否 |
| 數字類型按照String處理,默認為false。 |
fuzzy_parse | 否 |
| 加速JSON數據的導入效率,默認為false。 |
jsonpaths | 否 | 字符串。 | 當導入數據格式為JSON時,可通過 格式: |
strip_outer_array | 否 |
| 當導入數據格式為JSON時, 格式: |
json_root | 否 | 字符串。 | 當導入數據格式為JSON時,可以通過 格式: |
trim_double_quotes | 否 |
| 布爾類型,默認值為false。為true時表示裁剪掉CSV文件每個字段最外層的雙引號。 |
skip_lines | 否 | [0-Integer.MaxValue] | 整數類型,默認值為0。含義為跳過CSV文件的前幾行。當format設置為 |
path_partition_keys | 否 | 字符串。 | 指定文件路徑中攜帶的分區列名。例如/path/to/city=beijing/date="2023-07-09",則填寫path_partition_keys="city,date"。此時SelectDB將會自動從路徑中讀取相應列名和列值進行導入。 |
使用示例
讀取并訪問HDFS存儲上的CSV格式文件,示例如下。
MySQL [(none)]> SELECT * FROM hdfs(
"uri" = "hdfs://127.0.0.1:842/user/doris/csv_format_test/student.csv",
"fs.defaultFS" = "hdfs://127.0.0.1:8424",
"hadoop.username" = "doris",
"format" = "csv");
-- 返回示例
+------+---------+------+
| c1 | c2 | c3 |
+------+---------+------+
| 1 | alice | 18 |
| 2 | bob | 20 |
| 3 | jack | 24 |
| 4 | jackson | 19 |
| 5 | liming | 18 |
+------+---------+------+
讀取并訪問HA模式的HDFS存儲上的CSV格式文件,示例如下。
MySQL [(none)]> SELECT * FROM hdfs(
"uri" = "hdfs://127.0.0.1:842/user/doris/csv_format_test/student.csv",
"fs.defaultFS" = "hdfs://127.0.0.1:8424",
"hadoop.username" = "doris",
"format" = "csv",
"dfs.nameservices" = "my_hdfs",
"dfs.ha.namenodes.my_hdfs" = "nn1,nn2",
"dfs.namenode.rpc-address.my_hdfs.nn1" = "nanmenode01:8020",
"dfs.namenode.rpc-address.my_hdfs.nn2" = "nanmenode02:8020",
"dfs.client.failover.proxy.provider.my_hdfs" = "org.apache.hadoop.hdfs.server.namenode.ha.ConfiguredFailoverProxyProvider");
-- 返回示例
+------+---------+------+
| c1 | c2 | c3 |
+------+---------+------+
| 1 | alice | 18 |
| 2 | bob | 20 |
| 3 | jack | 24 |
| 4 | jackson | 19 |
| 5 | liming | 18 |
+------+---------+------+
配合DECS FUNCTION
使用,示例如下。
MySQL [(none)]> DECS FUNCTION hdfs(
"uri" = "hdfs://127.0.0.1:8424/user/doris/csv_format_test/student_with_names.csv",
"fs.defaultFS" = "hdfs://127.0.0.1:8424",
"hadoop.username" = "doris",
"format" = "csv_with_names");
使用方法
本章節將通過S3 TVF舉例說明如何進行文件分析。
自動推斷文件列類型?
目前支持對Parquet、ORC、CSV、JSON格式進行分析和列類型推斷。
> DESC FUNCTION s3 (
"URI" = "http://127.0.0.1:9312/test2/test.snappy.parquet",
"s3.access_key"= "ak",
"s3.secret_key" = "sk",
"format" = "parquet",
"use_path_style"="true"
);
-- 返回示例
+---------------+--------------+------+-------+---------+-------+
| Field | Type | Null | Key | Default | Extra |
+---------------+--------------+------+-------+---------+-------+
| p_partkey | INT | Yes | false | NULL | NONE |
| p_name | TEXT | Yes | false | NULL | NONE |
| p_mfgr | TEXT | Yes | false | NULL | NONE |
| p_brand | TEXT | Yes | false | NULL | NONE |
| p_type | TEXT | Yes | false | NULL | NONE |
| p_size | INT | Yes | false | NULL | NONE |
| p_container | TEXT | Yes | false | NULL | NONE |
| p_retailprice | DECIMAL(9,0) | Yes | false | NULL | NONE |
| p_comment | TEXT | Yes | false | NULL | NONE |
+---------------+--------------+------+-------+---------+-------+
可以看到,對于Parquet文件,SelectDB會根據文件內的元信息自動推斷列類型。
CSV Schema
默認情況下,CSV格式文件的所有列類型均會被SelectDB視為String。您可以通過csv_schema
屬性單獨指定列名和列類型。SelectDB會使用指定的列類型進行文件讀取。格式如下:
name1:type1;name2:type2;...
對于格式不匹配的列(例如文件中實際為字符串,您定義為int),或缺失列(比如文件中實際存在4列,您定義了5列),則這些列將返回null。當前支持的列類型為:
名稱 | 映射類型 |
tinyint | tinyint |
smallint | smallint |
int | int |
bigint | bigint |
largeint | largeint |
float | float |
double | double |
decimal(p,s) | decimalv3(p,s) |
date | datev2 |
datetime | datetimev2 |
char | string |
varchar | string |
string | string |
boolean | boolean |
示例如下。
s3 (
"URI" = "https://bucket1/inventory.dat",
"s3.access_key"= "ak",
"s3.secret_key" = "sk",
"format" = "csv",
"column_separator" = "|",
"csv_schema" = "k1:int;k2:int;k3:int;k4:decimal(38,10)",
"use_path_style"="true"
)
查詢分析
您可以使用任意的SQL語句,對TVF進行分析,示例如下。
SELECT * FROM s3(
"URI" = "http://127.0.0.1:9312/test2/test.snappy.parquet",
"s3.access_key"= "ak",
"s3.secret_key" = "sk",
"format" = "parquet",
"use_path_style"="true")
LIMIT 5;
-- 返回示例
+-----------+------------------------------------------+----------------+----------+-------------------------+--------+-------------+---------------+---------------------+
| p_partkey | p_name | p_mfgr | p_brand | p_type | p_size | p_container | p_retailprice | p_comment |
+-----------+------------------------------------------+----------------+----------+-------------------------+--------+-------------+---------------+---------------------+
| 1 | goldenrod lavender spring chocolate lace | Manufacturer#1 | Brand#13 | PROMO BURNISHED COPPER | 7 | JUMBO PKG | 901 | ly. slyly ironi |
| 2 | blush thistle blue yellow saddle | Manufacturer#1 | Brand#13 | LARGE BRUSHED BRASS | 1 | LG CASE | 902 | lar accounts amo |
| 3 | spring green yellow purple cornsilk | Manufacturer#4 | Brand#42 | STANDARD POLISHED BRASS | 21 | WRAP CASE | 903 | egular deposits hag |
| 4 | cornflower chocolate smoke green pink | Manufacturer#3 | Brand#34 | SMALL PLATED BRASS | 14 | MED DRUM | 904 | p furiously r |
| 5 | forest brown coral puff cream | Manufacturer#3 | Brand#32 | STANDARD POLISHED TIN | 15 | SM PKG | 905 | wake carefully |
+-----------+------------------------------------------+----------------+----------+-------------------------+--------+-------------+---------------+---------------------+
TVF可以出現在SQL中Table能出現的任意位置,如CTE的WITH子句中或者FROM子句中,您可以把文件當做一張普通的表進行任意分析。
您也可以通過CREATE VIEW
語句為TVF創建一個邏輯視圖。這樣您可以像其他視圖一樣,對這個TVF進行訪問、權限管理等操作,也可以讓其他用戶訪問這個TVF。
CREATE VIEW v1 AS
SELECT * FROM s3(
"URI" = "http://127.0.0.1:9312/test2/test.snappy.parquet",
"s3.access_key"= "ak",
"s3.secret_key" = "sk",
"format" = "parquet",
"use_path_style"="true");
DESC v1;
SELECT * FROM v1;
GRANT SELECT_PRIV ON db1.v1 TO user1;
數據導入?
配合INSERT INTO SELECT
語法,您可以方便將文件導入到SelectDB表中進行更快速的分析,示例如下。
-- 1. 創建SelectDB內部表
CREATE TABLE IF NOT EXISTS test_table
(
id int,
name varchar(50),
age int
)
DISTRIBUTED BY HASH(id) BUCKETS 4
PROPERTIES("replication_num" = "1");
-- 2. 使用S3 Table Value Function插入數據
INSERT INTO test_table (id,name,age)
SELECT cast(id as INT) as id, name, cast (age as INT) as age
FROM s3(
"uri" = "http://127.0.0.1:9312/test2/test.snappy.parquet",
"s3.access_key"= "ak",
"s3.secret_key" = "sk",
"format" = "parquet",
"use_path_style" = "true");
注意事項
如果S3或HDFS TVF指定的URI匹配不到文件,或者匹配到的所有文件都是空文件,那么S3或HDFS TVF將會返回空結果集。在這種情況下使用
DESC FUNCTION
查看這個文件的Schema,會得到一列虛假的列__dummy_col
,可忽略這一列。如果指定TVF的format為CSV,所讀文件不為空文件但文件第一行為空,則會產生報誤
The first line is empty, can not parse column numbers
。