web-dev-qa-db-fra.com

Comment transposer/pivoter les données dans la ruche?

Je sais qu'il n'y a pas de moyen direct de transposer des données dans Hive. J'ai suivi cette question: Y at-il un moyen de transposer des données dans Hive? , mais comme il n’ya pas de réponse finale, ne peut pas aller jusqu'au bout.

Ceci est la table que j'ai:

 | ID   |   Code   |  Proc1   |   Proc2 | 
 | 1    |    A     |   p      |   e     | 
 | 2    |    B     |   q      |   f     |
 | 3    |    B     |   p      |   f     |
 | 3    |    B     |   q      |   h     |
 | 3    |    B     |   r      |   j     |
 | 3    |    C     |   t      |   k     |

Ici, Proc1 peut avoir un nombre quelconque de valeurs. ID, Code et Proc1 forment ensemble une clé unique pour cette table. Je souhaite pivoter/transposer cette table afin que chaque valeur unique de Proc1 devienne une nouvelle colonne et que la valeur correspondante de Proc2 soit la valeur de cette colonne pour la ligne correspondante. Pour résumer, j'essaie d'obtenir quelque chose comme:

 | ID   |   Code   |  p   |   q |  r  |   t |
 | 1    |    A     |   e  |     |     |     |
 | 2    |    B     |      |   f |     |     |
 | 3    |    B     |   f  |   h |  j  |     |
 | 3    |    C     |      |     |     |  k  |

Dans la nouvelle table transformée, l'ID et le code sont la seule clé primaire. D'après le billet que j'ai mentionné ci-dessus, je pourrais aller aussi loin en utilisant toDAmap UDAF. (Avertissement - ceci peut ne pas être un pas dans la bonne direction, mais juste mentionner ici, si c'est)

 | ID   |   Code   |  Map_Aggregation   | 
 | 1    |    A     |   {p:e}            |
 | 2    |    B     |   {q:f}            |
 | 3    |    B     |   {p:f, q:h, r:j } |  
 | 3    |    C     |   {t:k}            |

Mais je ne sais pas comment aller de cette étape au tableau pivot/transposé que je veux . Toute aide sur la façon de procéder sera géniale! Merci.

17
Sunny

Voici la solution que j'ai finalement utilisée:

add jar brickhouse-0.7.0-SNAPSHOT.jar;
CREATE TEMPORARY FUNCTION collect AS 'brickhouse.udf.collect.CollectUDAF';

select 
    id, 
    code,
    group_map['p'] as p,
    group_map['q'] as q,
    group_map['r'] as r,
    group_map['t'] as t
    from ( select
        id, code,
        collect(proc1,proc2) as group_map 
        from test_sample 
        group by id, code
    ) gm;

Le fichier UDF to_map a été utilisé à partir du référentiel brickhouse: https://github.com/klout/brickhouse

5
Sunny

Voici l'approche que j'ai utilisée pour résoudre ce problème en utilisant la fonction UDF interne de Hive, "map":

select
    b.id,
    b.code,
    concat_ws('',b.p) as p,
    concat_ws('',b.q) as q,
    concat_ws('',b.r) as r,
    concat_ws('',b.t) as t
from 
    (
        select id, code,
        collect_list(a.group_map['p']) as p,
        collect_list(a.group_map['q']) as q,
        collect_list(a.group_map['r']) as r,
        collect_list(a.group_map['t']) as t
        from (
            select
              id,
              code,
              map(proc1,proc2) as group_map 
            from 
              test_sample
        ) a
        group by
            a.id,
            a.code
    ) b;

"concat_ws" et "map" sont Hive udf et "collect_list" est un Hive udaf.

12
Shakti Garg

Encore une autre solution.

Pivot en utilisant Hivemallto_map.

SELECT
  uid,
  kv['c1'] AS c1,
  kv['c2'] AS c2,
  kv['c3'] AS c3
FROM (
  SELECT uid, to_map(key, value) kv
  FROM vtable
  GROUP BY uid
) t

uid c1 c2 c3 101 11 12 13 102 21 22 23

Unpivot

SELECT t1.uid, t2.key, t2.value
FROM htable t1
LATERAL VIEW explode (map(
  'c1', c1,
  'c2', c2,
  'c3', c3
)) t2 as key, value

uid key value 101 c1 11 101 c2 12 101 c3 13 102 c1 21 102 c2 22 102 c3 23

4
myui

Je n'ai pas écrit ce code, mais je pense que vous pouvez utiliser certaines des fonctions définies par l'utilisateur fournies par klouts brickhouse: https://github.com/klout/brickhouse

Spécifiquement, vous pouvez faire quelque chose comme utiliser leur collection comme mentionné ici: http://brickhouseconfessions.wordpress.com/2013/03/05/use-collect-to-avoid-the-self-join/

et ensuite exploser les tableaux (ils seront de longueur différente) en utilisant les méthodes détaillées dans ce post http://brickhouseconfessions.wordpress.com/2013/03/07/exploding-multiple-arrays-at-the-same- time-with-numeric_ra

1
user2726995

Vous pouvez utiliser les déclarations de cas et l'aide de collect_set pour y parvenir. Vous pouvez vérifier cela. Vous pouvez vérifier la réponse détaillée sur - http://www.analyticshut.com/big-data/Hive/pivot-rows-to-columns-in-Hive/

Voici la requête pour référence,

SELECT resource_id,
CASE WHEN COLLECT_SET(quarter_1)[0] IS NULL THEN 0 ELSE COLLECT_SET(quarter_1)[0] END AS quarter_1_spends,
CASE WHEN COLLECT_SET(quarter_2)[0] IS NULL THEN 0 ELSE COLLECT_SET(quarter_2)[0] END AS quarter_2_spends,
CASE WHEN COLLECT_SET(quarter_3)[0] IS NULL THEN 0 ELSE COLLECT_SET(quarter_3)[0] END AS quarter_3_spends,
CASE WHEN COLLECT_SET(quarter_4)[0] IS NULL THEN 0 ELSE COLLECT_SET(quarter_4)[0] END AS quarter_4_spends
FROM (
SELECT resource_id,
CASE WHEN quarter='Q1' THEN amount END AS quarter_1,
CASE WHEN quarter='Q2' THEN amount END AS quarter_2,
CASE WHEN quarter='Q3' THEN amount END AS quarter_3,
CASE WHEN quarter='Q4' THEN amount END AS quarter_4
FROM billing_info)tbl1
GROUP BY resource_id;
0
Mahesh Mogal

Ci-dessous est aussi un moyen pour Pivot

SELECT TM1_Code, Product, Size, State_code, Description
  , Promo_date
  , Price
FROM (
SELECT TM1_Code, Product, Size, State_code, Description
   , MAP('FY2018Jan', FY2018Jan, 'FY2018Feb', FY2018Feb, 'FY2018Mar', FY2018Mar, 'FY2018Apr', FY2018Apr
        ,'FY2018May', FY2018May, 'FY2018Jun', FY2018Jun, 'FY2018Jul', FY2018Jul, 'FY2018Aug', FY2018Aug
        ,'FY2018Sep', FY2018Sep, 'FY2018Oct', FY2018Oct, 'FY2018Nov', FY2018Nov, 'FY2018Dec', FY2018Dec) AS tmp_column
FROM CS_ME_Spirits_30012018) TmpTbl
LATERAL VIEW EXPLODE(tmp_column) exptbl AS Promo_date, Price;
0
Anjib Rajkhowa

Pour Unpivot, nous pouvons simplement utiliser la logique ci-dessous.

SELECT Cost.Code, Cost.Product, Cost.Size
, Cost.State_code, Cost.Promo_date, Cost.Cost, Sales.Price
FROM
(Select Code, Product, Size, State_code, Promo_date, Price as Cost
FROM Product
Where Description = 'Cost') Cost
JOIN
(Select Code, Product, Size, State_code, Promo_date, Price as Price
FROM Product
Where Description = 'Sales') Sales
on (Cost.Code = Sales.Code
and Cost.Promo_date = Sales.Promo_date);
0
Anjib Rajkhowa

En cas de valeur numérique, vous pouvez utiliser la requête Hive ci-dessous:

Échantillon de données

ID  cust_freq   Var1    Var2    frequency
220444  1   16443   87128   72.10140547
312554  6   984 7339    0.342452643
220444  3   6201    87128   9.258396518
220444  6   47779   87128   2.831972441
312554  1   6055    7339    82.15209213
312554  3   12868   7339    4.478333954
220444  2   6705    87128   15.80822558
312554  2   37432   7339    13.02712127

select id, sum(a.group_map[1]) as One, sum(a.group_map[2]) as Two, sum(a.group_map[3]) as Three, sum(a.group_map[6]) as Six from
( select id, 
 map(cust_freq,frequency) as group_map 
 from table
 ) a group by a.id having id in 
( '220444',
'312554');

ID  one two three   six
220444  72.10140547 15.80822558 9.258396518 2.831972441
312554  82.15209213 13.02712127 4.478333954 0.342452643

In above example I have't used any custom udf. It is only using in-built Hive functions.
Note :For string value in key write the vale as sum(a.group_map['1']) as One.
0
Suman