Otimize o desempenho dos DataFrames do BigQuery

Os DataFrames do BigQuery ajudam a analisar e transformar dados no BigQuery usando uma API compatível com o pandas. Para tornar o processamento de dados mais rápido e rentável, pode usar várias técnicas para melhorar o desempenho.

Este documento descreve as seguintes formas de otimizar o desempenho:

Use o modo de ordenação parcial

O BigQuery DataFrames tem uma funcionalidade de modo de ordenação, que aplica uma ordem de linhas específica para operações como funções de janela e junções. Pode especificar o modo de ordenação definindo a propriedade ordering_mode como strict (conhecido como modo de ordenação rigoroso, que é o predefinido) ou partial (conhecido como modo de ordenação parcial). A utilização da definição partial pode tornar as suas consultas mais eficientes.

O modo de ordenação parcial é diferente do modo de ordenação rigoroso. O modo de ordenação rigorosa organiza todas as linhas numa ordem específica. Esta ordenação total faz com que os DataFrames do BigQuery funcionem melhor com o pandas, o que lhe permite aceder às linhas pela respetiva ordem através da propriedade DataFrame.iloc. No entanto, a ordenação total e o respetivo índice sequencial predefinido impedem que os filtros em colunas ou linhas reduzam a quantidade de dados analisados. Esta prevenção ocorre, a menos que aplique esses filtros como parâmetros às funções read_gbq e read_gbq_table. Para ordenar todas as linhas no DataFrame, os DataFrames do BigQuery criam um hash de todas as linhas. Esta operação pode provocar uma análise completa de dados que ignora os filtros de linhas e colunas.

O modo de ordenação parcial impede que os DataFrames do BigQuery criem uma ordem total para todas as linhas e desativa as funcionalidades que precisam de uma ordem total, como a propriedade DataFrame.iloc. O modo de ordenação parcial também define a classe DefaultIndexKind para um índice nulo, em vez de para um índice sequencial.

Quando filtra um objeto DataFrame usando o modo de ordenação parcial, os DataFrames do BigQuery não calculam que linhas estão em falta no índice sequencial. O modo de ordenação parcial também não combina automaticamente os dados com base no índice. Estas abordagens podem aumentar a eficiência das suas consultas. No entanto, quer use o modo de ordenação rigoroso predefinido ou o modo de ordenação parcial, a API BigQuery DataFrames funciona como a API pandas familiar.

Com os modos de ordenação parcial e rigorosa, paga pelos recursos do BigQuery que usa. No entanto, a utilização do modo de ordenação parcial pode reduzir os custos quando trabalha com tabelas grandes com clusters e partições. Esta redução de custos ocorre porque os filtros de linhas nas colunas de cluster e de partição reduzem a quantidade de dados processados.

Ative o modo de ordenação parcial

Para usar a ordenação parcial, defina a propriedade ordering_mode como partial antes de realizar qualquer outra operação com DataFrames do BigQuery, conforme mostrado no seguinte exemplo de código:

import bigframes.pandas as bpd

bpd.options.bigquery.ordering_mode = "partial"

O modo de ordenação parcial impede as junções implícitas de objetos BigQuery DataFrames não relacionados porque não tem um índice sequencial. Em alternativa, tem de chamar explicitamente o método DataFrame.merge para juntar dois objetos DataFrame do BigQuery que derivam de diferentes expressões de tabelas.

As funcionalidades Series.unique() e Series.drop_duplicates() não funcionam com o modo de ordenação parcial. Em alternativa, use o método groupby para encontrar valores únicos, conforme mostrado no exemplo seguinte:

# Avoid order dependency by using groupby instead of drop_duplicates.
unique_col = df.groupby(["column"], as_index=False).size().drop(columns="size")

Com o modo de ordenação parcial, o resultado das funções DataFrame.head(n) e Series.head(n) pode não ser o mesmo sempre que as executa. Para transferir uma amostra aleatória pequena dos dados, use os métodos DataFrame.peek() ou Series.peek().

Para um tutorial detalhado no qual usa a propriedade ordering_mode = "partial", consulte Analisar transferências de pacotes do PyPI com DataFrames do BigQuery.

Resolução de problemas

Uma vez que, por vezes, os DataFrames do BigQuery no modo de ordenação parcial não têm uma ordenação ou um índice, pode deparar-se com os seguintes problemas quando usa alguns métodos compatíveis com o pandas.

Erro de encomenda necessária

Algumas funcionalidades, como as funções DataFrame.head() e DataFrame.iloc, precisam de uma ordem. Para ver uma lista de funcionalidades que requerem ordenação, consulte a coluna Requires ordering em APIs pandas suportadas.

Quando um objeto não tem ordenação, a operação falha com uma mensagem OrderRequiredError semelhante à seguinte: OrderRequiredError: Op iloc requires an ordering. Use .sort_values or .sort_index to provide an ordering.

Conforme indicado na mensagem de erro, pode fornecer uma ordenação através do método DataFrame.sort_values() para ordenar por uma ou mais colunas. Outros métodos, como DataFrame.groupby()>, fornecem implicitamente uma ordenação total com base nas chaves de agrupamento.

Se a ordenação não for uma ordenação total completamente estável para todas as linhas, as operações posteriores podem apresentar uma mensagem AmbiguousWindowWarning semelhante à seguinte: AmbiguousWindowWarning: Window ordering may be ambiguous, this can cause unstable results.

Se o seu trabalho puder processar resultados que nem sempre são os mesmos ou se puder verificar manualmente se a ordenação é uma ordenação total, pode filtrar a mensagem AmbiguousWindowWarning da seguinte forma:

import warnings

import bigframes.exceptions

warnings.simplefilter(
    "ignore", category=bigframes.exceptions.AmbiguousWindowWarning
)

Erro de índice nulo

Algumas propriedades, como DataFrame.unstack() e Series.interpolate(), precisam de um índice. Para ver uma lista de funcionalidades que requerem um índice, consulte a coluna Requer índice em APIs pandas suportadas.

Quando usa uma operação que requer um índice com o modo de ordenação parcial, a operação gera uma mensagem NullIndexError semelhante à seguinte: NullIndexError: DataFrame cannot perform interpolate as it has no index. Set an index using set_index.

Conforme indicado na mensagem de erro, pode fornecer um índice através do método DataFrame.set_index() para ordenar por uma ou mais colunas. Outros métodos, como DataFrame.groupby(), fornecem implicitamente um índice com base nas chaves de agrupamento, a menos que o parâmetro as_index=False esteja definido.

Coloque os resultados em cache após operações dispendiosas

O BigQuery DataFrames armazena operações localmente e adia a execução de consultas até serem cumpridas determinadas condições. Isto pode fazer com que as mesmas operações sejam executadas várias vezes em diferentes consultas.

Para evitar repetir operações dispendiosas, guarde os resultados intermédios com o método cache(), conforme mostrado no exemplo seguinte:

# Assume you have 3 large dataframes "users", "group" and "transactions"

# Expensive join operations
final_df = users.join(groups).join(transactions)
final_df.cache()
# Subsequent derived results will reuse the cached join
print(final_df.peek())
print(len(final_df[final_df["completed"]]))
print(final_df.groupby("group_id")["amount"].mean().peek(30))

Este método cria uma tabela temporária do BigQuery para armazenar os seus resultados. É-lhe cobrado o armazenamento desta tabela temporária no BigQuery.

Pré-visualize os seus dados com o método peek()

O BigQuery DataFrames oferece dois métodos de API para pré-visualizar dados:

  • peek(n) devolve n linhas de dados, onde n é o número de linhas.
  • head(n) devolve as primeiras n linhas de dados, consoante o contexto, em que n é o número de linhas.

Use o método head() apenas quando a ordem dos dados for importante, por exemplo, quando quiser os cinco maiores valores numa coluna. Noutros casos, use o método peek() para uma obtenção de dados mais eficiente, conforme mostrado no seguinte exemplo de código:

import bigframes.pandas as bpd

# Read the "Penguins" table into a dataframe
df = bpd.read_gbq("bigquery-public-data.ml_datasets.penguins")

# Preview 3 random rows
df.peek(3)

Também pode usar o método peek() para transferir uma pequena amostra aleatória de dados enquanto usa o modo de ordenação parcial.

Adie a obtenção de dados do repr()

Pode chamar o método repr() em DataFrames do BigQuery com blocos de notas ou o depurador do IDE. Esta chamada aciona a chamada head() que obtém os dados reais. Esta obtenção pode tornar o processo de programação e depuração iterativo mais lento, bem como incorrer em custos.

Para impedir que o método repr() obtenha dados, defina o atributo repr_mode como "deferred", conforme mostrado no exemplo seguinte:

import bigframes.pandas as bpd

bpd.options.display.repr_mode = "deferred"

No modo diferido, só pode pré-visualizar os seus dados com chamadas peek() e head() explícitas.

O que se segue?