2016-06-01 3 views
3

Ich habe eine CSV-Datei, die ich in Amazon DynamoDB importieren möchte. So lade ich es bis S3, ein EMR-Cluster, und erstellen Sie eine externe Tabelle wie folgt aufgebaut:Importieren einer CSV-Datei (mit leeren Strings und Duplikaten) in DynamoDB

hive> CREATE EXTERNAL TABLE s3_table_myitems (colA BIGINT, colB STRING, colC STRING, colD DOUBLE, colE DOUBLE, colF STRING, colG STRING) 
    ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' 
    WITH SERDEPROPERTIES ('serialization.null.format'='""') 
    STORED AS TEXTFILE 
    LOCATION 's3://bucketname/dirname/' 
    TBLPROPERTIES ('skip.header.line.count'='1'); 

Jede der Spalten in der CSV leer sein kann, aber DynamoDB kann nicht mit leeren Saiten umgehen (“ com.amazonaws.AmazonServiceException: One or more parameter values were invalid: An AttributeValue may not contain an empty string ").

Dies ist, was Amazon says:

Wir werden diese optional betrachten Verhalten in einer zukünftigen Version "leere Zeichenkette ignorieren". ... Als Workaround könnten Sie ... leere Attributwerte in NULLs umwandeln. Beispielsweise können Sie einen komplexeren SELECT-Ausdruck verwenden, um leere Strings in etwas anderes zu verwandeln, einschließlich , die sie auf NULL setzen.

So ist das, was ich mit aufkam, aber es sieht hässlich:

hive> INSERT INTO TABLE ddb_tbl_ingredients 
    SELECT 
    regexp_replace(colA, '^$', 'NULL'), 
    regexp_replace(colB, '^$', 'NULL'), 
    regexp_replace(colC, '^$', 'NULL'), 
    regexp_replace(colD, '^$', 'NULL'), 
    regexp_replace(colE, '^$', 'NULL'), 
    regexp_replace(colF, '^$', 'NULL'), 
    regexp_replace(colG, '^$', 'NULL') 
    FROM s3_table_ingredients; 

Gibt es eine bessere Lösung für das Gesamtproblem (kurz Vorverarbeiten des CSV) oder zumindest ein besser SELECT Syntax?


bearbeiten: Am Ende habe ich mit Dubletten sowie ("com.amazonaws.AmazonServiceException: Provided list of item keys contains duplicates") zu behandeln.

Für die Nachwelt, hier ist mein vollständiger Ablauf. Ich würde gerne von einem besseren Weg hören, sowohl für die Ästhetik als auch für die Leistung. Die Aufgabe ist scheinbar einfach („Importieren eine CSV-Datei in DynamoDB“), aber komme mit diesen Stunden bisher genommen hat: P

# source 
hive> CREATE EXTERNAL TABLE s3_table_myitems (colA STRING, colB STRING, colC DOUBLE, colD DOUBLE, colE STRING, colF STRING) 
    ROW FORMAT SERDE 'org.apache.hadoop.hive.serde2.OpenCSVSerde' 
    WITH SERDEPROPERTIES ('serialization.null.format'='""') 
    STORED AS TEXTFILE 
    LOCATION 's3://bucketname/dirname/' 
    TBLPROPERTIES ('skip.header.line.count'='1'); 

# destination 
hive> CREATE EXTERNAL TABLE ddb_tbl_myitems (colA STRING, colB STRING, colC DOUBLE, colD DOUBLE, colE STRING, colF STRING) 
    STORED BY 'org.apache.hadoop.hive.dynamodb.DynamoDBStorageHandler' 
    TBLPROPERTIES ("dynamodb.table.name" = "myitems", 
     "dynamodb.column.mapping" = "colA:colA,colB:colB,colC:colC,colD:colD,colE:colE,colF:colF"); 

# remove dupes - http://stackoverflow.com/a/34165762/594211 
hive> CREATE TABLE tbl_myitems_deduped AS 
    SELECT colA, min(colB) AS colB, min(colC) AS colC, min(colD) AS colD, min(colE) AS colE, min(colF) AS colF 
    FROM (SELECT colA, colB, colC, colD, unit, colF, rank() OVER 
     (PARTITION BY colA ORDER BY colB, colC, colD, colE, colF) 
     AS col_rank FROM s3_table_myitems) t 
    WHERE t.col_rank = 1 
    GROUP BY colA; 

# replace empty strings with placeholder 'NULL' 
hive> CREATE TABLE tbl_myitems_noempty AS 
    SELECT colA, 
    regexp_replace(colB, '^$', 'NULL') AS colB, 
    regexp_replace(colC, '^$', 'NULL') AS colC, 
    regexp_replace(colD, '^$', 'NULL') AS colD, 
    regexp_replace(colE, '^$', 'NULL') AS colE, 
    regexp_replace(colF, '^$', 'NULL') AS colF 
    FROM tbl_myitems_deduped 
    WHERE LENGTH(colA) > 0; 

# ...other preprocessing here... 

# insert to DB 
hive> INSERT INTO TABLE ddb_tbl_myitems 
    SELECT * FROM tbl_myitems_noempty; 

Hinweis: colA sind die Partition Schlüssel.

+0

Ich habe in das gleiche Problem gerannt. Ich habe das dedupling etwas anders gelöst, bin aber jetzt mit dem leeren String-Problem konfrontiert. Ich habe versucht, beide mit: 'serialization.null.format '='" "'' in den SerDe-Eigenschaften von OpenCSVSerde sowie in den TBLPROPERTIES wie in der einzigen Antwort bisher erwähnt. –

Antwort

0

Sie können Ihrer create table-Anweisung zusätzliche Tabelleneigenschaften hinzufügen, die jedes angegebene Zeichen als Nullwert behandeln.

TBLPROPERTIES('serialization.null.format'=''); 
+0

Ich habe das versucht. Das hat keine Auswirkung, da die leeren Strings einfach leere Strings in der CSV sind. Sie sind nicht null ('\ N'). – jrc

+0

Was ist, wenn Sie das Zeichen verwenden, das Sie in Ihren regexp_replace-Funktionen von '$ $' angeben? – Jared

Verwandte Themen