Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[infra] Adiciona ao cliente Python a funcionalidade de download direto (sem passar na memória) #123

Closed
wants to merge 14 commits into from

Conversation

aguiarandre
Copy link

Closes #119

Tentei criar esse pipeline de download à parte e opcional (através do argumento: bypass_memory, que por default é False - inclusive, não sei criar nomes, fiquem à vontade pra sugerir haha) já que ele introduz uma dificuldade em termos de autorização (o usuário precisa ter uma credencial com acesso de escrita à buckets, leitura ao bigquery e criação de jobs).

Basicamente, implementei a ideia de:
create temporary bucket ➡️ move table from bq to temp bucket ➡️ download blob from bucket ➡️ delete temporary bucket

Fiz todas estas funções como 'ocultas' ( _create_bucket, _move_table_to_bucket, _direct_download, etc) pra não poluir pro usuário final. Não consegui pensar numa forma mais elegante de permitir que o bucket não seja temporário a não ser que o usuário use estas funções internas (_create_bucket(...) ➡️ _move_table_to_bucket(...))

Pontos de melhoria:
Acredito que há alguns pontos a serem melhorados, mas que não implementei nessa versão:

  • por hora estou considerando apenas .csv mas acredito que outros formatos trariam vantagem significativa em performance (avro, por exemplo)
  • tratamento de exceção para explicar para o usuário o que fazer quando der erro (explicar quais autorizações ele precisa, etc)

Experimentos:

Fiz um pequeno experimento com uma base do bigquery-public-data. Usei duas bases diferentes pra não envolver problemas com cache (inclusive isso me deu ideia de outra melhoria, que seria permitir passar o job_config no read_sql), mas ambas as bases possuem cerca de ~500MB no BigQuery e ~200MB em csv.

import pandas as pd
import basedosdados as bd

%%time

bd.download(savepath='download_1.csv', 
            dataset_id='irs_990', 
            table_id='irs_990_2016', 
            project_id='bigquery-public-data', 
            bypass_memory=True)

# CPU times: user 5.24 s, sys: 3.09 s, total: 8.33 s
# Wall  time: 2min 42s

%%time

bd.download(savepath='download_1.csv', 
            dataset_id='irs_990', 
            table_id='irs_990_2016', 
            project_id='bigquery-public-data')

# CPU times: user 3min  10 s, sys: 7.49 s, total: 3min 18s
# Wall  time: 9min 57s

Além da vantagem de wall-time para estas bases um pouco maiores, é interessante ver que o tempo de processamento é quase nulo (já que o processo é puramente I/O).

Closes #68

Na questão de tornar o index=False por default, usei a seguinte estratégia para aceitar o index e ainda permitir o pandas_kwargs:

index_bool = pandas_kwargs.pop('index', False)
table.to_csv(savepath, index=index_bool, **pandas_kwargs)

Veja se faz sentido pra vocês fazer dessa forma, por favor?

Closes #122

Apenas adicionei o argumento project_id à função read_table() para permitir que o usuário utilize um projeto específico.

NOTA: Se tiverem alguma sugestão, por favor me avisem. Tentei fazer de maneira organizada mas não tenho experiência nessa questão de contribuição open-source e estou querendo me aprimorar. Fico à disposição para quaisquer dúvidas que não comentei por aqui!

@aguiarandre
Copy link
Author

Aliás, se eu fiz algo errado ou não segui algum padrão que estão seguindo, por favor me avisem também que corrijo!

@JoaoCarabetta
Copy link
Contributor

Muito obrigado pela contribuição!

Alguns comentários gerais.

Closes #119

Acho que o download sem passar pela memória deveria ser o padrão. A opção passando pela memória nem deveria existir, pois, complexifica a implementação e não traz nenhuma vantagem clara. O que você acha?

Dito isso, esse processo:

  1. também deve funcionar para chamadas do download com o parâmetro query.
  2. O parâmetro bypass_memory nem deveria existir.

Sobre o formato, acho que csv deveria ser o padrão por sua facilidade. Mas, acredito que o arquivo deveria ser comprimido para diminuir o tempo de I/O. Existem algumas opções de compressão. Idealmente, gostaríamos de um formato nativo para as maiorias dos sistemas operacionais.

Também, a sugestão de passar os parâmetros do job_config uma boa. Expandiria para todas as funcões download, read_sql e read_table. Assim, os usuários teriam mais controle sobre o processo.

Closes #68

Dado que não baixaremos mais os dados via pandas, não sei se é fácil tirar o index. Então, nem acho que deveríamos nos preocupar com isso.

Closes #122

Ótimo!

Credenciais

Estou trabalhando em outro PR #120 para mudar como o usuário vai configurar as credenciais. Estamos pensando em fazer a validação via browser. Mas, ainda não testamos. Portanto, toda a requisição para o Client() pode ser modificada.

No geral, o PR está muito bom. Ainda não temos um padrão de PR, mas isso é uma ótima ideia. Fique à vontade para sugerir um padrão.

Também, se você tiver pensando em contribuir mais para o projeto e participar das decisões de 'pra onde a gente vai', chega lá no grupo do Whatsapp que a gente marca uma conversa.

@aguiarandre
Copy link
Author

Obrigado João, pelos comentários.

Eu concordo que o download poderia ser sempre sem passar na memória. A única vantagem direta que vejo de trazer via pandas é que requer menos autenticação (não precisa da permissão de escrita e leitura do Cloud Storage). Mas acredito que isso se resolva através de um bd.read_table(...).to_csv(...).

Quanto à questão da compressão, já vi aqui como faz, vou testar e já incluo! Muito boa.

Pra fazer funcionar com o parâmetro query acho que preciso dar um pensada melhor pra ver o melhor jeito.

Mas com certeza, quero ajudar sim. Vou dar um toque no grupo! Valeu!

@JoaoCarabetta JoaoCarabetta changed the title Adiciona ao cliente Python a funcionalidade de download direto (sem passar na memória) [infra] Adiciona ao cliente Python a funcionalidade de download direto (sem passar na memória) Mar 14, 2021
@JoaoCarabetta JoaoCarabetta mentioned this pull request Nov 8, 2021
13 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
3 participants