2017-06-15 4 views
0

J'ai un fichier csv que j'essaye de traiter en utilisant Azure Data Lake Analytics U-SQL. Je suis assez nouveau à U-SQL alors s'il vous plaît, supportez-moi. Le fichier original est semi-structuré que j'ai réussi à corriger en utilisant le silent: true flag. Maintenant que c'est plus structuré, je voudrais remplir les cellules vides avec les données dans les cellules ci-dessus.Comment remplir une cellule vide avec les données ci-dessus en utilisant U-SQL

Mes données ressemble à ceci: CSV with empty cells

Mon problème réside dans les cellules vides dans les quatre premières colonnes.

La deuxième ligne contient des données que je souhaite copier dans les cellules vides situées en dessous (lignes 3-5). Les données de la ligne 7 doivent être copiées jusqu'à la ligne 8, les données de la ligne 9 doivent être copiées sur les lignes 10-13 et les données de la ligne 14 doivent être copiées sur les lignes 15-18.

Ceci doit être fait sans changer les valeurs dans la colonne 'Montant réclamé'.

Est-ce que quelqu'un a des idées sur la façon d'y parvenir en U-SQL?

Merci.

+0

Merci à tous pour les conseils. Je ne suis pas un développeur, donc cela peut prendre du temps pour le comprendre, mais j'apprécie sincèrement toute l'aide. – Ally

Répondre

0

Je pense que vous pouvez résoudre ce problème en utilisant des opérateurs définis par l'utilisateur U-SQL (UDO). Dans UDO, vous parcourez rangée par rangée et chaque fois que vous obtenez une ligne avec des valeurs vides, copiez les données de la rangée précédente.

+0

** Les lignes ne possèdent pas d'ordre ** - ce sont des conteneurs de données logiques semblables à des HashSets non dédutifs. L'ordre d'origine des lignes sérialisées ne transfère pas implicitement à un ensemble de lignes (et donc à un UDO), il doit être recréé. Soyez vigilant à chaque fois que votre approche * suppose * une commande - toute commande inter-lignes doit être explicitement spécifiée dans la langue. – Nabeel

+0

** Vous pouvez créer une commande ** - Vous pouvez utiliser le tri préliminaire pour maintenir l'ordre et traiter les données sur un seul sommet pour vous assurer qu'il fonctionne séquentiellement. Vous pouvez obtenir plus d'aide pour apprendre cela en utilisant cet article et laissez-moi savoir si vous ne comprenez pas comment cela fonctionne: https://blogs.msdn.microsoft.com/mrys/2016/06/08/how-do-i -combine-overlapping-ranges-using-u-sql-introduction-u-sql-reducer-udos/ – Jamil

+0

J'ai rencontré une situation similaire il y a plus d'un an et voici une discussion à ce sujet: https: //stackoverflow.com/questions/35624870/azur-data-lake-analytics-combine-overlapping-time-duration-using-u-sql J'espère que cela vous aidera à apprendre. – Jamil

1

La fonction d'analyse LAG permet d'accéder à une ligne à un décalage physique donné précédant la ligne en cours. Utilisez cette fonction analytique dans une expression SELECT pour comparer les valeurs de la ligne en cours avec les valeurs d'une ligne précédente.

https://msdn.microsoft.com/en-us/library/azure/mt791650.aspx

2

U-SQL est généralement une langue pour le traitement grand, ordre agnostique données - ce problème n'est pas un bon moyen pour elle

  • Il n'y a pas de critère de commande de ligne dans les données d'entrée.
  • Recréer l'ordre des lignes d'entrée dans U-SQL peut uniquement être effectué en limitant l'extraction à 1 sommet - ce qui limite la taille des données d'entrée et est en contradiction avec l'utilisation d'un grand langage parallèle.

Rowsets - les fondamentaux blocs de construction sont USQL - désordonnées conteneurs de données logiques. Ainsi, l'ordre des lignes dans l'entrée d'origine est perdu au moment où vous l'avez lu dans un jeu de lignes; vous devez recréer l'ordre dans U-SQL en utilisant une clé de commande.

Si l'on suppose il y a une telle clé de commande,

@data = SELECT A, LAST_VALUE(Col == "" ? null : Col) OVER (ORDER BY Key ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW) AS Col FROM @input; 

devrait faire puisque LAST_VALUE devrait ignorer les valeurs NULL. Remarque - Le code USQL documentation ne spécifie pas si les valeurs NULL sont ignorées - elles doivent être conformes aux conventions générales de la fonction agrégat/fenêtrage, mais cela doit être vérifié.

Vos données ne dispose pas d'une colonne de commande - pour créer un, vous devez

  1. Assurez-vous que toutes les données sont traitées par 1 sommet - [SqlUserDefinedExtractor(AtomicFileProcessing = true)]
  2. Ajouter une colonne de commande dans un extracteur personnalisé.

Cela peut être trop compliqué pour une quantité de données que vous pourriez simplement traiter localement avant de télécharger.

0

Une autre approche (LAST_VALUE ne fonctionne pas pour moi):

Si vous avez un numéro de ligne ou d'un champ d'horodatage alors il n'y a pas de problème

@tb1 = SELECT * FROM 
     (VALUES 
     (1, "Noah1"), 
     (2, (string)null), 
      (3, "Noah3"), 
      (5, (string) null), 
      (6, (string)null), 
      (7, "Noah6"), 
      (8, "Noah7") 
     ) AS T(Timestamp, a); 


@tb1 = 
    SELECT Timestamp, 
      [a], 
      [a] != null && [a] != LEAD([a], 1) OVER(ORDER BY Timestamp ASC) AS aSwitch 
    FROM @tb1; 

@tb1 = 
    SELECT Timestamp, 
      [a], 
      SUM(aSwitch ? 1 : 0) OVER(ORDER BY Timestamp ASC ROWS UNBOUNDED PRECEDING) AS aGrp 
    FROM @tb1; 

@tb1 = 
    SELECT Timestamp, 
      FIRST_VALUE([a]) OVER(PARTITION BY aGrp ORDER BY Timestamp ASC) AS aFilled 
    FROM @tb1; 

OUTPUT @tb1 TO "/test.csv" USING Outputters.Csv(outputHeader: true); 

Résultat:

"Timestamp","aFilled" 
1,"Noah1" 
2,"Noah1" 
3,"Noah3" 
5,"Noah3" 
6,"Noah3" 
7,"Noah6" 
8,"Noah7" 

Mais que faire si vous n'avez pas un tel champ? Dans les cas simples, vous pouvez utiliser un champ muet:

@tb1 = SELECT * FROM 
     (VALUES 
     ("Noah1"), 
     ((string)null), 
      ("Noah3"), 
      ((string) null), 
      ((string)null), 
      ("Noah6"), 
      ("Noah7") 
     ) AS T(a); 

@tb1 = SELECT 1 AS Timestamp, 
       [a] 
      FROM @tb1;