Importazione Sqoop: chiave primaria composita e chiave primaria testuale

Stack: installato HDP-2.3.2.0-2950 utilizzando Ambari 2.1

Lo schema del DB di origine si trova su SQL Server e contiene diverse tabelle che hanno la chiave primaria come:

  • Un varchar
  • Composito: due colonne varchar o una varchar + una colonna int o due colonne int. C’è un grande tavolo con? righe che ha tre colonne nel PK una int + due colonne varchar

Secondo la documentazione di Sqoop:

Sqoop cannot currently split on multi-column indices. If your table has no index column, or has a multi-column key, then you must also manually choose a splitting column. 

La prima domanda è: cosa ci si aspetta da ‘scegliere manualmente una colonna di divisione’ – come posso sacrificare il pk e usare solo una colonna o mi manca qualche concetto?

La tabella di SQL Server è (solo due colonne e formano una chiave primaria composta):

     ChassiNo varchar(8) Unchecked ECU_Name nvarchar(15) Unchecked 

    Ho proceduto con l’importazione, la tabella di origine ha 7909097 record :

     sqoop import --connect 'jdbc:sqlserver://somedbserver;database=somedb' --username someusname --password somepass --as-textfile --fields-terminated-by '|&|' --table ChassiECU --num-mappers 8 --warehouse-dir /dataload/tohdfs/reio/odpdw/may2016 --verbose 

    I preoccupanti avvisi e gli input e i record dei mapper non corretti:

     16/05/13 10:59:04 WARN manager.CatalogQueryManager: The table ChassiECU contains a multi-column primary key. Sqoop will default to the column ChassiNo only for this job. 16/05/13 10:59:08 WARN db.TextSplitter: Generating splits for a textual index column. 16/05/13 10:59:08 WARN db.TextSplitter: If your database sorts in a case-insensitive order, this may result in a partial import or duplicate records. 16/05/13 10:59:08 WARN db.TextSplitter: You are strongly encouraged to choose an integral split column. 16/05/13 10:59:38 INFO mapreduce.Job: Counters: 30 File System Counters FILE: Number of bytes read=0 FILE: Number of bytes written=1168400 FILE: Number of read operations=0 FILE: Number of large read operations=0 FILE: Number of write operations=0 HDFS: Number of bytes read=1128 HDFS: Number of bytes written=209961941 HDFS: Number of read operations=32 HDFS: Number of large read operations=0 HDFS: Number of write operations=16 Job Counters Launched map tasks=8 Other local map tasks=8 Total time spent by all maps in occupied slots (ms)=62785 Total time spent by all reduces in occupied slots (ms)=0 Total time spent by all map tasks (ms)=62785 Total vcore-seconds taken by all map tasks=62785 Total megabyte-seconds taken by all map tasks=128583680 Map-Reduce Framework Map input records=15818167 Map output records=15818167 Input split bytes=1128 Spilled Records=0 Failed Shuffles=0 Merged Map outputs=0 GC time elapsed (ms)=780 CPU time spent (ms)=45280 Physical memory (bytes) snapshot=2219433984 Virtual memory (bytes) snapshot=20014182400 Total committed heap usage (bytes)=9394716672 File Input Format Counters Bytes Read=0 File Output Format Counters Bytes Written=209961941 16/05/13 10:59:38 INFO mapreduce.ImportJobBase: Transferred 200.2353 MB in 32.6994 seconds (6.1235 MB/sec) 16/05/13 10:59:38 INFO mapreduce.ImportJobBase: Retrieved 15818167 records. 

    Tabella creata:

     CREATE EXTERNAL TABLE IF NOT EXISTS ChassiECU(`ChassiNo` varchar(8), `ECU_Name` varchar(15)) ROW FORMAT DELIMITED FIELDS TERMINATED BY '|' LOCATION '/dataload/tohdfs/reio/odpdw/may2016/ChassiECU'; 

    Risultato orribile (senza errori) –PROBLEM: 15818167 vs 7909097 (server sql) record:

      > select count(1) from ChassiECU; Query ID = hive_20160513110313_8e294d83-78aa-4e52-b90f-b5640268b8ac Total jobs = 1 Launching Job 1 out of 1 Tez session was closed. Reopening... Session re-established. Status: Running (Executing on YARN cluster with App id application_1446726117927_0059) -------------------------------------------------------------------------------- VERTICES STATUS TOTAL COMPLETED RUNNING PENDING FAILED KILLED -------------------------------------------------------------------------------- Map 1 .......... SUCCEEDED 14 14 0 0 0 0 Reducer 2 ...... SUCCEEDED 1 1 0 0 0 0 -------------------------------------------------------------------------------- VERTICES: 02/02 [==========================>>] 100% ELAPSED TIME: 6.12 s -------------------------------------------------------------------------------- OK _c0 15818167 

    Sorprendentemente, ho ottenuto un’accuratezza o una mancata corrispondenza di meno di 10 record se la chiave composta consisteva di un int (che è stato utilizzato per la suddivisione), ma sono ancora in apprensione per quelli!

    Come posso procedere?

    Specificare manualmente la colonna divisa. La colonna divisa non è necessariamente uguale a PK. Puoi avere PK complessi e alcune colonne Split int. È ansible specificare qualsiasi colonna intera o anche semplice funzione (alcune semplici funzioni come sottostringa o cast, non aggregazione o analitica). La colonna divisa preferibilmente dovrebbe essere un numero intero distribuito uniformsmente.

    Ad esempio se la colonna di divisione contiene poche righe con valore -1 e 10M righe con valori 10000 – 10000000 e num-mappers = 8, allora sqoop dividerà il set di dati tra i mapper in modo non uniforms:

    • 1 ° mappatore otterrà poche righe con -1,
    • Il 2 ° -7 ° mappatore otterrà 0 righe,
    • L’ottavo mappatore otterrà quasi 10 milioni di righe,

    ciò comporterà l’inclinazione dei dati e l’8th mapper verrà eseguito per sempre o addirittura fallito. E ho anche ottenuto i duplicati quando usato split-column non intero con MS-SQL. Quindi, usa la colonna split integer. Nel tuo caso con una tabella con solo due colonne varchar puoi o

    (1) aggiungi surrogate int PK e usalo anche come split o

    (2) suddividere manualmente i dati utilizzando la query personalizzata con la clausola WHERE ed eseguire sqoop alcune volte con num-mappers = 1, oppure

    (3) applicare qualche funzione deterministica di non aggregazione Integer alla colonna varchar, ad esempio cast (substr (…) int) come split-column.