2017-02-22 1 views
2

j'ai les tableaux ci-dessous la première (Range) comprend plage de valeurs et de colonnes supplémentaires:moyen efficace de joindre des tables de plage à l'aide impala

row | From | To  | Country .... 
-----|--------|---------|--------- 
1 | 1200 | 1500 | 
2 | 2200 | 2700 | 
3 | 1700 | 1900 | 
4 | 2100 | 2150 | 
... 

Le From et To sont bigint et sont exclusifs. La table Range inclut des enregistrements 1,8M. tableau supplémentaire (Values) contient des enregistrements de 2,7 millions et ressemble à:

row  | Value | More columns.... 
--------|--------|---------------- 
    1 | 1777 |  
    2 | 2122 |  
    3 | 1832 |  
    4 | 1340 |  
    ... 

Je voudrais créer une table comme suit:

row  | Value | From | To | More columns.... 
--------|--------|--------|-------|--- 
    1 | 1777 | 1700 | 1900 | 
    2 | 2122 | 2100 | 2150 | 
    3 | 1832 | 1700 | 1900 | 
    4 | 1340 | 1200 | 1500 | 
    ... 

J'utilisé BETWEEN pour la tâche ci-dessus, mais la requête ne se termine:

VALUES.VALUE between RANGE.FROM and RANGE.TO 

Y a-t-il un changement que je dois faire dans les partitions de table ou dans Impala?

+1

est-il une partie de "utiliser autant de mots clés que possible pour les tables définition de" défi? –

Répondre

2

L'idée principale de la solution suivante est de remplacer une jointure theta (jointure non-equi) par une jointure equi qui conduira à une bonne distribution + algorithme de jointure local efficace.

La plage (-infinity, infinity) est divisée en section de n length.
Chaque plage de la table de plages est associée aux sections qu'elle croise.

par exemple. étant donné n = 1000, la gamme [1652,3701] sera associée aux sections [1000,2000), [2000,3000) et [3000,4000) (et auront 3 fiches, une pour chaque section)

   1652    3701 
       |     | 
       ------------------- 

------------------------------------------------------- 
|  |  |  |  |  |     
0  1000  2000  3000  4000  5000 

De la même manière, une valeur de la table de valeurs est en cours associé à la gamme qui le contient, par exemple 2093 sera associé à la plage [2000,3000).

La jointure entre les deux tables va se faire sur la valeur qui représente la section, par ex. [1652,3701] et 2093 vont se joindre à la section [2000,3000)


create table val_range (id int,from_val bigint,to_val bigint); 

insert into val_range values 
    (1,1200,1500) 
    ,(2,2200,2700) 
    ,(3,1700,1900) 
    ,(4,2100,2150) 
; 

create table val (id int,val bigint); 

insert into val values 
    (1,1777)  
    ,(2,2122)  
    ,(3,1832)  
    ,(4,1340) 
; 

set n=1000; 

select  v.id 
      ,v.val 
      ,r.from_val 
      ,r.to_val 

from  (select r.* 
        ,floor(from_val/${hiveconf:n}) + pe.i as match_val 

      from val_range r 
        lateral view posexplode 
            (
             split 
             (
              space 
              (
               cast 
               (
                floor(to_val/${hiveconf:n}) 
                - floor(from_val/${hiveconf:n}) 

                as int 
               ) 
              ) 
              ,' ' 
             ) 
            ) pe as i,x 
      ) r 

      join val v 

      on  floor(v.val/${hiveconf:n}) = 
        r.match_val 

where  v.val between r.from_val and r.to_val 

order by v.id   
; 

+------+-------+------------+----------+ 
| v.id | v.val | r.from_val | r.to_val | 
+------+-------+------------+----------+ 
| 1 | 1777 |  1700 |  1900 | 
| 2 | 2122 |  2100 |  2150 | 
| 3 | 1832 |  1700 |  1900 | 
| 4 | 1340 |  1200 |  1500 | 
+------+-------+------------+----------+ 
+0

Merci Dudu! Pouvez-vous s'il vous plaît ajouter une petite explication à votre excellente solution? – Avi

+0

Je le ferai, mais vous devriez savoir que c'est une solution pour Hive –

+0

Merci, je l'ai vu. Je peux travailler avec Hive ou Impala. Impala est préférable, mais si cela fonctionne dans Hive seulement, je l'utiliserai dans Hive. – Avi