hive regexp_extract weirdness

Sto riscontrando alcuni problemi con regexp_extract:

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

abc.def.ghi 

Ora, se lo faccio:

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

MR funziona, funziona, e ottengo “abc” dall’indice 0.

Ma ora, 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 

Il 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

Dai documenti https://cwiki.apache.org/confluence/display/Hive/LanguageManual+UDF sembra che regexp_extract () sia un’estrazione record / linea dei dati che desideri estrarre.

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

0 = l’intera partita
1 = gruppo di acquisizione 1
2 = Cattura gruppo 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 del genere potrebbe funzionare:
regexp_extract(name, '\.([^.]+)', 1)
o questo
regexp_extract(name, '[.]([^.]+)', 1)

modificare

Mi sono interessato a questo, solo un fyi, potrebbe esserci una scorciatoia / soluzione per te.

Sembra che tu desideri un particolare segmento separato da un punto . personaggio, che è quasi come diviso.
È più che probabile che il motore regex utilizzato sovrascriva un gruppo se è quantificato più di una volta.
Puoi approfittarne con qualcosa del genere:

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 (poiché l’indice fa ancora riferimento al gruppo 1), solo la ripetizione regex cambia.

Alcune note:

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

  • Potrebbe essere questo ^(?:([^.]*)\.?){n} ma questo corrisponderà anche se ci sono meno di n-1 punti,
    compresa 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.
Ciò utilizza un’asserzione lookahead e il buffer di cattura 2 come flag.

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

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

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

Qui è ripartito

 ^ # 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 fa asserzioni, allora questo non funzionerà!

Penso che devi fare “gruppi” no?

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

(non testato)

Penso che si comporti come la libreria java e questo dovrebbe funzionare, fammi sapere però.