Redshift не мог импортировать пустое строковое значение, пока не был указан VARCHAR (65535) - PullRequest
0 голосов
/ 21 декабря 2018

Я столкнулся со странным поведением импорта данных в Redshift из Postgres с помощью AWS Glue.У меня есть поле в таблице postgres lastname varchar(255).AWS Glue перемещает этот стол с помощью такого кода:

import sys, boto3
from pyspark.context import SparkContext
from awsglue.job import Job
from awsglue.utils import getResolvedOptions
from awsglue.context import GlueContext


def getDBUrl(database):
    dbConnection = glue.get_connection(Name=database)
    jdbc_url = dbConnection['Connection']['ConnectionProperties']['JDBC_CONNECTION_URL']
    username = dbConnection['Connection']['ConnectionProperties']['USERNAME']
    password = dbConnection['Connection']['ConnectionProperties']['PASSWORD']
    jdbc_url = jdbc_url + '?user=' + username + '&password=' + password
    print jdbc_url
    return jdbc_url


args = getResolvedOptions(sys.argv, ['TempDir', 'JOB_NAME'])

sc = sc if 'sc' in vars() else SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session

job = Job(glueContext)
job.init(args['JOB_NAME'], args)


source_database_connection = 'Postgres'
target_database_connection = 'Redshift'

bound_query = """
(
    select COALESCE(max(id),0)
    from {0}
) as temp
"""

glue = boto3.client(service_name='glue', region_name='us-east-1')

# Create connection urls
jdbc_url_source = getDBUrl(database=source_database_connection)
jdbc_url_target = getDBUrl(database=target_database_connection)


def extract_and_save(source_table, target_table, source_bound_query):
    print "loading {0}".format(target_table)
    (upper_bound,) = (spark.read
                      .jdbc(url=jdbc_url_source, table=source_bound_query)
                      .first())

    df = spark.read.jdbc(url=jdbc_url_source,
                         table=source_table,
                         column='id',
                         lowerBound=1,
                         upperBound=upper_bound + 10,
                         numPartitions=50)

    df.write.format("com.databricks.spark.redshift") \
        .option("url", jdbc_url_target) \
        .option("dbtable", target_table) \
        .option("tempdir", args["TempDir"]) \
        .option("aws_iam_role", "AWS_ROLE") \
        .mode("overwrite") \
        .option("jdbcdriver", "com.amazon.redshift.jdbc41.Driver") \
        .save()

source_user = """
(
SELECT 
    cast(firstname as VARCHAR(65535)),
    last_updated,
    registration_date,
    date_created,
    cast(sex as VARCHAR(65535)),
    id,
    cast(email as VARCHAR(65535)),
    cast(lastname as VARCHAR(65535)),
    cast(username as VARCHAR(65535))
FROM user
) as temp
"""


# do extract
extract_and_save(
    source_user,
    "user",
    bound_query.format("user"))

job.commit()

И он отлично работает.Однако, как только я начинаю использовать в полях varchar не VARCHAR(65535), а оригинальный размер varchar(255), я получаю ошибку при импорте: Missing data for not-null field.Из STL_LOAD_ERROR я могу узнать, что я получаю пустую строку в поле lastname.Но в STL_LOAD_ERROR это значение помечено как @NULL@.В определении таблицы Redshift нет ограничения not null.

Так почему varchar(255) вызывает проблемы с обработкой пустых строк, а varchar(65535) делает это безупречно?

...