MaxCompute推出了Object Table功能,该功能支持数仓计算引擎访问数据湖存储中的非结构化数据及其元信息。本文为您介绍Object Table相关的命令语法和示例。
背景信息
许多AI流程环节需要熟悉数据和业务的数仓开发者,利用大数据平台提供的低成本大规模算力对大模型进行数据预处理或非结构化数据处理。这些计算过程及其结果将与数仓或数据湖中的数据进行交互。
使用SQL处理非结构化数据存在以下问题。
大数据SQL引擎在读取对象存储文件时并不感知对象的大小,因此缺乏依据来优化执行计划。这使得控制并发或自动启动合适的并发变得困难。同时,由于无法有效下推过滤条件,在数据倾斜的情况下,无法充分发挥算力的优势。
对象存储的元信息读取性能不足,每次查询均需远程访问存储服务,导致延时较高。
只能在UDTF中以单进程串行方式获取对象存储的文件列表,导致数据读取性能较差。
需要在用户自定义函数(UDF)中自主实现权限打通的逻辑,并且需要实现UDF与存储服务等之间的网络连接逻辑。
UDF在非结构化数据处理方面的能力不足,传统数据仓库缺乏灵活且安全的自定义镜像上传功能,同时也缺乏UDF的安全运行环境。此外,远程调用需要与分布式计算服务进行并发对接。
功能说明
MaxCompute推出了Object Table功能,该功能支持数仓计算引擎访问数据湖存储中的非结构化数据及其元信息,具备以下能力:
支持引擎以表的形式读取OSS文件元信息。
基于Metadata Table能力,以版本化方式缓存OSS文件的各种元信息,后续SQL引擎能基于Metadata Table实现有效的查询优化,包括数据过滤和条件下推等功能。
基于内置文档函数以多种方式读取非结构化数据文件内容。
MaxCompute SQL引擎基于Object Table元信息进行并发切分,启动大规模分布式计算能力,以提高数据读取和处理的效率。
支持用户上传自定义镜像构建UDF,并处理引擎读取的非结构化数据。
支持引擎处理非结构化数据,生成结构化数据结果并将其写入数据仓库的内部表和外部表,后续支持生成非结构化数据结果,并通过Object Table写回对象存储服务。
支持Python生态系统的Maxframe引擎。
使用说明
目前Object Table正在邀测中,试用Object Table功能需要使用云栖新功能邀测项目。
请您在新功能邀测申请表单中填写注册信息。注册完成后,您可通过以下两种方式开始体验新功能:
在MaxCompute控制台新建项目时,选择项目类型为云栖新功能邀测项目,完成创建。
在DataWorks控制台创建工作空间时,选择数据开发(Data Studio)(新版)公测版本完成创建。在绑定MaxCompute计算资源时,新建MaxCompute内部项目并选择项目类型为云栖新功能邀测项目,完成绑定。
创建完云栖新功能邀测项目,即可体验以下Object Table功能。
使用限制
MaxCompute项目需要支持Schema功能,详情请参见Schema功能开启。
MaxCompute需要支持2.0数据类型系统。
Object Table暂不支持分区。
费用说明
Object Table是OSS上文件元信息的集合,因此会对刷新存入Object Table的元数据收取存储费用,详情请参见存储费用。由于OSS上的文件没有存储在MaxCompute内部,MaxCompute不收取存储费用,具体存储和访问数据的费用由OSS存储服务收取,详情请参见OSS存储费用。
在刷新OSS元信息的抽取任务中,扫描的每个文件的
inputsize
是一个与元信息相关的值,而与文件的实际大小无关。因此,刷新计算任务的整体费用与OSS上对应文件的实际大小无关,而是与文件数量相关。详情请参见外部表按量付费计费规则。使用Object Table及其相关元数据进行OSS非结构化数据的分析与提取,并进行相应处理,会产生计算费用。
在按量付费模式下,对Object Table的元数据分析按照内表进行计费,请参见普通表按量付费计算规则。而对OSS非结构化数据的内容进行处理则按照外表进行计费,请参见外部表按量付费计费规则。
在包年包月付费模式下,均使用包年包月的预付费资源,请参见计算费用(包年包月)。
创建OBJECT TABLE
语法
CREATE OBJECT TABLE [IF NOT EXISTS] <objecttable_name>
WITH SERDEPROPERTIES ('<key>' = '<value>')
LOCATION '<location>'
[TBLPROPERTIES ('<key>' = '<value>')]
[COMMENT '<comment>']
;
Object Table需要在内部项目支持Schema模式下使用,同时开启Schema语法开关。
Object Table不需要定义列,元数据信息列由系统提供。
参数说明
参数 | 是否必填 | 说明 |
objecttable_name | 必填。 | 表名。 |
SERDEPROPERTIES ('<key>'='<value>') | 必填。 | 支持填写RAM角色认证信息。不填则默认使用当前阿里云账号(主账号)的名为
|
location | 必填。 | Object Table映射的OSS对象存储的路径。Object Table会对目录下的文件的元信息进行抽取。 例如: |
TBLPROPERTIES ('<key>'='<value>') | 可选。 | 缓存刷新模式设定,目前仅支持手工刷新模式 |
comment | 可选。 | 表注释内容。 |
示例
SET odps.namespace.schema=true;
CREATE OBJECT TABLE ot_demo_day
WITH serdeproperties (
'odps.properties.rolearn'='acs:ram::xxxxxx:role/aliyunodpsdefaultrole')
LOCATION 'oss://oss-cn-hangzhou.aliyuncs.com/odps-external-****/ottest/';
查看OBJECT TABLE属性
语法
DESC <objecttable_name>
参数说明
objecttable_name:必填,表名。
示例
DESC ot_demo_day;
返回结果如下。
+------------------------------------------------------------------------------------+
| Owner: ALIYUN$****@test.aliyunid.com |
| Project: test_objecttable |
| Schema: default |
| TableComment: |
+------------------------------------------------------------------------------------+
| CreateTime: 2024-09-02 20:01:56 |
| LastDDLTime: 2024-09-02 20:01:56 |
| LastModifiedTime: 2024-09-02 20:01:56 |
+------------------------------------------------------------------------------------+
| InternalTable: YES | Size: 0 |
+------------------------------------------------------------------------------------+
| Native Columns: |
+------------------------------------------------------------------------------------+
| Field | Type | Label | Comment |
+------------------------------------------------------------------------------------+
| key | varchar(2048) | | The name of the object. |
| size | bigint | | The size of the returned object in bytes. |
| type | varchar(32) | | The type of the object and valid values: Normal, Multipart, Appendable, and Symlink. |
| last_modified | timestamp | | The last modified time of the object. |
| storage_class | varchar(32) | | The storage class of the object. |
| etag | varchar(64) | | The entity tag (ETag). When an object is created, an ETag is created to identify the content of the object. |
| restore_info | varchar(256) | | The restoration status of the object. |
| owner_id | bigint | | The ID of the bucket owner. |
| owner_display_name | varchar(256) | | The display name of the bucket owner. |
+------------------------------------------------------------------------------------+
返回结果部分列名说明。
列名 | 说明 |
key | 对象在Object Table中的相对路径名。 |
size | 对象的大小,单位为字节。 |
type | 对象在OSS侧的文件类型:Normal、Multipart、Appendable和Symlink。 |
last_modified | 对象在OSS上的数据最后变更时间。 |
storage_class | 对象在OSS上的存储类型。具体类型请参见存储类型概述。 |
etag | ETag在每个Object生成时创建的实体标记(一个签名信息),用于标识一个Object的内容在前后两次更新过程中是否变化(但不是唯一性标记)。 |
restore_info | 描述一个对象是否被从冷存中恢复,如果是恢复过程中的对象,则有相关的信息描述。 |
owner_id | 对象的所有者ID。 |
owner_display_name | 对象的所有者的名称。 |
查看OBJECT TABLE建表语句
语法
SHOW CREATE TABLE <objecttable_name>;
参数说明
objecttable_name:必填,表名。
示例
SHOW CREATE TABLE ot_demo_day;
返回结果如下。
CREATE OBJECT TABLE IF NOT EXISTS yunqi_object_****.`default`.ot_demo_day
WITH SERDEPROPERTIES (
'serialization.format'='1',
'odps.properties.rolearn'='acs:ram::139699392458****:role/aliyunodpsdefaultrole')
LOCATION
'oss://oss-cn-hangzhou-internal.aliyuncs.com/odps-external-****/ottest/'
TBLPROPERTIES (
'last_modified_time'='1731478307',
'transient_lastDdlTime'='1731478307',
'metadata.cache.mode'='manual',
'metadata.staleness.seconds'='3600');
刷新OBJECT TABLE元信息
Object Table的真实对象数据存储于OSS中。在MaxCompute中,对这些对象数据的元信息进行缓存,并基于缓存的元数据执行各种查询和计算。因此,在实际使用Object Table之前,需要对其进行一些缓存更新操作。您可以通过手动刷新或在建表时配置周期性刷新参数。
手动刷新
每次刷新均为全量元信息同步,您可自主控制刷新的时机与频率。
语法
ALTER TABLE <objecttable_name> REFRESH METADATA;
参数说明
objecttable_name:必填,表名。
示例
ALTER TABLE ot_demo_day REFRESH METADATA;
周期性刷新
如果Object Table映射的OSS目录中的文件经常发生变化,可以按周期刷新元数据。您只需要在建表时指定相关参数即可,减少维护的成本。
语法
SET odps.namespace.schema=true; SET odps.sql.type.system.odps2 = true; CREATE OBJECT TABLE ot_demo_day WITH serdeproperties ( 'odps.properties.rolearn'='acs:ram::xxxxxx:role/aliyunodpsdefaultrole' ) location 'oss://oss-cn-hangzhou.aliyuncs.com/odps-external-ottest/ottest/' tblproperties ( 'metadata.cache.mode' = 'periodic', 'metadata.staleness.seconds' = '3600' );
参数说明
metadata.staleness.seconds
:刷新周期。对于periodic
模式来说,必须要指定这个参数,取值范围为[1, 604800]
,表示1秒到1周范围内。该参数并非强制性保障,调度器将尽可能按照该参数进行执行。metadata.cache.mode
:刷新触发方式,有两种选择。periodic
:周期性触发。manual
:手动触发(默认),您可以自主控制触发时机。
查询OBJECT TABLE
Object Table获取了OSS目录中文件的元信息,您可以通过查询Object Table明细来浏览这些元信息,也可以使用SQL语句对元信息进行过滤、匹配等计算,包括但不限于Aggregation、Join、Window、Order By、Limit等。
语法
SELECT * FROM <objecttable_name>;
参数说明
objecttable_name:必填,表名。
示例
-- 您可以查询上传至指定OSS对象目录下的数据,若数据量大,您可以查看5条。
SELECT * FROM ot_demo_day [limit 5];
查询对象内容进行业务计算
查询过程本质上仅针对对象的元信息进行相关计算,并不涉及对象的实际内容。然而,实际的计算过程需要读取对象的真实内容。MaxCompute内置了下载函数,以便用户能够将其集成到实际的计算过程中。
语法
MaxCompute将读取一个对象的部分或全部内容,并以二进制形式返回。您可以在其他能够接收二进制字段作为参数的函数中使用读取到的数据。
/*
@return 返回被访问对象的二进制结果。如果某个relative_path不存在,则根据when_object_not_found的策略来返回数据,
*/
binary get_data_from_oss (
string full_object_table_name,
string key,
[long offset=0,] // 偏移量, >=0
[long length=-1,] // 读取长度, -1表示读取所有内容,不限长度
[string object_not_found_policy ='OUTPUT_NULL'] // 在该key对应的对象不存在时,如何处理
)
参数说明
参数名称 | 是否必填 | 参数说明 |
full_object_table_name | 必填 | 完整的Object Table表的路径,包括Project和Schema层,类似 |
key | 必填 | 即被访问对象在该Object Table中的名称。详情请参见查看OBJECT TABLE属性结果 |
offset | 可选 | 表示从字节流的角度来看,读取对象内容的起始位置,默认为0,即从开头开始读取。 |
length | 可选 | 表示需要读取的字节数,默认值为-1,即不对长度进行限制。 |
object_not_found_policy | 可选 | 表示如果缓存数据中存在某个对象的key,但在实际的OSS中该对象已不存在,那么MaxCompute应当如何返回当前函数调用的结果。可选择
|
示例
不同参数组合方式如下,默认Object Table的完整路径为project.default.ot_demo_day
。
-- 最完整形式
SELECT get_data_from_oss('project.default.ot_demo_day', key, 0, -1, 'OUTPUT_NULL') FROM ot_demo_day WHERE ...
-- 以下写法都与get_data_from_oss('project.default.ot_demo_day', key, 0, -1, 'OUTPUT_NULL')等价
SELECT get_data_from_oss('project.default.ot_demo_day', key) FROM ot_demo_day WHERE ...;
SELECT get_data_from_oss('project.default.ot_demo_day', key, 0) FROM ot_demo_day WHERE ...
SELECT get_data_from_oss('project.default.ot_demo_day', key, 0, -1) FROM ot_demo_day WHERE ...
SELECT get_data_from_oss('project.default.ot_demo_day', key, 'OUTPUT_NULL') FROM ot_demo_day WHERE ...
SELECT get_data_from_oss('project.default.ot_demo_day', key, 0, 'OUTPUT_NULL') FROM ot_demo_day WHERE ...
通过内置下载函数,用户能够充分利用Object Table和SQL的能力,从事与业务高度相关的活动。例如,在Data For AI的场景中进行数据预处理操作。假设我们需要从OSS上提取某些符合要求的图片数据的标签信息,示例如下。
INSERT INTO tbl_tags (tags, key, size)
SELECT udf_extract_tags (
get_data_from_oss('project.default.ot_demo_day', key)
) as tags, key, size
FROM ot_demo_day
WHERE size >= 5242880
AND (key LIKE '%.jpg' OR key LIKE '%.jpeg')
ORDER BY last_modified DESC
LIMIT 100000;
使用查询优化技术提升性能
默认情况下,在MaxCompute的SQL中访问某张表时,将根据该表的记录行数、记录的字节数以及总的计算资源(受限于用户的配额配置)进行合理且均匀的切片处理。此举旨在为不同的分片提供并行计算能力,从而有效控制并行任务中的长尾问题,提升整体查询性能。
这种切片方式对于需要下载对象表中对象内容以进行内存计算的SQL不太适用,性能表现并不是最佳方案,I/O操作容易成为瓶颈,从而导致长尾问题。考虑以下案例:
key | size |
a0000.jpg | 10MB |
a0001.jpg | 10MB |
a0002.jpg | 10MB |
…… | …… |
a1022.jpg | 10MB |
a1023.jpg | 10MB |
b.avi | 10GB |
假设我们仅有两个工作资源可用,按照普通内表的处理方式,以行数或记录字节进行切片,我们可能会切出两个split
对象,分别是split1([a0000.jpg ~ a0511.jpg]
)和split2([a0512.jpg ~ a1023.jpg, b.avi]
)。实际的split1所需下载的数据量为10 MB * 512 = 5 GB
,而split2所需下载的数据量为5 GB+10 GB=15 GB
。因此,split2对应的计算量明显高于split1,导致出现严重的长尾现象。
真正合理的逻辑是:当用户的SQL中存在下载对象的需求时,应尽量根据对象的实际大小进行切片,以最大限度地控制长尾问题。如果用户消费OSS对象数据的逻辑更加耗时,则更需要提供灵活的切片能力。针对上述案例,我们可以拆分出split1:[a0000.jpg ~ a1023.jpg]
和split2:[b.avi]
两个切片,这两个切片的下载量均为10 GB。
为此,MaxCompute的Object Table提供了这样的能力,并且默认按照对象的实际大小进行切片。该默认值为1GB,用户可根据需要进行调整,粒度可选择KB、MB或GB三个级别。
# 默认为1GB,用户可以自行调整
SET odps.sql.object.table.split.unit.gb = 1;
SELECT get_data_from_oss('project.default.ot_demo_day', key) FROM ot_demo_da WHERE ...
# 或者,用户选择MB级控制,优先级高于GB参数
SET odps.sql.object.table.split.unit.mb = 1;
SELECT get_data_from_oss('project.default.ot_demo_day', key) FROM ot_demo_da WHERE ...
# 或者,用户选择KB级控制,优先级高于GB、MB参数
SET odps.sql.object.table.split.unit.kb = 1;
SELECT get_data_from_oss('project.default.ot_demo_day', key) FROM ot_demo_da WHERE ...
若需要在某些情况下主动希望关闭此查询优化方案(该方案会启动两个作业,第一个作业负责进行一些预处理,并且可以在Logview上查看相关信息)。因此,MaxCompute的Object Table表也提供了相应的解决方案:
SET odps.sql.object.table.split.by.object.size.enabled = false;
SELECT get_data_from_oss('project.default.ot_demo_day', key) FROM ot_demo_day WHERE ...
删除OBJECT TABLE
Object Table本身会缓存用户的元信息,这将占用一定的存储空间并产生存储成本。因此,如果用户在业务上不再需要这些缓存数据,可以选择删除Object Table表。如后续业务需要重新使用这些数据,可以重建Object Table。
语法
DROP TABLE [IF EXISTS] <objecttable_name>;
参数说明
objecttable_name:必填,表名。
示例
DROP TABLE IF EXISTS ot_demo_day;