我正在研究一个小的云函数python脚本,以重写来自存储的csv文件(跳过某些列)并将其发送到BigQuery。
我脚本的BigQuery部分如下:
def bq_import(request):
job_config.skip_leading_rows = 1
# The source format defaults to CSV, so the line below is optional.
job_config.source_format = bigquery.SourceFormat.CSV
uri = "gs://url.appspot.com/fil.csv"
load_job = bq_client.load_table_from_uri(
uri, dataset_ref.table('table'), job_config=job_config
) # API request
load_job.result() # Waits for table load to complete.
destination_table = bq_client.get_table(dataset_ref.table('table'))
我找到了此脚本,该脚本允许我跳过一些列来重写csv:
def remove_csv_columns(input_csv, output_csv, exclude_column_indices):
with open(input_csv) as file_in, open(output_csv, 'w') as file_out:
reader = csv.reader(file_in)
writer = csv.writer(file_out)
writer.writerows(
[col for idx, col in enumerate(row)
if idx not in exclude_column_indices]
for row in reader)
remove_csv_columns('in.csv', 'out.csv', (3, 4))
因此,我基本上需要使这两个脚本在我的云功能中一起工作。但是,我不确定如何处理remove_csv_columns
函数,尤其是output_csv
变量。我应该创建一个空的虚拟csv文件吗?还是数组或类似的东西?如何即时改写此csv文件?
我认为我的最终脚本应该像这样,但是缺少某些内容...
uri = "gs://url.appspot.com/fil.csv"
def remove_csv_columns(uri, output_csv, exclude_column_indices):
with open(input_csv) as file_in, open(output_csv, 'w') as file_out:
reader = csv.reader(file_in)
writer = csv.writer(file_out)
writer.writerows(
[col for idx, col in enumerate(row)
if idx not in exclude_column_indices]
for row in reader)
def bq_import(request):
job_config.skip_leading_rows = 1
# The source format defaults to CSV, so the line below is optional.
job_config.source_format = bigquery.SourceFormat.CSV
csv_file = remove_csv_columns('in.csv', 'out.csv', (3, 4))
load_job = bq_client.load_table_from_uri(
csv_file, dataset_ref.table('table'), job_config=job_config
) # API request
load_job.result() # Waits for table load to complete.
destination_table = bq_client.get_table(dataset_ref.table('table'))
基本上,我认为我需要通过remove_csv_columns
来在bq_import函数中定义我的cvs文件,但是我不确定该如何做。
顺便说一下,我正在学习python,但我不是开发人员专家。谢谢。
答案 0 :(得分:1)
您的代码有很多错误,我将在更正中尝试弄清楚
uri = "gs://url.appspot.com/fil.csv"
我不知道您的函数是如何触发的,但是通常要处理的文件包含在this for event from GCS之类的request
对象中。使用存储桶和名称动态构建您的uri
def remove_csv_columns(uri, output_csv, exclude_column_indices):
with open(input_csv) as file_in, open(output_csv, 'w') as file_out:
注意:您将uri
用作函数参数名称,并使用input_csv
以读取模式打开输入文件。这里的代码崩溃是因为input_csv
不存在!
这里还有另一句话。 uri
是函数参数名称,仅在函数内部和外部关系中知道,但调用方(填写此值)除外。它与您在uri = "gs://url.appspot.com/fil.csv"
reader = csv.reader(file_in)
writer = csv.writer(file_out)
writer.writerows(
[col for idx, col in enumerate(row)
if idx not in exclude_column_indices]
for row in reader)
def bq_import(request):
job_config.skip_leading_rows = 1
# The source format defaults to CSV, so the line below is optional.
job_config.source_format = bigquery.SourceFormat.CSV
csv_file = remove_csv_columns('in.csv', 'out.csv', (3, 4))
您的输入文件是静态的。阅读我关于动态uri
构建的评论。
看一下函数remove_csv_columns
:它什么也不返回,它只是在out.csv
中写一个新文件。因此,您的csv_file
在这里什么也不代表。另外,这个功能做什么?读取in.csv
文件并写入out.csv
文件(通过删除列)。您必须将文件传递给此功能
顺便说一句,您必须从Cloud Storage下载文件并将其存储在本地。在Cloud Function中,只有/tmp
是可写的。因此您的代码应该像这样
# create storage client
storage_client = storage.Client()
# get bucket with name
bucket = storage_client.get_bucket('<your bucket>')
# get bucket data as blob
blob = bucket.get_blob('<your full file name, path included')
# convert to string
data = blob.download_as_string()
# write the file
with open('/tmp/input.csv', 'w') as file_out:
file_out.write(data )
remove_csv_columns('/tmp/input.csv', '/tmp/out.csv', (3, 4))
继续您的代码
load_job = bq_client.load_table_from_uri(
csv_file, dataset_ref.table('table'), job_config=job_config
) # API request
函数load_table_from_uri
将文件从存在于Cloud Storage中的文件加载到BigQuery中。在这里,这不是您的目标,您想将本地创建的文件out.csv
加载到函数中。正确的电话是load_job = bq_client.load_table_from_file(open('/tmp/out.csv', 'rb'), job_config=job_config)
load_job.result() # Waits for table load to complete.
destination_table = bq_client.get_table(dataset_ref.table('table'))
然后,考虑清理/tmp
目录以释放内存,请注意Cloud Function超时,在requirements.txt
文件中导入正确的库(至少是Cloud Storage和BigQuery依赖项),然后最后拿起roles of your cloud function
但是,这只是为了提高Python代码和技能。无论如何,此功能都没有用。
确实,如前所述,具有云功能,您只能在/tmp
目录上进行写操作。它是一个内存中文件系统,云功能仅限于2Gb内存(包括文件和执行代码占用的内存)。顺便说一句,输入文件的大小不能超过800Mb,对于小文件,更容易。
INSERT SELECT
BigQuery查询INSERT INTO `<dataset>.<table>`
SELECT * except (<column to ignore>) from `<dataset>.<temporary table>`
由于您的文件很小(小于1GB),并且由于BigQuery免费层是5TB的已扫描数据(您只需支付所扫描的数据而不是进行处理,就可以免费执行所有SQL转换),因此更容易可以将数据处理到BigQuery中,而不是使用Python。
函数处理时间会更长,您可以为函数而不是BigQuery支付处理时间。