web-dev-qa-db-fra.com

AWS Glue to Redshift: Est-il possible de remplacer, mettre à jour ou supprimer des données?

Voici quelques points essentiels en ce qui concerne ma configuration: 

  • J'ai des fichiers CSV téléchargés sur S3 et une configuration du robot d'exploration Glue pour créer la table et le schéma.
  • J'ai une configuration de travail Glue qui écrit les données de la table Glue dans notre base de données Amazon Redshift à l'aide d'une connexion JDBC. Le Job est également chargé de mapper les colonnes et de créer la table redshift.

En ré-exécutant un travail, je reçois des lignes en double dans redshift (comme prévu). Cependant, existe-t-il un moyen de remplacer ou de supprimer des lignes avant d'insérer les nouvelles données, à l'aide d'une clé ou de la configuration des partitions?

import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job

from awsglue.dynamicframe import DynamicFrame
from awsglue.transforms import SelectFields

from pyspark.sql.functions import lit

## @params: [TempDir, JOB_NAME]
args = getResolvedOptions(sys.argv, ['TempDir','JOB_NAME'])

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

columnMapping = [
    ("id", "int", "id", "int"),
    ("name", "string", "name", "string"),
]

datasource1 = glueContext.create_dynamic_frame.from_catalog(database = "db01", table_name = "table01", transformation_ctx = "datasource0")

applymapping1 = ApplyMapping.apply(frame = datasource1, mappings = columnMapping, transformation_ctx = "applymapping1")
resolvechoice1 = ResolveChoice.apply(frame = applymapping1, choice = "make_cols", transformation_ctx = "resolvechoice1")
dropnullfields1 = DropNullFields.apply(frame = resolvechoice1, transformation_ctx = "dropnullfields1")
df1 = dropnullfields1.toDF()
data1 = df1.withColumn('platform', lit('test'))
data1 = DynamicFrame.fromDF(data1, glueContext, "data_tmp1")

## Write data to redshift
datasink1 = glueContext.write_dynamic_frame.from_jdbc_conf(frame = data1, catalog_connection = "Test Connection", connection_options = {"dbtable": "table01", "database": "db01"}, redshift_tmp_dir = args["TempDir"], transformation_ctx = "datasink1")

job.commit()
17
krchun

C'est la solution que j'ai obtenue de l'assistance AWS Glue:

Comme vous le savez peut-être, bien que vous puissiez créer des clés primaires, Redshift n'impose pas l'unicité. Par conséquent, si vous réexécutez des travaux Glue, des lignes en double peuvent être insérées. Certains des moyens de maintenir l'unicité sont:

  1. Utilisez une table intermédiaire pour insérer toutes les lignes, puis effectuez une opération upsert/fusion [1] dans la table principale. Cette opération doit être effectuée en dehors de la colle.

  2. Ajoutez une autre colonne dans votre tableau redshift [1], comme un horodatage d'insertion, pour permettre la duplication, mais pour savoir laquelle est arrivée en premier ou en dernier, puis supprimez la duplication ultérieurement si vous en avez besoin.

  3. Chargez les données précédemment insérées dans le cadre de données, puis comparez les données à insérer pour éviter d'insérer des doublons [3].

[1] - http://docs.aws.Amazon.com/redshift/latest/dg/c_best-practices-upsert.html et http://www.silota.com/blog/Amazon- redshift-upsert-support-staging-table-replace-rows/

[2] - https://github.com/databricks/spark-redshift/issues/238

[3] - https://docs.databricks.com/spark/latest/faq/join-two-dataframes-duplicated-column.html

4
krchun

Les signets de travail sont la clé. Il vous suffit de modifier le travail et d'activer les "signets de travail" pour éviter de traiter les données déjà traitées . Notez que le travail doit être relancé une fois avant de pouvoir être détecté.

Pour plus d'informations, voir: http://docs.aws.Amazon.com/glue/latest/dg/monitor-continuations.html

Le nom "bookmark" est un peu tiré par les cheveux, à mon avis. Je ne l'aurais jamais regardée si je n'avais pas coïncidé par hasard lors de ma recherche.

8
Matthijs

Aujourd'hui, j'ai testé et obtenu une solution de contournement pour mettre à jour/supprimer de la table cible à l'aide d'une connexion JDBC.

J'ai utilisé comme ci-dessous 

import sys
from awsglue.transforms import *
from awsglue.utils import getResolvedOptions
from pyspark.context import SparkContext
from awsglue.context import GlueContext
from awsglue.job import Job

import pg8000
args = getResolvedOptions(sys.argv, [
    'JOB_NAME',
    'PW',
    'Host',
    'USER',
    'DB'
])
# ...
# Create Spark & Glue context

sc = SparkContext()
glueContext = GlueContext(sc)
spark = glueContext.spark_session
job = Job(glueContext)
job.init(args['JOB_NAME'], args)

# ...
config_port = ****
conn = pg8000.connect(
    database=args['DB'], 
    user=args['USER'], 
    password=args['PW'],
    Host=args['Host'],
    port=config_port
)
query = "UPDATE table .....;"

cur = conn.cursor()
cur.execute(query)
conn.commit()
cur.close()



query1 = "DELETE  AAA FROM  AAA A, BBB B WHERE  A.id = B.id"

cur1 = conn.cursor()
cur1.execute(query1)
conn.commit()
cur1.close()
conn.close()
1
cloudguru

Veuillez vérifier ceci répondre. Des explications et des exemples de code expliquent comment transférer des données dans Redshift à l'aide d'une table intermédiaire. La même approche peut être utilisée pour exécuter des requêtes SQL avant ou après que Glue ait écrit des données en utilisant les options preactions et postactions:

// Write data to staging table in Redshift
glueContext.getJDBCSink(
  catalogConnection = "redshift-glue-connections-test",
  options = JsonOptions(Map(
    "database" -> "conndb",
    "dbtable" -> staging,
    "overwrite" -> "true",
    "preactions" -> "<another SQL queries>",
    "postactions" -> "<some SQL queries>"
  )),
  redshiftTmpDir = tempDir,
  transformationContext = "redshift-output"
).writeDynamicFrame(datasetDf)
0
Yuriy Bondaruk

L'option de bookmarking dans Glue devrait faire l'affaire, comme suggéré ci-dessus. Je l'utilise avec succès lorsque mon source est S3 . http://docs.aws.Amazon.com/glue/latest/dg/monitor-continuations.html

0
Turja Chaudhuri

Selon mes tests (avec le même scénario), la fonctionnalité BOOKMARK ne fonctionne pas. Les données dupliquées sont insérées lorsque le travail est exécuté plusieurs fois. J'ai résolu ce problème en supprimant les fichiers de l'emplacement S3 quotidiennement (via lambda) et en implémentant les tables Staging & Target. les données seront insérées/mises à jour en fonction des colonnes clés correspondantes.

0
cloudguru