2016-03-11 6 views
9

Ho difficoltà ad accedere a un campo nidificato ripetuto mantenendo la struttura di righe originale in BigQuery.join bigquery su nidificato ripetuto

Per il mio esempio, chiamerò i due tavoli uniti A e B.

Records in tabella A qualcosa di simile a:

{ 
    "url":"some url", 
    "repeated_nested": [ 
    {"key":"some key","property":"some property"} 
    ] 
} 

e registra nella tabella B aspetto qualcosa di simile:

{ 
    "key":"some key", 
    "property2": "another property" 
} 

Sto sperando di trovare un modo per unire questi dati insieme per generare una riga che assomiglia a:

{ 
    "url":"some url", 
    "repeated_nested": [ 
    { 
     "key":"some key", 
     "property":"some property", 
     "property2":"another property" 
    } 
    ] 
} 

La prima domanda che ho provato era:

SELECT 
    url, repeated_nested.key, repeated_nested.property, repeated_nested.property2 
FROM A 
    AS lefttable 
LEFT OUTER JOIN B 
    AS righttable 
    ON lefttable.key=righttable.key 

Questo non funziona perché BQ non può partecipare su campi nidificati ripetuti. Non esiste un identificativo univoco per ogni riga. Se dovessi fare uno FLATTEN su repeated_nested allora non sono sicuro di come riportare correttamente la riga originale.

I dati sono tali che uno url avrà sempre lo stesso campo repeated_nested con esso. A causa di questo, sono stato in grado di fare una soluzione utilizzando un UDF a sorta di rimboccarsi questo oggetto nidificato ripetuto in una stringa JSON e poi srotolarlo di nuovo:

SELECT url, repeated_nested.key, repeated_nested.property, repeated_nested.property2 

FROM 
JS(
    (
    SELECT basetable.url as url, repeated_nested 
    FROM A as basetable 

    LEFT JOIN (
     SELECT url, CONCAT("[", GROUP_CONCAT_UNQUOTED(repeated_nested_json, ","), "]") as repeated_nested 
     FROM 
     (
     SELECT 
      url, 
      CONCAT(
       '{"key": "', repeated_nested.key, '",', 
       ' "property": "', repeated_nested.property, '",', 
       ' "property2": "', mapping_table.property2, '"', 
       '}' 
      ) 
     ) as repeated_nested_json 
     FROM (
      SELECT 
      url, repeated_nested.key, repeated_nested.property 
      FROM A 
      GROUP BY url, repeated_nested.key, repeated_nested.property 
     ) as urltable 

     LEFT OUTER JOIN [SDF.alchemy_to_ric] 
      AS mapping_table 
      ON urltable.repeated_nested.key=mapping_table.key 
    ) 
     GROUP BY url 
    ) as companytable 
    ON basetable.url = urltable.url 
), 

    // input columns: 
    url, repeated_nested_json, 

    // output schema: 
    "[{'name': 'url', 'type': 'string'}, 
    {'name': 'repeated_nested_json', 'type': 'RECORD', 'mode':'REPEATED', 'fields': 
    [ { 'name': 'key', 'type':'string' }, 
     { 'name': 'property', 'type':'string' }, 
     { 'name': 'property2', 'type':'string' }] 
    }]", 

    // UDF: 
    "function(row, emit) { 
    parsed_repeated_nested = []; 
    try { 
     if (row.repeated_nested_json != null) { 
      parsed_repeated_nested = JSON.parse(row.repeated_nested_json); 
     } 
    } catch (ex) { } 

    emit({ 
     url: row.url, 
     repeated_nested: parsed_repeated_nested 
    }); 
    }" 
) 

Questa soluzione funziona bene per tavolini. Ma le tabelle della vita reale con cui sto lavorando hanno molte più colonne che nel mio esempio sopra. Quando ci sono altri campi oltre a url e repeated_nested_json, tutti devono passare attraverso l'UDF. Quando lavoro con tabelle che si aggirano intorno alla gamma da 50 GB tutto va bene. Ma quando applico l'UDF e eseguo query su tabelle che sono 500-1000 GB, ottengo un errore interno del server da BQ.

Alla fine ho solo bisogno di tutti i dati in formato JSON delimitato da nuova riga in GCS. Come ultimo tentativo ho cercato di concatenare tutti i campi in una stringa JSON (così ho avuto solo 1 colonna) nella speranza che potessi esportarlo come CSV e avere ciò di cui ho bisogno. Tuttavia, il processo di esportazione è sfuggito alle virgolette doppie e aggiunge virgolette doppie attorno alla stringa JSON. Secondo i documenti BQ sui lavori (https://cloud.google.com/bigquery/docs/reference/v2/jobs) c'è una proprietà configuration.query.tableDefinitions.(key).csvOptions.quote che potrebbe aiutarmi. Ma non riesco a capire come farlo funzionare.

Qualcuno ha consigli su come hanno affrontato questo tipo di situazione?

+0

"Internal Server Error da BQ" - id lavoro si prega di modo che il team possa indagare –

+0

@FelipeHoffa sharethis.com:quixotic-spot-526:bquijob_39502947_1535e1c5f59 –

risposta

1

Non ho mai dovuto farlo, ma dovresti essere in grado di utilizzare flatten, quindi unire, quindi utilizzare nest per ottenere nuovamente i campi ripetuti.

I documenti affermano che BigQuery appiattisce sempre i risultati delle query, ma ciò sembra essere falso: è possibile scegliere di non avere risultati appiattiti se si imposta una tabella di destinazione. Dovresti quindi essere in grado di esportare quella tabella come JSON in Storage.

Vedere anche this answer per come ottenere nest per il funzionamento.

+1

Un dettaglio ingannevole: non c'è alcun modo pulito per usare 'NEST' per tornare un record ripetuto - puoi usare solo 'NEST' sui campi foglia per ottenere i singoli record ripetuti. Per ovviare a questo problema, è possibile considerare il smooshing del record in una stringa (come menzionato nella domanda), utilizzando 'NEST' per trasformarlo in un campo ripetuto e quindi utilizzare una UDF per decomprimere il record. –

+1

BTW, abbiamo presto miglioramenti al nostro dialetto SQL che renderà tutto molto più semplice. Segui https://code.google.com/p/google-bigquery/issues/detail?id=448 per ricevere una notifica. –

+0

Inoltre, 'NEST' deve essere usato con un' GROUP BY'. Nel mio caso, non sono stato in grado di creare un campo per utilizzare un 'GROUP BY' su. –