【问题标题】:String delimiter present in string not permitted in Polybase?Polybase中不允许字符串中存在字符串分隔符?
【发布时间】:2021-05-01 13:05:50
【问题描述】:

我正在使用存储在 Azure Data Lake Storage 中的 CSV 创建一个外部表,并使用 SQL Server 中的 Polybase 填充该表。

但是,我遇到了这个问题,并认为这可能是因为在一个特定的列中,字符串中存在双引号,并且字符串分隔符在 Polybase (STRING_DELIMITER = '"') 中指定为 "

HdfsBridge::recordReaderFillBuffer - Unexpected error encountered filling record reader buffer: HadoopExecutionException: Could not find a delimiter after string delimiter

例子:

我对此进行了相当广泛的研究,发现这个问题已经存在多年,但尚未看到任何解决方案。

任何帮助将不胜感激。

【问题讨论】:

  • 您能提供一些示例数据吗?这可能是问题所在。
  • 我添加了一个字符串,该字符串类似于我的列中的内容,我认为这是 Polybase 不允许这样的问题
  • 我的处理方法是指定字符串分隔符,导入该数据并使用 SQL 清理它。另一种思考方式是,你能用英文写一条你希望导入遵循的规则吗?
  • 假设您的数据还有其他列,您能否提供一个更真实的样本?
  • 如果您的示例是正确的,那么您没有处理正确编码的 CSV 文件。 RFC 4180 Common Format and MIME Type for Comma-Separated Values (CSV) Files 会让你将该字符串编码为:"Hello ""world"", it's me"(注意世界各地的双引号)。

标签: sql-server data-warehouse polybase


【解决方案1】:

我认为解决此问题的最简单方法是,因为您负责创建 .csv,因此使用不是逗号的分隔符并省略字符串分隔符。使用您知道不会出现在文件中的分隔符。我在示例中使用了管道,并且在将字符串导入数据库后对其进行清理。

一个简单的例子:

IF EXISTS ( SELECT * FROM sys.external_tables WHERE name = 'delimiterWorking' )
DROP EXTERNAL TABLE delimiterWorking
GO

IF EXISTS ( SELECT * FROM sys.tables WHERE name = 'cleanedData' )
DROP TABLE cleanedData
GO



IF EXISTS ( SELECT * FROM sys.external_file_formats WHERE name = 'ff_delimiterWorking' )
DROP EXTERNAL FILE FORMAT ff_delimiterWorking
GO

CREATE EXTERNAL FILE FORMAT ff_delimiterWorking
WITH (
    FORMAT_TYPE = DELIMITEDTEXT,
    FORMAT_OPTIONS (
        FIELD_TERMINATOR = '|',
        --STRING_DELIMITER = '"',
        FIRST_ROW = 2,
        ENCODING = 'UTF8'
        )
);
GO


CREATE EXTERNAL TABLE delimiterWorking (
    id                  INT NOT NULL,
    body                VARCHAR(8000) NULL
)
WITH (
    LOCATION = 'yourLake/someFolder/delimiterTest6.txt',
    DATA_SOURCE = ds_azureDataLakeStore,
    FILE_FORMAT = ff_delimiterWorking,
    REJECT_TYPE = VALUE,
    REJECT_VALUE = 0
);
GO


SELECT *
FROM delimiterWorking
GO



-- Fix up the data
CREATE TABLE cleanedData
WITH (
    CLUSTERED COLUMNSTORE INDEX,
    DISTRIBUTION = ROUND_ROBIN
    )
AS
SELECT
    id,
    body AS originalCol,
    SUBSTRING ( body, 2, LEN(body) - 2 ) cleanBody
FROM delimiterWorking
GO



SELECT *
FROM cleanedData

我的结果:

【讨论】:

    【解决方案2】:

    如果您将数据湖平面文件转换为 Parquet 格式,则可以避免字符串分隔符问题。

    输入:

    "ID" "NAME" "COMMENTS"
    "1" "DAVE" "Hi "I am Dave" from"
    "2" "AARO" "AARO"

    步骤:

    1 将平面文件转换为 Parquet 格式[使用 Azure 数据工厂]

    2 在数据湖中创建外部文件格式[假设主密钥,范围凭据可用]

    CREATE EXTERNAL FILE FORMAT PARQUET_CONV
    WITH (FORMAT_TYPE = PARQUET, 
    DATA_COMPRESSION = 'org.apache.hadoop.io.compress.SnappyCodec'
    );
    

    3 使用 FILE_FORMAT = PARQUET_CONV 创建外部表

    输出:

    我相信这是最好的选择,因为微软目前没有解决方案来处理外部表数据中出现的这个字符串分隔符

    【讨论】:

    • 这不会删除应该在字母I之前的引号之一吗?
    • @user3396351,纠正它仍然是一个错误,我们可以为所有出现的引号引入转义字符,除了(字符串分隔符)。无论是平面/拼花格式
    猜你喜欢
    • 1970-01-01
    • 2011-02-08
    • 1970-01-01
    • 2011-03-20
    • 2017-09-25
    • 2014-06-29
    • 2021-10-06
    • 1970-01-01
    • 2010-12-09
    相关资源
    最近更新 更多