BigQuery Storage API 无法读取由有序 (ORDER BY) 查询创建的临时表

Posted

技术标签:

【中文标题】BigQuery Storage API 无法读取由有序 (ORDER BY) 查询创建的临时表【英文标题】:BigQuery Storage API cannot read from a temporary table created by ordered (ORDER BY) queries 【发布时间】:2019-05-18 14:27:41 【问题描述】:

Google 的 BigQuery Storage API 可以读取由仅涉及 SELECT、FROM 和 WHERE 的基本查询创建的临时表

我看到的是,当您使用 ORDER BY 语句检索一组有序的行时,BigQuery 存储 API 无法读取创建的临时表。

看看下面的代码示例:

让我们来看看这个查询:

sql = """SELECT name FROM `bigquery-public-data.usa_names.usa_1910_current` LIMIT 1000"""

如果您使用此 BigQuery python API 代码运行它:

bq_client = bigquery.Client("myproject") ## << Change to your project

query_job = bq_client.query(
    sql,
    location='US')  

project_id = query_job.destination.project
dataset_id = query_job.destination.dataset_id
table_id = query_job.destination.table_id

print("Destination table: " + project_id + "." + dataset_id + "." + table_id)

...然后你得到目标表。

从这里,您可以将此目标表传递给 BigQuery Storage API 以使用 RPC 获取结果:


client = bigquery_storage_v1beta1.BigQueryStorageClient()

table_ref = bigquery_storage_v1beta1.types.TableReference()
table_ref.project_id = project_id
table_ref.dataset_id = dataset_id
table_ref.table_id = table_id

read_options = bigquery_storage_v1beta1.types.TableReadOptions()
read_options.selected_fields.append("name")

parent = "projects/".format(project_id)
session = client.create_read_session(
    table_ref, parent, table_modifiers=modifiers, read_options=read_options
)  # API request.

reader = client.read_rows(
    bigquery_storage_v1beta1.types.StreamPosition(stream=session.streams[0])
)

rows = reader.rows(session)

这很好用。

现在将sql= &lt;yourquery&gt; 中的查询更改为

sql = """SELECT name FROM `bigquery-public-data.usa_names.usa_1910_current` ORDER BY name ASC LIMIT 1000"""

您将从代码的 BigQuery Storage API 部分收到以下错误:

Table 'myproject:mydataset.temptable' has a storage format that is not supported.

这意味着查询中的 ORDER BY 语句增加了某种复杂性,使存储 API 无法读取临时表。

问题: 1)关于如何解决这个问题的任何想法,还是此时存储 API 的真正限制? 2) 如果 ORDER BY 产生问题,查询的全范围是多少 为存储 API 创建不可读的临时表?

【问题讨论】:

结果集的大小是多少? AFAIK,这与临时表的大小有关,而不是 ORDER BY。 BigQuery Storage API 可以从临时表中读取之前的阈值约为 100 MB。这可以通过在查询中显式设置目标表来解决。 如果您运行上面的代码示例,您会发现相同的结果:无论数据大小如何,通过将 ORDER BY 添加到查询中,您将无法再从临时表中读取。实际上,当您显式创建一个临时表作为目标时它可以工作,但不适用于隐式创建的表。 当我运行代码示例时(将修饰符设置为 None,因为这没有定义),我首先得到错误 400 there was an error creating the session: the table has a storage format that is not supported,没有设置 ORDER BY,然后使用 ORDER BY 设置我得到 400 The following selected fields do not exist in the table schema: name 【参考方案1】:

我们可以使用 bigquery_storage.BigQueryReadClient 从由 order by、join 等查询创建的临时表中读取数据。下面是工作代码。 我已经使用 join 创建了临时表。

from google.cloud.bigquery_storage import BigQueryReadClient
from google.cloud.bigquery_storage import types, ReadRowsResponse

bqclient = bigquery.Client(credentials=credentials, project=your_project_id,)
client = bigquery_storage.BigQueryReadClient(credentials=credentials)

try:
    import fastavro
except ImportError:  
    fastavro = None

sql = """SELECT s.id, s.name, d.dept  FROM sbx-test.EMP.emp01 s join sbx-test.EMP.dept d 
on s.id = d.id"""
query_job = bqclient.query(sql)

project_id = query_job.destination.project
dataset_id = query_job.destination.dataset_id
table_id = query_job.destination.table_id

table = "projects//datasets//tables/".format(
    project_id, dataset_id, table_id
)
requested_session = types.ReadSession()
requested_session.table = table
requested_session.data_format = types.DataFormat.AVRO

requested_session.read_options.selected_fields = ["name", "dept"]

parent = "projects/".format(project_id)
session = client.create_read_session(
    parent=parent,
    read_session=requested_session,
    max_stream_count=1,
)
reader = client.read_rows(session.streams[0].name)
rows = reader.rows(session)

names = set()
depts = set()
for row in rows:
    names.add(row["name"])
    depts.add(row["dept"])
    
print("Got unique employees  and departments ".format(names, depts))
 

【讨论】:

以上是关于BigQuery Storage API 无法读取由有序 (ORDER BY) 查询创建的临时表的主要内容,如果未能解决你的问题,请参考以下文章

Google Spark-BigQuery-Connector如何利用BigQuery Storage API?

通过 Spark 使用 BigQuery Storage API:请求多个分区但仅获得 1 个

Bigquery API:如何为 load_table_from_storage 调用提供架构

bigquery storage API:是不是可以将 AVRO 文件直接流式传输/保存到 Google Cloud Storage?

如何使用 API 存储在 Google Cloud Storage 中的架构文件在 BigQuery 加载作业上设置架构?

Bigquery 无法从 Google Cloud Storage 加载数据