web-dev-qa-db-fra.com

Ruche Table Externe Sauter Première Rangée

J'utilise la version de Hive de Cloudera et j'essaie de créer une table externe sur un fichier CSV contenant les noms de colonne dans la première colonne. Voici le code que j'utilise pour le faire.

CREATE EXTERNAL TABLE Test ( 
  RecordId int, 
  FirstName string, 
  LastName string 
) 
ROW FORMAT serde 'com.bizo.Hive.serde.csv.CSVSerde' 
WITH SerDeProperties (  
  "separatorChar" = ","
) 
STORED AS TEXTFILE 
LOCATION '/user/File.csv'

Échantillon de données

RecordId,FirstName,LastName
1,"John","Doe"
2,"Jane","Doe"

Quelqu'un peut-il m'aider à sauter la première ligne ou dois-je ajouter une étape intermédiaire?

42
Rick Gittins

Les lignes d'en-tête dans les données sont un mal de tête perpétuel dans Hive. Sans modifier la source de Hive, je crois que vous ne pouvez pas vous en sortir sans étape intermédiaire. (Edit: Ce n'est plus vrai, voir la mise à jour ci-dessous)

Malheureusement, cela répond à votre question. Je vais donner quelques idées pour l'étape intermédiaire de la complétude.

Vous pouvez vous passer d'une étape supplémentaire dans votre chargement de données si vous souhaitez filtrer la ligne d'en-tête sur chaque requête qui touche la table. Malheureusement, cela ajoute un jeu supplémentaire un peu partout ailleurs. Et vous devrez faire preuve d'intelligence/désordre lorsque la ligne d'en-tête viole votre schéma. Si vous optez pour cette approche, vous pouvez envisager d’écrire un SerDe personnalisé qui facilite le filtrage de cette ligne. Malheureusement, SerDe ne peut pas supprimer complètement la ligne (ou qui pourrait constituer une solution possible), ils doivent renvoyer quelque chose comme null. Je n'ai jamais vu cette approche prise en pratique pour traiter les lignes d'en-tête car cela rend la lecture difficile, et la lecture a tendance à être beaucoup plus courante que l'écriture. Il peut y avoir une place si vous utilisez une ou plusieurs tables ou si la ligne d’en-tête n’est qu’une ligne parmi plusieurs lignes mal formées.

Vous pouvez faire ce filtrage une fois avec des variantes sur la suppression de la première ligne du chargement de données. Une clause WHERE dans une instruction INSERT le ferait. Vous pouvez utiliser des utilitaires tels que sed pour vous en débarrasser. J'ai vu les deux approches prises. Il existe des compromis entre votre approche et le seul moyen de traiter les lignes d'en-tête. Malheureusement, ces deux approches prennent du temps et nécessitent une duplication temporaire des données. Si vous avez absolument besoin de la ligne d'en-tête pour une autre application, la duplication sera permanente.

Mettre à jour:

A partir de Hive v0.13.0, vous pouvez utiliser skip.header.line.count. Vous pouvez également spécifier la même chose lors de la création de la table. Par exemple:

create external table testtable (name string, message string)
row format delimited 
fields terminated by '\t' 
lines terminated by '\n' 
location '/testtable'
tblproperties ("skip.header.line.count"="1");
62
Daniel Koverman

Pendant que vous avez la réponse de Daniel, voici quelques personnalisations possibles à l'aide de OpenCSVSerde:

CREATE EXTERNAL TABLE `mydb`.`mytable`(
    `product_name` string,
    `brand_id` string,
    `brand` string,
    `color` string,
    `description` string,
    `sale_price` string)
PARTITIONED BY (
    `seller_id` string)
ROW FORMAT SERDE
    'org.Apache.hadoop.Hive.serde2.OpenCSVSerde'
WITH SERDEPROPERTIES (
    'separatorChar' = '\t',
    'quoteChar' = '"',
    'escapeChar' = '\\')
STORED AS INPUTFORMAT
    'org.Apache.hadoop.mapred.TextInputFormat'
OUTPUTFORMAT
    'org.Apache.hadoop.Hive.ql.io.HiveIgnoreKeyTextOutputFormat'
LOCATION
    'hdfs://namenode.com:port/data/mydb/mytable'
TBLPROPERTIES (
    'serialization.null.format' = '',
    'skip.header.line.count' = '1')

Avec cela, vous avez un contrôle total sur le séparateur, le caractère de citation, le caractère d'échappement, la gestion des valeurs null et la gestion des en-têtes.

Regardez ici et ici .

9
Nirmal

Il suffit d’ajouter la propriété ci-dessous dans votre requête et le premier en-tête ou la première ligne de l’enregistrement ne se chargera pas ou sera ignorée.

Essaye ça

tblproperties ("skip.header.line.count"="1");
6
Manish
create external table table_name( 
Year int, 
Month int,
column_name data_type ) 
row format delimited fields terminated by ',' 
location '/user/user_name/example_data' TBLPROPERTIES('serialization.null.format'='', 'skip.header.line.count'='1');
1
Aman Mundra

J'ai également eu du mal avec cela et je n'ai trouvé aucun moyen de dire à Hive de sauter la première ligne, comme par exemple. à Greenplum. Alors finalement, je devais le supprimer des fichiers . "cat File.csv | grep -v ID_enregistrement> File_no_header.csv"

1
Atanas

Je ne sais pas si cela fonctionne avec ROW FORMAT serde 'com.bizo.Hive.serde.csv.CSVSerde' mais je suppose que cela devrait être similaire à ROW FORMAT DELIMITED FIELDS TERMINATED BY ',' .
Dans votre cas, la première ligne sera traitée comme une ligne normale. Mais le premier champ ne pouvant pas être INT, tous les champs, pour la première ligne, seront définis sur NULL. Vous n'avez besoin que d'une étape intermédiaire pour résoudre ce problème:

INSERT OVERWRITE TABLE Test
SELECT * from Test WHERE RecordId IS NOT NULL

Un seul inconvénient est que votre fichier csv d'origine sera modifié. J'espère que ça aide. GL!

1
www

skip.header.line.count fonctionne, mais si un outil externe accède à cette table, il verra toujours les données réelles sans sauter ces lignes 

1
itsavy

Juste pour ceux qui ont déjà créé la table avec l'en-tête. Voici la commande alter pour le même. Ceci est utile si vous avez déjà la table et souhaitez que la première ligne soit ignorée sans suppression ni recréation. Il aide également les personnes à se familiariser avec ALTER en tant qu’option avec TBLPROPERTIES.

ALTER TABLE tablename SET TBLPROPERTIES ("skip.header.line.count"="1");
0