注意
本文档适用于 Ceph 的开发版本。
Ceph s3 select
概述
S3 Select 引擎在客户端和 Ceph 后端节点之间创建了一个高效的管道。S3 Select 引擎在尽可能靠近后端存储实现时效果最佳。
S3 Select 引擎使得使用类似 SQL 的语法来选择存储在 S3 对象中的受限数据子集成为可能。S3 Select 引擎有助于使用更高级别的分析应用程序(例如:SPARK-SQL)。S3 Select 引擎能够针对 S3 对象中结构化数据的适当子集,从而减少延迟并提高吞吐量。
例如:假设用户需要提取一个由另一列过滤的单列,并且这些列存储在一个大小为数 GB 的 S3 对象中的 CSV 文件中。以下查询执行此提取:select customer-id from s3Object where age>30 and age<65;
如果不使用 S3 Select,则必须先通过 RGW 从 OSD 检索整个 S3 对象,然后才能对数据进行过滤和提取。通过将查询“下推”到 radosgw,可以节省大量的网络和 CPU 开销。
对象越大,查询越精确,s3select 的性能就越好.
基本工作流程
S3 Select 查询通过 AWS-CLI 发送到 RGW
S3 Select 将身份验证和权限参数作为传入消息(POST)传递。RGWSelectObj_ObjStore_S3::send_response_data 是入口点,并根据输入的对象密钥处理每个获取的块。send_response_data 是第一个处理输入查询的:它提取查询和其他 CLI 参数。
RGW 对每个新获取的块(最大 4 MB)执行 S3 Select 查询。当前实现支持 CSV 对象。CSV 行有时会被块限制在中间“切断”,并且在处理查询时会跳过这些断行(每块的第一个或最后一个)。此类断行被存储并稍后与下一个断行(属于下一个块)合并,然后才进行处理。
对于每个已处理的块,输出消息会根据 aws specification 格式化并发送回客户端。RGW 支持以下响应:{:event-type,records} {:content-type,application/octet-stream} {:message-type,event}。对于聚合查询,最后一个块应被标识为输入结束。
基本功能
S3select 具有一套与 AWS 兼容的明确功能集。
已实现的软件架构支持基本的算术表达式、逻辑和比较表达式,包括嵌套函数调用和类型转换运算符,这为用户提供了极大的灵活性。
请查看下面的 s3-select-feature-table。
错误处理
检测到错误后,RGW 返回 400-Bad-Request,并将特定错误消息发送回客户端。目前,主要有两种错误类型。
语法错误:s3select 解析器拒绝与本_文档中描述的解析器语法定义不一致的用户请求。发生语法错误时,引擎会创建一个指向错误位置的错误消息。RGW 在特定错误响应中发送回错误消息。
处理时错误:运行时引擎可能会检测到仅在处理时发生的错误,对于此类错误,不同的错误消息会描述该错误。RGW 在特定错误响应中发送回错误消息。
功能支持
目前仅实现了 AWS select command 的一部分,下表描述了当前支持的功能。
下表描述了 s3-select 功能的当前实现
功能 |
详细信息 |
示例/描述 |
|---|---|---|
算术运算符 |
^ * % / + - ( ) |
select (int(_1)+int(_2))*int(_9) from s3object; |
|
select count(*) from s3object where cast(_1 as int)%2 = 0; |
|
|
select cast(2^10 as int) from s3object; |
|
比较运算符 |
> < >= <= = != |
select _1,_2 from s3object where (int(_1)+int(_3))>int(_5); |
逻辑运算符 |
AND OR NOT |
select count(*) from s3object where not (int(_1)>123 and int(_5)<200); |
逻辑运算符 |
is null |
对于表达式中的 null 指示返回 true/false |
逻辑运算符 |
is not null |
对于表达式中的 null 指示返回 true/false |
逻辑运算符和 NULL |
未知状态 |
查看 null-handle,观察逻辑运算符与 null 的结果。以下查询返回 0。 select count(*) from s3object where null and (3>2); |
带 NULL 的算术运算符 |
未知状态 |
查看 null-handle,观察与 NULL 进行二进制操作的结果,以下查询返回 0。 select count(*) from s3object where (null+1) and (3>2); |
与 NULL 比较 |
未知状态 |
查看 null-handle,观察与 NULL 进行比较操作的结果,以下查询返回 0。 select count(*) from s3object where (null*1.5) != 3; |
缺少列 |
未知状态 |
select count(*) from s3object where _1 is null; |
查询正在过滤谓词返回非 null 结果的行。如果 _1 或 _2 为 null,此谓词将返回 null |
select count(*) from s3object where (_1 > 12 and _2 = 0) is not null; |
|
投影列 |
类似于 switch/case default |
select case cast(_1 as int) + 1 when 2 then “a” when 3 then “b” else “c” end from s3object; |
投影列 |
类似于 if/then/else |
select case when (1+1=(2+1)*3) then ‘case_1’ when ((4*3)=(12)) then ‘case_2’ else ‘case_else’ end, age*2 from s3object; |
逻辑运算符 |
select coalesce(nullif(5,5),nullif(1,1.0),age+12) from s3object; |
|
逻辑运算符 |
select nullif(cast(_1 as int),cast(_2 as int)) from s3object; |
|
逻辑运算符 |
select count(*) from s3object where ‘ben’ in (trim(_5),substring(_1,char_length(_1)-3,3),last_name); |
|
逻辑运算符 |
select count(*) from s3object where substring(_3,char_length(_3),1) between “x” and trim(_1) and substring(_3,char_length(_3)-1,1) = “:”; |
|
逻辑运算符 |
select count(*) from s3object where first_name like ‘%de_’; select count(*) from s3object where _1 like "%a[r-s]; |
|
逻辑运算符 |
select count(*) from s3object where “jok_ai” like “%#_ai” escape “#”; |
|
true / false 谓词作为投影 |
select (cast(_1 as int)>123 = true) from s3object where address like ‘%new-york%’; |
|
谓词的别名作为投影 |
select (_1 like “_3_”) as likealias,_1 from s3object where likealias = true and cast(_1 as int) between 800 and 900; |
|
类型转换运算符 |
select cast(123 as int)%2 from s3object; |
|
类型转换运算符 |
select cast(123.456 as float)%2 from s3object; |
|
类型转换运算符 |
select cast(‘ABC0-9’ as string),cast(substr(‘ab12cd’,3,2) as int)*4 from s3object; |
|
类型转换运算符 |
select cast(5 as bool) from s3object; |
|
类型转换运算符 |
select cast(substring(‘publish on 2007-01-01’,12,10) as timestamp) from s3object; |
|
非 AWS 类型转换运算符 |
select int(_1),int( 1.2 + 3.4) from s3object; |
|
非 AWS 类型转换运算符 |
select float(1.2) from s3object; |
|
非 AWS 类型转换运算符 |
select to_timestamp(‘1999-10-10T12:23:44Z’) from s3object; |
|
聚合函数 |
sum |
select sum(int(_1)) from s3object; |
聚合函数 |
avg |
select avg(cast(_1 a float) + cast(_2 as int)) from s3object; |
聚合函数 |
min |
select min( int(_1) * int(_5) ) from s3object; |
聚合函数 |
max |
select max(float(_1)),min(int(_5)) from s3object; |
聚合函数 |
count |
select count(*) from s3object where (int(_1)+int(_3))>int(_5); |
时间戳函数 |
extract |
select count(*) from s3object where extract(year from to_timestamp(_2)) > 1950 and extract(year from to_timestamp(_1)) < 1960; |
时间戳函数 |
date_add |
select count(0) from s3object where date_diff(year,to_timestamp(_1),date_add(day,366, to_timestamp(_1))) = 1; |
时间戳函数 |
date_diff |
select count(0) from s3object where date_diff(month,to_timestamp(_1),to_timestamp(_2))) = 2; |
时间戳函数 |
utcnow |
select count(0) from s3object where date_diff(hours,utcnow(),date_add(day,1,utcnow())) = 24; |
时间戳函数 |
to_string |
select to_string( to_timestamp(“2009-09-17T17:56:06.234567Z”), “yyyyMMdd-H:m:s”) from s3object;
|
字符串函数 |
substring |
select count(0) from s3object where int(substring(_1,1,4))>1950 and int(substring(_1,1,4))<1960; |
substring with |
select substring(“123456789” from -4) from s3object; |
|
substring with |
select substring(“123456789” from 0 for 100) from s3object; |
|
字符串函数 |
trim |
select trim(’ foobar ‘) from s3object; |
字符串函数 |
trim |
select trim(trailing from ‘ foobar ‘) from s3object; |
字符串函数 |
trim |
select trim(leading from ‘ foobar ‘) from s3object; |
字符串函数 |
trim |
select trim(both ‘12’ from ‘1112211foobar22211122’) from s3objects; |
字符串函数 |
lower/upper |
select lower(‘ABcD12#$e’) from s3object; |
字符串函数 |
char_length character_length |
select count(*) from s3object where char_length(_3)=3; |
复杂查询 |
select sum(cast(_1 as int)), max(cast(_3 as int)), substring(‘abcdefghijklm’,(2-1)*3+sum(cast(_1 as int))/sum(cast(_1 as int))+1, (count() + count(0))/count(0)) from s3object; |
|
别名支持 |
select int(_1) as a1, int(_2) as a2 , (a1+a2) as a3 from s3object where a3>100 and a3<300; |
|
NULL
NULL 在 ceph-s3select 系统中是一个合法值,类似于其他数据库系统,即系统需要处理值为 NULL 的情况。
在我们的上下文中,NULL 的定义是缺少/未知,在这个意义上 NULL 不能在任何算术运算中产生值(a + NULL 将产生 NULL 值)。
算术比较也是如此,任何与 NULL 的比较都是 NULL,即未知。下面是包含 NULL 用例的真值表。
A 是 NULL |
结果 (NULL=UNKNOWN) |
|---|---|
NOT A |
NULL |
A OR False |
NULL |
A OR True |
True |
A OR A |
NULL |
A AND False |
False |
A AND True |
NULL |
A and A |
NULL |
S3-select 函数接口
时间戳函数
AWS-specs 中描述的时间戳功能已完全实现。
to_timestamp( string ):类型转换运算符将字符串转换为时间戳基本类型。to_timestamp 运算符能够将以下YYYY-MM-DDTHH:mm:ss.SSSSSS+/-HH:mm、YYYY-MM-DDTHH:mm:ss.SSSSSSZ、YYYY-MM-DDTHH:mm:ss+/-HH:mm、YYYY-MM-DDTHH:mm:ssZ、YYYY-MM-DDTHH:mm+/-HH:mm、YYYY-MM-DDTHH:mmZ、YYYY-MM-DDT或YYYYT字符串格式转换为时间戳。如果字符串格式中缺少时间(或部分时间),则用零替换缺少的_部分。如果缺少月份和日期,则默认值为 1。时区部分的格式为+/-HH:mm或Z,其中字母“Z”表示世界协调时间 (UTC)。时区值的范围可以在 -12:00 和 +14:00 之间。
extract(date-part from timestamp):该函数从输入时间戳中提取 date-part 并将其作为整数返回。支持的 date-part:year、month、week、day、hour、minute、second、timezone_hour、timezone_minute。
date_add(date-part, quantity, timestamp):该函数将 quantity(整数)添加到时间戳的 date-part 中,并将结果作为时间戳返回。它还包括时区计算。支持的 data-part:year、month、day、hour、minute、second。
date_diff(date-part, timestamp, timestamp):该函数返回一个整数,它是根据 date-part 计算的 2 个时间戳之间的差值。它包括时区计算。支持的 date-part:year、month、day、hour、minute、second。
utcnow():返回当前时间的时间戳。
to_string(timestamp, format_pattern):返回给定输入字符串格式的输入时间戳的字符串表示形式。
to_string 参数
格式 |
示例 |
描述 |
|---|---|---|
yy |
69 |
2 位年份 |
y |
1969 |
4 位年份 |
yyyy |
1969 |
零填充的 4 位年份 |
M |
1 |
月份 |
MM |
01 |
零填充的月份 |
MMM |
Jan |
缩写月份名称 |
MMMM |
January |
完整月份名称 |
MMMMM |
J |
月份的第一个字母(注意:不适用于 to_timestamp 函数) |
d |
2 |
月份中的日期 (1-31) |
dd |
02 |
零填充的月份中的日期 (01-31) |
a |
AM |
上午或下午 |
h |
3 |
小时 (1-12) |
hh |
03 |
零填充的小时 (01-12) |
H |
3 |
小时 (0-23) |
HH |
03 |
零填充的小时 (00-23) |
m |
4 |
分钟 (0-59) |
mm |
04 |
零填充的分钟 (00-59) |
s |
5 |
秒 (0-59) |
ss |
05 |
零填充的秒 (00-59) |
S |
0 |
秒的小数部分(精度:0.1,范围:0.0-0.9) |
SS |
6 |
秒的小数部分(精度:0.01,范围:0.0-0.99) |
SSS |
60 |
秒的小数部分(精度:0.001,范围:0.0-0.999) |
SSSSSS |
60000000 |
秒的小数部分(最大精度:1 纳秒,范围:0.0-0999999999) |
n |
60000000 |
纳秒 |
X |
+07 或 Z |
小时偏移量,如果偏移量为 0,则为“Z” |
XX 或 XXXX |
+0700 或 Z |
小时和分钟偏移量,如果偏移量为 0,则为“Z” |
XXX 或 XXXXX |
+07:00 或 Z |
小时和分钟偏移量,如果偏移量为 0,则为“Z” |
X |
7 |
小时偏移量 |
xx 或 xxxx |
700 |
小时和分钟偏移量 |
xxx 或 xxxxx |
+07:00 |
小时和分钟偏移量 |
聚合函数
count() :根据匹配条件的行数(如果存在)返回整数。
sum(expression) :返回所有匹配条件的行(如果存在)的表达式摘要。
avg(expression) :返回所有匹配条件的行(如果存在)的表达式平均值。
max(expression) :返回所有匹配条件的表达式的最大结果(如果存在)。
min(expression) :返回所有匹配条件的表达式的最小结果(如果存在)。
字符串函数
substring(string,from,to) :substring( string from start [ for length ] ) 根据 from、to 输入从输入字符串中提取字符串。 substring(string from ) substring(string from for)
char_length :返回字符串中的字符数(character_length 执行相同的操作)。
trim :trim ( [[leading | trailing | both remove_chars] from] string ) 从目标字符串中修剪前导/尾随(或两者)字符,默认为空格字符。
upper\lower :将字符转换为小写/大写。
SQL Limit 运算符
SQL LIMIT 运算符用于限制查询处理的行数。达到用户设置的限制后,RGW 停止获取额外的块。TODO:为聚合和非聚合查询添加示例。
别名
别名编程构造是 s3-select 语言的重要组成部分,它使编程更加出色,尤其是对于包含多列的对象或在复杂查询的情况下。
解析包含别名构造的语句时,它将别名替换为对正确投影列的引用,在查询执行时,该引用会像任何其他表达式一样进行评估。
存在自引用(或循环)引用的风险,可能导致堆栈溢出(无限循环),因此在评估别名时,会对其进行循环引用验证。
别名还维护一个结果缓存,这意味着给定别名的连续使用不会再次评估表达式。结果而是从缓存中返回。
每添加一行,缓存就会失效,因为结果可能会有所不同。
测试
s3select 包含几个测试框架,为其功能提供了广泛的覆盖。
(1) 与受信任引擎进行比较的测试,这意味着 C/C++ 编译器是一个受信任的表达式评估器,因为算术和逻辑表达式的语法相同(s3select 与 C 比较),该框架运行相等的表达式并验证其结果。专用的表达式生成器为每个新测试会话生成不同的表达式集。
(2) 比较语法不同但语义等效的查询结果。此类测试验证不同的运行时流在每次运行中都会使用不同的随机数据集生成相同的结果。
例如,对于包含随机数(1-1000)的数据集,以下查询将生成相同的结果。 select count(*) from s3object where char_length(_3)=3; select count(*) from s3object where cast(_3 as int)>99 and cast(_3 as int)<1000;
常量数据集,传统的测试方式。查询处理常量数据集,其结果根据常量结果进行验证。
附加语法支持
S3select 语法支持表别名 select s._1 from s3object s where s._2 = ‘4’;
S3select 语法支持大小写不敏感 Select SUM(Cast(_1 as int)) FROM S3Object;
S3select 语法支持没有分号结尾的语句 select count(*) from s3object
向 RGW 发送查询
任何 HTTP 客户端都可以向 RGW 发送 s3-select 请求,该请求必须符合 AWS Request syntax。
使用 AWS CLI 向 RGW 发送 s3-select 请求时,客户端必须遵循 AWS command reference。下面是一个示例
aws --endpoint-url http://localhost:8000 s3api select-object-content
--bucket {BUCKET-NAME}
--expression-type 'SQL'
--scan-range '{"Start" : 1000, "End" : 1000000}'
--input-serialization
'{"CSV": {"FieldDelimiter": "," , "QuoteCharacter": "\"" , "RecordDelimiter" : "\n" , "QuoteEscapeCharacter" : "\\" , "FileHeaderInfo": "USE" }, "CompressionType": "NONE"}'
--output-serialization '{"CSV": {"FieldDelimiter": ":", "RecordDelimiter":"\t", "QuoteFields": "ALWAYS"}}'
--key {OBJECT-NAME}
--request-progress '{"Enabled": True}'
--expression "select count(0) from s3object where int(_1)<10;" output.csv
输入序列化
FileHeaderInfo -> (string) 描述输入的第一行。有效值为
NONE :第一行不是标题。IGNORE :第一行是标题,但您不能使用标题值来指示表达式中的列。可以使用列位置(例如 _1, _2, ...)来指示列 (SELECT s._1 FROM S3OBJECT s)。USE :第一行是标题,您可以使用标题值来标识表达式中的列 (SELECT column_name FROM S3OBJECT)。
QuoteEscapeCharacter -> (string) 用于转义已转义值内引号字符的单个字符。
RecordDelimiter -> (string) 用于分隔输入中单个记录的单个字符。除了默认值之外,您可以指定任意分隔符。
FieldDelimiter -> (string) 用于分隔记录中单个字段的单个字符。您可以指定任意分隔符。
输出序列化
AWS CLI 示例
aws s3api select-object-content --bucket “mybucket” --key keyfile1 --expression “SELECT * FROM s3object s” --expression-type ‘SQL’ --request-progress ‘{“Enabled”: false}’ --input-serialization ‘{“CSV”: {“FieldDelimiter”: “,”}, “CompressionType”: “NONE”}’ --output-serialization ‘{“CSV”: {“FieldDelimiter”: “:”, “RecordDelimiter”:”\t”, “QuoteFields”: “ALWAYS”}}’ /dev/stdout
QuoteFields -> (string) 指示是否在输出字段周围使用引号。ALWAYS:始终对输出字段使用引号。ASNEEDED(未实现):在需要时对输出字段使用引号。
RecordDelimiter -> (string) 用于分隔输出中单个记录的单个字符。除了默认值之外,您可以指定任意分隔符。
FieldDelimiter -> (string) 用于分隔记录中单个字段的值。您可以指定任意分隔符。
扫描范围选项
AWS-CLI 的扫描范围选项使客户端能够仅扫描和处理对象的选定部分。此选项通过跳过不感兴趣的对象部分来减少输入/输出操作和带宽。TODO:不同的数据源(CSV、JSON、Parquet)
CSV 解析行为
s3-select引擎包含一个 CSV 解析器,它按如下方式解析 s3-object。- 每行以row-delimiter结尾。-field-separator分隔相邻列,连续的field separator实例定义一个 NULL 列。-quote-character覆盖field separator,这意味着field separator被视为引号之间的任何字符。-escape character禁用特殊字符的解释,除了row delimiter。以下是 CSV 解析规则的示例。
功能 |
描述 |
input ==> tokens |
|---|---|---|
NULL |
连续字段分隔符 |
,,1,,2, ==> {null}{null}{1}{null}{2}{null} |
QUOTE |
引号字符覆盖字段分隔符 |
11,22,”a,b,c,d”,last ==> {11}{22}{“a,b,c,d”}{last} |
Escape |
转义字符覆盖元字符。转义符被移除 |
11,22,str=\”abcd\”\,str2=\”123\”,last ==> {11}{22}{str=”abcd”,str2=”123”}{last} |
行分隔符 |
没有结束引号,行分隔符是结束行 |
11,22,a=”str,44,55,66 ==> {11}{22}{a=”str,44,55,66} |
csv 标头信息 |
FileHeaderInfo 标签 |
“USE” 值表示第一行上的每个标记都是列名,“IGNORE” 值表示跳过第一行 |
JSON
JSON 读取器已与 s3select-engine 集成,允许客户端使用 SQL 语句从 JSON 文档中扫描和提取信息。需要注意的是,CSV、Parquet 和 JSON 文档的数据读取器和解析器与 SQL 引擎本身是分离的,因此所有这些读取器都使用相同的 SQL 引擎。
重要的是要注意,JSON 文档中的值可以以各种方式嵌套,例如嵌套在对象或数组中。这些对象和数组可以相互嵌套,没有任何限制。使用 SQL 查询 JSON 文档中的特定值时,客户端必须通过 SELECT 语句中的路径指定值的位置。
SQL 引擎以基于行的方式处理 SELECT 语句。它使用语句中指定的列来执行其投影计算,并且每行包含这些列的值。换句话说,SQL 引擎一次处理一行(并聚合结果),使用列中的值来执行 SQL 计算。然而,JSON 文档的通用结构没有像 CSV 或 Parquet 那样的行和列结构。相反,是 SQL 语句本身在查询 JSON 文档时定义行和列。
使用 SQL 查询 JSON 文档时,SELECT 语句中的 FROM 子句定义行边界。JSON 文档中的一行应该类似于查询 CSV 对象时用于定义行的行分隔符,以及查询 Parquet 对象时用于定义行的行组。语句“SELECT ... FROM s3object[*].aaa.bb.cc”指示读取器搜索路径“aaa.bb.cc”,并根据此路径的出现定义行边界。当读取器遇到路径时,一行开始,当读取器退出路径的最内层部分(在本例中为对象“cc”)时,一行结束。
注意:查询 JSON 文档的语义可能会发生变化,并且可能与当前描述的方法不同。
TODO:对象和数组值的相关示例。
JSON 查询示例
{
"firstName": "Joe",
"lastName": "Jackson",
"gender": "male",
"age": "twenty",
"address": {
"streetAddress": "101",
"city": "San Diego",
"state": "CA"
},
"firstName": "Joe_2",
"lastName": "Jackson_2",
"gender": "male",
"age": 21,
"address": {
"streetAddress": "101",
"city": "San Diego",
"state": "CA"
},
"phoneNumbers": [
{ "type": "home1", "number": "734928_1","addr": 11 },
{ "type": "home2", "number": "734928_2","addr": 22 },
{ "type": "home3", "number": "734928_3","addr": 33 },
{ "type": "home4", "number": "734928_4","addr": 44 },
{ "type": "home5", "number": "734928_5","addr": 55 },
{ "type": "home6", "number": "734928_6","addr": 66 },
{ "type": "home7", "number": "734928_7","addr": 77 },
{ "type": "home8", "number": "734928_8","addr": 88 },
{ "type": "home9", "number": "734928_9","addr": 99 },
{ "type": "home10", "number": "734928_10","addr": 100 }
],
"key_after_array": "XXX",
"description" : {
"main_desc" : "value_1",
"second_desc" : "value_2"
}
}
# the from-clause define a single row.
# _1 points to root object level.
# _1.age appears twice in Documnet-row, the last value is used for the operation.
query = "select _1.firstname,_1.key_after_array,_1.age+4,_1.description.main_desc,_1.description.second_desc from s3object[*];";
expected_result = Joe_2,XXX,25,value_1,value_2
# the from-clause points the phonenumbers array (it defines the _1)
# each element in phoneNumbers array define a row.
# in this case each element is an object contains 3 keys/values.
# the query "can not access" values outside phonenumbers array, the query can access only values appears on _1.phonenumbers path.
query = "select cast(substring(_1.number,1,6) as int) *10 from s3object[*].phonenumbers where _1.type='home2';";
expected_result = 7349280
BOTO3
由于 AWS-cli 支持,使用 BOTO3 是“自然”且容易的。
import pprint
def run_s3select(bucket,key,query,column_delim=",",row_delim="\n",quot_char='"',esc_char='\\',csv_header_info="NONE"):
s3 = boto3.client('s3',
endpoint_url=endpoint,
aws_access_key_id=access_key,
region_name=region_name,
aws_secret_access_key=secret_key)
result = ""
try:
r = s3.select_object_content(
Bucket=bucket,
Key=key,
ExpressionType='SQL',
InputSerialization = {"CSV": {"RecordDelimiter" : row_delim, "FieldDelimiter" : column_delim,"QuoteEscapeCharacter": esc_char, "QuoteCharacter": quot_char, "FileHeaderInfo": csv_header_info}, "CompressionType": "NONE"},
OutputSerialization = {"CSV": {}},
Expression=query,
RequestProgress = {"Enabled": progress})
except ClientError as c:
result += str(c)
return result
for event in r['Payload']:
if 'Records' in event:
result = ""
records = event['Records']['Payload'].decode('utf-8')
result += records
if 'Progress' in event:
print("progress")
pprint.pprint(event['Progress'],width=1)
if 'Stats' in event:
print("Stats")
pprint.pprint(event['Stats'],width=1)
if 'End' in event:
print("End")
pprint.pprint(event['End'],width=1)
return result
run_s3select(
"my_bucket",
"my_csv_object",
"select int(_1) as a1, int(_2) as a2 , (a1+a2) as a3 from s3object where a3>100 and a3<300;")
S3 SELECT 响应
错误响应
<?xml version="1.0" encoding="UTF-8"?>
<Error>
<Code>NoSuchKey</Code>
<Message>The resource you requested does not exist</Message>
<Resource>/mybucket/myfoto.jpg</Resource>
<RequestId>4442587FB7D0A2F9</RequestId>
</Error>
报告响应
HTTP/1.1 200
<?xml version="1.0" encoding="UTF-8"?>
<Payload>
<Records>
<Payload>blob</Payload>
</Records>
<Stats>
<Details>
<BytesProcessed>long</BytesProcessed>
<BytesReturned>long</BytesReturned>
<BytesScanned>long</BytesScanned>
</Details>
</Stats>
<Progress>
<Details>
<BytesProcessed>long</BytesProcessed>
<BytesReturned>long</BytesReturned>
<BytesScanned>long</BytesScanned>
</Details>
</Progress>
<Cont>
</Cont>
<End>
</End>
</Payload>
响应描述
对于 CEPH S3 Select,响应可以是以下类型的消息
Records message:可以包含单个记录、部分记录或多个记录。根据结果的大小,一个响应可以包含一个或多个此类消息。
Error message:检测到错误后,RGW 返回 400 Bad Request,并根据其类型将特定错误消息发送回客户端。
Continuation message:Ceph S3 定期发送此消息以保持 TCP 连接打开。这些消息会随机出现在响应中。客户端必须检测消息类型并相应地处理它。
Progress message:如果请求,Ceph S3 会定期发送此消息。它包含有关已开始但尚未完成的查询进度的信息。
Stats message:Ceph S3 在请求结束时发送此消息。它包含有关查询的统计信息。
End message:表示请求已完成,并且不会再发送任何消息。在客户端收到 End 消息之前,您不应假定请求已完成。