BigQuery:将数据导出到分层文件夹:YYYY / MM / DD

时间:2019-10-21 14:12:42

标签: google-bigquery

我要导出的BigQuery中有一个按日期分区的表。我想将其导出,以使每天的数据最终保存在另一个文件中。例如,到具有gs://my-bucket/YYYY/MM/DD/之类的嵌套文件夹结构的GS存储桶。这可能吗?

请不要告诉我我需要为每天的数据运行一个单独的导出作业:我知道这是可能的,但是在导出许多年的数据时,这很痛苦,因为您需要运行数千个导出作业。

在进口方面,可以使用镶木地板格式。

如果直接使用BigQuery无法做到这一点,那么是否有像dataproc或dataflow这样的GCS工具可以简化此工作(链接到实际执行此导出的脚本的要点)。

2 个答案:

答案 0 :(得分:1)

使用bq extract的bash脚本可以工作吗?

#!/bin/bash

# Stop on first error
set -e;

# Used for Bigquery partitioning (to distinguish from bash variable reference)
DOLLAR="\$"

# -I ISO DATE
# -d FROM STRING
start=$(date -I -d 2019-06-01) || exit -1
end=$(date -I -d 2019-06-15)   || exit -1

d=${start}

# string(d) <= string(end)
while [[ ! "$d" > "$end" ]]; do
    YYYYMMDD=$(date -d ${d} +"%Y%m%d")
    YYYY=$(date -d ${d} +"%Y")
    MM=$(date -d ${d} +"%m")
    DD=$(date -d ${d} +"%d")

    # print current date
    echo ${d}

    cmd="bq extract --destination_format=AVRO \
    'project:dataset.table${DOLLAR}${YYYYMMDD}' \
    'gs://my-bucket/${YYYY}/${MM}/${DD}/part*.avro'
    "

    # execute    
    eval ${cmd}

    # d++
    d=$(date -I -d "$d + 1 day")
done

也许您应该在https://issuetracker.google.com/savedsearches/559654上请求一项新功能。

不是bash忍者,所以请确保有一种比较酷的日期比较方法。

答案 1 :(得分:0)

在@Ben P的要求下,这是我以前用来并行运行许多导出作业的解决方案(python脚本)。这是相当粗糙的代码,应该通过在每个导出作业运行后检查其状态是否成功来进行改进。

我不会接受这个答案,因为问题正在寻找一种执行本任务的大查询本机方式。

请注意,此脚本用于导出版本化的数据集,因此围绕许多用户可能不需要的逻辑。假定输入表和输出文件夹名称都使用该版本。这应该很容易删除。

import argparse
import datetime as dt
from google.cloud import bigquery
from multiprocessing import Pool
import random
import time

GCS_EXPORT_BUCKET = "YOUR_BUCKET_HERE"
VERSION = "dataset_v1"

def export_date(export_dt, bucket=GCS_EXPORT_BUCKET, version=VERSION):
    table_id = '{}${:%Y%m%d}'.format(version, export_dt)
    gcs_filename = '{}/{:%Y/%m/%d}/{}-*.jsonlines.gz'.format(version, export_dt, table_id)
    gcs_path = 'gs://{}/{}'.format(bucket, gcs_filename)
    job_id = export_data_to_gcs(table_id, gcs_path, 'currents')
    return (export_dt, job_id)

def export_data_to_gcs(table_id, destination_gcs_path, dataset):
    bigquery_client = bigquery.Client()
    dataset_ref = bigquery_client.dataset(dataset)
    table_ref = dataset_ref.table(table_id)
    job_config = bigquery.job.ExtractJobConfig()
    job_config.destination_format = 'NEWLINE_DELIMITED_JSON'
    job_config.compression = 'GZIP'
    job_id = 'export-{}-{:%Y%m%d%H%M%S}'.format(table_id.replace('$', '--'),
                                                dt.datetime.utcnow())
    # Add a bit of jitter
    time.sleep(5 * random.random())
    job = bigquery_client.extract_table(table_ref,
                                        destination_gcs_path,
                                        job_config=job_config,
                                        job_id=job_id)
    print(f'Now running job_id {job_id}')
    time.sleep(50)
    job.reload()
    while job.running():
        time.sleep(10)
        job.reload()
    return job_id



if __name__ == "__main__":
    parser = argparse.ArgumentParser()

    parser.add_argument('-s', "--startdate",
                        help="The Start Date - format YYYY-MM-DD (Inclusive)",
                        required=True,
                        type=dt.date.fromisoformat)
    parser.add_argument('-e', "--enddate",
                        help="The End Date format YYYY-MM-DD (Exclusive)",
                        required=True,
                        type=dt.date.fromisoformat)

    args = parser.parse_args()

    start_date = args.startdate
    end_date = args.enddate

    dates = []
    while start_date < end_date:
        dates.append(start_date)
        start_date += dt.timedelta(days=1)

    with Pool(processes=30) as pool:
        jobs = pool.map(export_date, dates, chunksize=1)

要运行此代码,请将其放入名为bq_exporter.py的文件中,然后运行python bq_exporter.py -s 2019-01-01 -e 2019-02-01。该操作将在2019年1月导出,并打印每个导出作业的ID。您可以通过bq show -j JOB_ID使用BigQuery CLI检查作业的状态。