Azure Databricks в Azure SQL DW: длинные текстовые столбцы

Я хочу заполнить Azure SQL DW из среды записной книжки Azure Databricks. Я использую встроенный коннектор с pyspark:

sdf.write \
  .format("com.databricks.spark.sqldw") \
  .option("forwardSparkAzureStorageCredentials", "true") \
  .option("dbTable", "test_table") \
  .option("url", url) \
  .option("tempDir", temp_dir) \
  .save()

Это работает нормально, но я получаю сообщение об ошибке, когда включаю строковый столбец с достаточно длинным содержимым. Я получаю следующую ошибку:

Py4JJavaError: ошибка при вызове o1252.save. : com.databricks.spark.sqldw.SqlDWSideException: SQL DW не удалось выполнить запрос JDBC, созданный соединителем.

Базовые исключения SQLException: - com.microsoft.sqlserver.jdbc.SQLServerException: HdfsBridge :: recordReaderFillBuffer - Произошла непредвиденная ошибка при заполнении буфера чтения записи: HadoopSqlException: строка или двоичные данные будут усечены. [ErrorCode = 107090] [SQLState = S0001]

Насколько я понимаю, это потому, что тип строки по умолчанию - NVARCHAR (256). Можно настроить (ссылка) , но максимальная длина NVARCHAR составляет 4 КБ символов. Мои строки иногда достигают 10 тысяч символов. Поэтому мне любопытно, как я могу вместо этого экспортировать определенные столбцы как текст / длинный текст.

Я предполагаю, что следующее будет работать, если только preActions будут выполнены после создания таблицы. Это не так, и поэтому он терпит неудачу.

sdf.write \
  .format("com.databricks.spark.sqldw") \
  .option("forwardSparkAzureStorageCredentials", "true") \
  .option("dbTable", "test_table") \
  .option("url", url) \
  .option("tempDir", temp_dir) \
  .option("preActions", "ALTER TABLE test_table ALTER COLUMN value NVARCHAR(MAX);") \
  .save()

Кроме того, postActions выполняются после вставки данных, поэтому это также не сработает.

Любые идеи?


person casparjespersen    schedule 04.03.2020    source источник


Ответы (1)


У меня была аналогичная проблема, и я смог ее решить, используя следующие параметры:

.option("maxStrLength",4000)

Таким образом, в вашем примере это будет:

sdf.write \
  .format("com.databricks.spark.sqldw") \
  .option("forwardSparkAzureStorageCredentials", "true") \
  .option("dbTable", "test_table") \
  .option("maxStrLength",4000)\
  .option("url", url) \
  .option("tempDir", temp_dir) \
  .save()

Это задокументировано здесь:

StringType в Spark сопоставляется с типом NVARCHAR (maxStrLength) в Azure Synapse. Вы можете использовать maxStrLength, чтобы установить длину строки для всех столбцов типа NVARCHAR (maxStrLength), которые находятся в таблице с именем dbTable в Azure Synapse.

Если ваши струны превышают 4k, вам следует:

Предварительно определите столбец таблицы с помощью NVARCHAR (MAX), а затем напишите в режиме добавления в таблицу. В этом случае вы не можете использовать индекс columnstore по умолчанию, поэтому либо используйте HEAP, либо установите правильные индексы. Ленивая куча будет:

CREATE TABLE example.table
(
    NormalColumn NVARCHAR(256),
    LongColumn NVARCHAR(4000),
    VeryLongColumn NVARCHAR(MAX)
) 
WITH (HEAP)

Затем вы можете писать в него как обычно, без параметра maxStrLength. Это также означает, что вы не переопределяете все остальные строковые столбцы.

Другие варианты:

  1. используйте split для преобразования 1 столбца в несколько столбцов строк.
  2. сохранить как паркет, а затем загрузить изнутри синапса
person jabberwocky    schedule 09.09.2020
comment
На самом деле в большинстве случаев VARCHAR (4000) будет лучше, чем NVARCHAR (4000), но другая тема. - person jabberwocky; 30.04.2021