2011-12-13 22 views
10

Sto avendo alcuni problemi con regexp_extract:alveare regexp_extract stranezza

sto eseguendo la query su un file delimitato da tabulazioni, la colonna sto controllando ha stringhe che assomigliano a questo:

abc.def.ghi 

Ora, se faccio: lavoro

select distinct regexp_extract(name, '[^.]+', 0) from dummy; 

MR viene eseguito, funziona, ed ottengo "abc" dall'indice 0.

Ma n ow, se voglio ottenere "def" dall'indice 1:

select distinct regexp_extract(name, '[^.]+', 1) from dummy; 

Hive fallisce con:

2011-12-13 23:17:08,132 Stage-1 map = 0%, reduce = 0% 
2011-12-13 23:17:28,265 Stage-1 map = 100%, reduce = 100% 
Ended Job = job_201112071152_0071 with errors 
FAILED: Execution Error, return code 2 from org.apache.hadoop.hive.ql.exec.MapRedTask 

file di registro dice:

java.lang.RuntimeException: org.apache.hadoop.hive.ql.metadata.HiveException: Hive Runtime Error while processing row 

sto facendo qualcosa di fondamentalmente sbagliato qui ?

Grazie, Mario

risposta

27

Dai documenti https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF sembra che regexp_extract() sia un'estrazione record/riga dei dati che si desidera estrarre.

Sembra funzionare su un primo trovato (quindi chiuso) rispetto al globale. Pertanto l'indice fa riferimento al gruppo di cattura.

0 = tutto il match
1 = gruppo di cattura 1
2 = gruppo di cattura 2, ecc ...

parafrasato dal manuale:

regexp_extract('foothebar', 'foo(.*?)(bar)', 2) 
           ^^ 
       groups    1 2 

This returns 'bar'. 

Quindi, nel tuo caso, per ottenere il testo dopo il punto, qualcosa di simile potrebbe funzionare:
regexp_extract(name, '\.([^.]+)', 1)
o questo
regexp_extract(name, '[.]([^.]+)', 1)

modificare

ho preso nuovamente interessato a questo, solo un Cordiali saluti, ci potrebbe essere una scorciatoia/soluzione per voi.

Sembra che tu voglia un segmento particolare separato con un punto . carattere, che è quasi come diviso.
È più che probabile che il motore regex utilizzato sovrascriva un gruppo se è stato quantificato più di una volta.
Si può approfittare di questo con qualcosa di simile:

Restituisce il primo segmento: abc .def.ghi
regexp_extract(name, '^(?:([^.]+)\.?){1}', 1)

Restituisce il secondo segmento: abc. def .ghi
regexp_extract(name, '^(?:([^.]+)\.?){2}', 1)

Restituisce il terzo segmento: abc.def. ghi
regexp_extract(name, '^(?:([^.]+)\.?){3}', 1)

L'indice non cambia (perché l'indice referrs ancora a catturare gruppo 1), solo le espressioni regolari cambiamenti ripetizione.

Alcune note:

  • Questa espressione regolare ^(?:([^.]+)\.?){n} ha problemi però.
    Richiede che ci sia qualcosa tra i punti nel segmento o che la regex non corrisponda a ....

  • Potrebbe essere questo ^(?:([^.]*)\.?){n} ma corrisponderà anche se non è inferiore a n-1, punti
    inclusa la stringa vuota. Questo probabilmente non è desiderabile.

C'è un modo per farlo dove non richiede il testo tra i punti, ma richiede comunque almeno n-1 punti.
Questo utilizza un'asserzione lookahead e il buffer di cattura 2 come flag.

^(?:(?!\2)([^.]*)(?:\.|$())){2}, tutto il resto è lo stesso.

Quindi, se utilizza regex in stile java, dovrebbe funzionare.
regexp_extract(name, '^(?:(?!\2)([^.]*)(?:\.|$())){2}', 1) cambia {2} in qualunque 'segmento' è necessario (questo è il segmento 2).

e restituisce ancora il buffer di acquisizione 1 dopo l'iterazione di {N}.

Qui è suddiviso

^    # Begining of string 
(?:    # Grouping 
    (?!\2)   # Assertion: Capture buffer 2 is UNDEFINED 
    ([^.]*)   # Capture buffer 1, optional non-dot chars, many times 
    (?:    # Grouping 
     \.    # Dot character 
     |     # or, 
     $()    # End of string, set capture buffer 2 DEFINED (prevents recursion when end of string) 
    )     # End grouping 
){3}   # End grouping, repeat group exactly 3 (or N) times (overwrites capture buffer 1 each time) 

Se non lo fa affermazioni, allora questo non funzionerà!

+0

grazie, era così. tempo di presentare una richiesta di funzionalità con l'alveare :-) – Mario

+0

@ Mario - Il benvenuto. Aggiunta la possibile regex di soluzione alternativa per accorciare le cose come soluzione. – sln

+0

vorrei poterti votare una seconda volta – Mario

1

Credo che bisogna fare 'gruppi' no?

select distinct regexp_extract(name, '([^.]+)', 1) from dummy; 

(non testato)

penso si comporta come la libreria Java e questo dovrebbe funzionare, fatemelo sapere però.

+0

ha, strano, il lavoro MR viene eseguito con quello, ma restituisce ancora il contenuto dell'indice 0! – Mario

+0

e ho appena provato per calci con indice 2, e poi fallisce con 2011-12-13 23: 33: 41,377 Mappa fase 1 = 0%, ridurre = 0% 2011-12-13 23:34: 01.465 Mappa fase 1 = 100%, riduzione = 100% Lavoro terminato = job_201112071152_0074 con errori NON RIUSCITO: errore di esecuzione, codice di ritorno 2 da org.apache.hadoop.hive.ql.exec.MapRedTask di nuovo .... strano strano strano .... – Mario