BigQuery Ottenere "risposta troppo grande" quando si utilizza la funzione Ntile con il set di dati di esempio pubblico su Wikipedia
-
21-12-2019 - |
Domanda
Fondamentalmente sto testando la funzione Ntile per dividere il conteggio totale della parola della tabella di Wikipedia in 100 secchi.Sto ricevendo la "risposta troppo grande errore" utilizzando la console web.Così ho provato lo strumento BQ CLI con entrambe le opzioni --Destination_table e --allow_large_results senza fortuna.
Ecco la query:
SELECT id, num_characters, NTILE(100) OVER (ORDER BY num_characters) percentile
FROM [publicdata:samples.wikipedia]
.
Come posso recuperare correttamente i risultati?
Soluzione
Segreto di BigQuery per prestazioni sorprendenti: distribuzione del carico di lavoro. Ogni volta che si rilascia una query, un grande numero di computer inizia a leggere tutti i dati in parallelo, elaborandolo e passandolo ad altri computer nella catena.
Tuttavia, ci sono operazioni molto difficili da parallelizzare - tipicamente funzioni che corrono dopo che tutto il resto è stato fatto. Quelle operazioni non vengono distribuite, ma vincolate a tutti i dati che si adattano a un computer. Ordina per e oltre () sono alcune di queste funzioni - come alla fine una singola macchina deve ordinare l'intero risultato impostato.
La buona notizia è che abbiamo alternative. Quantili è in grado di passare attraverso tutti i dati, mentre il calcolo dei risultati approssimativi:
SELECT QUANTILES(num_characters, 100)
FROM [publicdata:samples.wikipedia]
Query complete (1.7s elapsed, 2.34 GB processed)
.
o eseguire lo stesso sopra (ordine per) rispetto alla domanda originale, ma su un campione dei dati:
SELECT id, num_characters, NTILE(100) OVER (ORDER BY num_characters) percentile
FROM [publicdata:samples.wikipedia]
WHERE id % 10 = 0;
Query complete (258.7s elapsed, 4.68 GB processed)
.
Vedrai che entrambi producono risultati simili (uno per approssimazione, l'altro per campionamento) - ma uno è molto più veloce.
Altri suggerimenti
È possibile utilizzare una funzione UDF per ottenere ntili di tutti i dati senza saturazione della memoria e senza dover campionare, anche se potrebbe essere meno performante.
Ho impiegato questo metodo per calcolare il percentile un valore caduto all'interno, proprio come la funzione generatagODicetagCode integrata.La funzione incorporata esaurirebbe la memoria durante l'operazione NTILE
, se applicata a un numero massiccio di righe.
La funzione definita dall'utente prende un array Quantili (in questo caso generato utilizzando ORDER BY
) e un valore e restituisce quale ntile il valore è in.
-- Define UDF
CREATE TEMPORARY FUNCTION getNTile(quantiles ARRAY<INT64>, val INT64)
RETURNS INT64
LANGUAGE js AS """
var ntile = 0;
while(parseInt(val, 10) > parseInt(quantiles[ntile], 10) && ntile < quantiles.length) {
ntile+=1;
}
return ntile;
""";
-- Calculate an array of approximate quantiles, in this case percentiles
WITH master AS (
SELECT
id,
num_characters
FROM
`publicdata.samples.wikipedia`
),
quantiles AS (
SELECT
APPROX_QUANTILES(num_characters, 99) AS approx
FROM
master
)
-- Use UDF with approx quantile array to find nTile
SELECT
id,
num_characters,
getNTile(quantiles.approx, num_characters) AS percentile
FROM
master,
quantiles
.
Il codice JS nell'UDF sta costringendo i valori agli interi con APPROX_QUANTILES
.Potrebbe essere un bug bigquery, ma per qualche motivo i valori stavano arrivando come stringhe altrimenti, stranamente.
Spero che questo aiuti qualcuno.