Azure Synapse 无服务器 - Azure Synapse 无服务器池中的流加载镶木地板意外结束

Azure Synapse Serverless -- Unexpected end of stream loading parquet in Azure Synapse Serverless pool

尝试加载以下镶木地板文件,导致 Unexpected end of stream 错误。也许 parquet 文件已损坏?

预期查询

SELECT * FROM OPENROWSET(
        BULK N'/path/to/my.parquet',
        DATA_SOURCE='my_blob_datasource',
        FORMAT='PARQUET'
) as somehow_necessary_alias

错误陈述

Statement ID: {1F956C7F-FA37-4D34-AC0D-D4BDF8336160}
Query hash: 0x729ED47717032037
Distributed request ID: {5815A501-2179-4968-BE71-3B7AACFE717C}.
Total size of data scanned is 27 megabytes,
total size of data moved is 290 megabytes,
total size of data written is 0 megabytes.

Msg 15813, Level 16, State 1, Line 1 Error handling external file: 
'Unexpected end of stream'. File/External table name:
https://mystorageaccount.blob.core.windows.net/mycontainer/path/to/my.parquet

我重现了场景,并能够在 Azure Synapse Serverless SQL 池中成功 运行 查询。

注意:确保您有权访问该文件并确保您使用的是 UTF-8 数据库排序规则。

您可以通过此 document 了解更多详细信息。

我的问题是我使用的 parquet.net 版本错误地写入了 Int16 数据(参见此处的问题:https://github.com/aloneguid/parquet-dotnet/issues/16)。我将 属性 更改为 Int32 并且错误消失了。

所以我们找到了答案,但我无法制作一个可以分享的可重现示例,但我会尽可能多地给出解释。 parquet 文件是由 pandas.to_parquet() 使用 pyarrow 引擎创建的。目前有一个箭头错误,其中一个尚未诊断的 pandas 索引快速转换为在名为 "__index_level_0__" 的末尾添加的额外列。我想这就是出现 Unexpected end of stream 错误的原因。

此问题最初被标记为 pandas issue, but then moved to an Arrow Jira ticket,其中有一个可重现的示例。

但是,我们的场景有所不同,因为我们没有使用 pandas.to_parquet()partition_cols 参数,所以发生了一些奇怪的事情。幸运的是,pandas docs 提出了以下建议:

the code below creates a parquet file with three columns if you use pyarrow for serialization: a, b, and __index_level_0__. If you’re using fastparquet, the index may or may not be written to the file.

python df.to_parquet("test.parquet", engine="pyarrow")

This unexpected extra column causes some databases like Amazon Redshift to reject the file, because that column doesn’t exist in the target table.

If you want to omit a dataframe’s indexes when writing, pass index=False to to_parquet()

p.s。如果您使用 pandas 创建镶木地板文件以上传到 Synapse,请务必将 use_deprecated_int96_timestamps=True 传递给 to_parquet(),以便 Synapse 正确解析您的日期时间列。有关相关信息,请参阅 this question