2015-08-07 28 views
6

Attualmente, per classificare percentile una colonna nell'alveare, sto usando qualcosa come la seguente. Sto cercando di classificare gli elementi in una colonna in base a quale percentile essi rientrano, assegnando un valore da 0 a 1 a ciascun elemento. Il codice seguente assegna un valore compreso tra 0 e 9, in sostanza dicendo che un articolo con uno char_percentile_rank di 0 si trova nel 10% inferiore degli articoli e un valore pari a 9 è nel 10% superiore degli articoli. C'è un modo migliore per farlo?Hive: esiste un modo migliore per classificare una colonna?

select item 
    , characteristic 
    , case when characteristic <= char_perc[0] then 0 
     when characteristic <= char_perc[1] then 1 
     when characteristic <= char_perc[2] then 2 
     when characteristic <= char_perc[3] then 3 
     when characteristic <= char_perc[4] then 4 
     when characteristic <= char_perc[5] then 5 
     when characteristic <= char_perc[6] then 6 
     when characteristic <= char_perc[7] then 7 
     when characteristic <= char_perc[8] then 8 
     else 9 
     end as char_percentile_rank 
from (
    select split(item_id,'-')[0] as item 
     , split(item_id,'-')[1] as characteristic 
     , char_perc 
    from (
     select collect_set(concat_ws('-',item,characteristic)) as item_set 
      , PERCENTILE(BIGINT(characteristic),array(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9)) as char_perc 
     from(
      select item 
       , sum(characteristic) as characteristic 
      from table 
      group by item 
     ) t1 
    ) t2 
    lateral view explode(item_set) explodetable as item_id 
) t3 

Nota: ho dovuto fare il collect_set al fine di evitare un self join, come la funzione percentile esegue implicitamente una group by.

Ho notato che la funzione percentile è orribilmente lenta (almeno in questo utilizzo). Forse sarebbe meglio calcolare manualmente il percentile?

risposta

4

provare a rimuovere una delle vostre tabelle derivate

select item 
    , characteristic 
    , case when characteristic <= char_perc[0] then 0 
     when characteristic <= char_perc[1] then 1 
     when characteristic <= char_perc[2] then 2 
     when characteristic <= char_perc[3] then 3 
     when characteristic <= char_perc[4] then 4 
     when characteristic <= char_perc[5] then 5 
     when characteristic <= char_perc[6] then 6 
     when characteristic <= char_perc[7] then 7 
     when characteristic <= char_perc[8] then 8 
     else 9 
     end as char_percentile_rank 
from (
    select item, characteristic, 
     , PERCENTILE(BIGINT(characteristic),array(0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9)) over() as char_perc 
    from (
     select item 
     , sum(characteristic) as characteristic    
     from table 
     group by item    
    ) t1 
) t2 
+0

La funzione percentile ha bisogno di avere un gruppo - è per questo che ho fatto la collect_set apparentemente inutili (concat_ws (...)) - in modo da renderlo uno gruppo. Se invece raggruppo per articolo e caratteristica, allora percentili per articolo e caratteristica, che non voglio. Qualche idea su come evitarlo? –

+1

L'ho capito quasi subito dopo aver dormito su di esso e tornare ad esso. Basta aggiungere() sul percentile. Quindi la riga dovrebbe contenere: PERCENTILE (BIGINT (caratteristica), array (0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7, 0.8, 0.9)) over() come char_perc. Ma sembra che sia la mia query originale che quella nuova abbiano prestazioni molto simili. –

+0

@CharlieHaley è possibile fare riferimento a 'PERCENTILE (BIGINT ...) [i]' dove 'i = 0-8'? In tal caso, è possibile spostare l'istruzione case e rimuovere 1 tabella derivata – FuzzyTree