使用 ObjectRef 值
本文档介绍了 ObjectRef 值以及如何在 BigQuery 中创建和使用这些值。
ObjectRef 值是一种 STRUCT 类型,具有引用 Cloud Storage 对象进行多模态分析的预定义架构。它可由 OBJ 函数、AI 函数或 Python 用户定义的函数进行处理。
架构
ObjectRef 值具有以下字段:
| 名称 | Type | Mode | 说明 | 示例 |
|---|---|---|---|---|
uri |
STRING |
REQUIRED |
Cloud Storage 对象的 URI。 | "gs://cloud-samples-data/vision/demo-img.jpg" |
version |
STRING |
NULLABLE |
对象生成。 | "1560286006357632" |
authorizer |
STRING |
NULLABLE |
用于委托访问的 BigQuery 连接 ID,或用于直接访问的 NULL。该 ID 可以采用以下格式:"region.connection"或 "project.region.connection" |
"myproject.us.myconnection" |
details |
JSON |
NULLABLE |
对象元数据或处理对象时发生的错误。它可以包含对象的 content_type、md5_hash、size 和 updated 字段。 |
{"gcs_metadata":{"content_type":"image/png","md5_hash":"dfbbb5cf034af026d89f2dc16930be15","size":915052,"updated":1560286006000000}} |
details 列中 gcs_metadata 字段内的 content_type 字段是从 Cloud Storage 中提取的。您可以在 Cloud Storage 中设置对象的内容类型。如果您在 Cloud Storage 中省略了该参数,则 BigQuery 会根据 URI 的后缀推断内容类型。
创建 ObjectRef 值
您可以使用对象表、OBJ.MAKE_REF 函数、OBJ.LIST 函数或 Cloud Storage Insights 数据集创建 ObjectRef 值。
使用对象表
如果您没有在表中存储 URI,并且想要保留 Cloud Storage 前缀中的所有对象的列表,请使用对象表。对象表在每行中存储对对象的引用,并具有包含 ObjectRef 值的 ref 列。以下查询使用 CREATE EXTERNAL TABLE 语句创建对象表:
CREATE EXTERNAL TABLE mydataset.images
WITH CONNECTION `us.myconnection`
OPTIONS (uris=["gs://mybucket/images/*"], object_metadata="SIMPLE");
SELECT ref AS image_ref FROM mydataset.images;
来自对象表的 ObjectRef 值必须具有委托访问权限的授权方。授权方连接与您用于创建对象表的连接相同。
使用 OBJ.MAKE_REF 函数
如果您已在表中存储了 URI,并且想要根据这些 URI 创建 ObjectRef 值,请使用 OBJ.MAKE_REF 函数。以下查询展示了如何从包含 Cloud Storage URI 的 uri 列在 image_ref 列中创建 ObjectRef 值:
-- Specify only the URI
SELECT *, OBJ.MAKE_REF(uri) AS image_ref FROM mydataset.images;
-- Specify the URI and the connection
SELECT *, OBJ.MAKE_REF(uri, "us.myconnection") AS image_ref FROM mydataset.images;
如需修改现有 ObjectRef 值的授权方,您可以使用 OBJ.MAKE_REF 函数:
-- Remove the authorizer
SELECT *, OBJ.MAKE_REF(ref, authorizer=>NULL) AS image_ref FROM mydataset.images;
-- Change the authorizer
SELECT *, OBJ.MAKE_REF(ref, authorizer=>"us.myconnection2") AS image_ref FROM mydataset.images;
OBJ.MAKE_REF 函数接受可为 null 的授权方,以支持直接访问和委托访问。
使用 OBJ.LIST 函数
使用 OBJ.LIST 函数可实现自发发现。OBJ.LIST 函数会返回一个表,其中包含 Cloud Storage 中存储的文件的元数据和 ObjectRef 值。Cloud Storage 数据可以包括文档、图片和音频。
使用 OBJ.LIST 后,您无需在永久表中手动构建 ObjectRef 值。您可以快速将 Cloud Storage 对象添加到 AI 函数中,以构建自发 ETL 流水线,用于处理将非结构化数据转换为结构化数据。如果您需要一个持久、自行更新的表,以便持续跟踪一段时间内到达存储桶的新对象,则应改为创建标准 BigQuery 对象表。
以下查询使用通配符 (*) 发现特定文件类型,并使用 AI.IF 函数过滤非结构化数据。此查询仅列出包含狗图片的 PNG 文件。
SELECT
uri,
content_type,
size
FROM
OBJ.LIST('gs://mybucket/images/*.png')
WHERE
AI.IF(('Does this image contain a dog?', ref))
ORDER BY
uri;
使用 Cloud Storage Insights 数据集
如果您配置了 Storage Insights 数据集,则该数据集已包含一个包含 ObjectRef 值的 ref 列。在 Storage Insights 数据集中创建的任何 ObjectRef 值都没有授权方。如需查询这些对象,您必须拥有对该对象的直接访问权限,或者向 ObjectRef 添加授权方以使用委托访问权限。
授权方和权限
当您将 ObjectRef 值传递给 ObjectRef 函数、AI 函数或 Python UDF 时,这些函数需要访问存储在 Cloud Storage 中的对象。您可以根据 authorizer 字段的值,通过以下两种方式授权此访问权限:直接访问和委托访问。
直接访问
通过直接访问,运行查询的用户可以使用自己的凭据直接访问对象。当 ObjectRef 值没有授权方时,系统会使用直接访问。
直接访问具有以下限制:
- 用户必须拥有访问对象的权限。
- 如果查询作业在没有连接的情况下使用
AI.GENERATE、AI.IF、AI.SCORE或AI.CLASSIFY函数,则用户需要拥有额外权限。该查询只能访问执行作业的同一项目中的 Cloud Storage 存储桶和对象。
例如,如果您对没有授权者的 ObjectRef 值调用 AI.GENERATE 函数,则该函数会以您的身份读取对象。如果您无权读取对象,则该函数会将 "permission denied" 错误写入结果中的 status 列。
以下示例展示了使用直接访问的查询:
-- Requires that the end user can read the object "gs://cloud-samples-data/vision/demo-img.jpg" and use the Agent Platform model.
SELECT AI.GENERATE(
("Describe this image:",
OBJ.MAKE_REF("gs://cloud-samples-data/vision/demo-img.jpg")));
委托的访问权限
借助委托访问权限,运行查询的用户会将对象访问权限委托给 BigQuery Cloud 资源连接,该连接在 ObjectRef 值的 authorizer 字段中指定。委托访问权限可实现跨项目数据访问。
如需使用委托访问权限,您的数据管理员必须按照以下步骤设置连接和权限:
- 一次性设置。数据管理员必须设置 Cloud 资源连接来管理 Cloud Storage 存储桶:
- 创建新的 BigQuery Cloud 资源连接,或重复使用项目中的现有连接。
- 在连接的元数据中查找服务账号。
- 在项目或 Cloud Storage 存储桶中,向服务账号授予
storage.objects.get权限(用于读取)或storage.objects.create权限(用于写入)。您可以使用 Storage Object Viewer 或 Storage Object User 角色授予这些权限。
- 按用户设置。数据管理员必须向用户授予对 BigQuery 连接的
bigquery.objectRefs.read权限(用于读取)或bigquery.objectRefs.write权限(用于写入)。您可以使用 BigQuery ObjectRef Reader 或 BigQuery ObjectRef Admin 角色授予这些权限。
例如,如果用户将具有授权方的 ObjectRef 值传递给 AI.GENERATE 函数,则该函数会验证用户是否具有 bigquery.objectRefs.read 权限,然后使用连接的服务账号读取对象。如果用户或服务账号权限不足,则该函数会将 "permission denied" 错误写入结果中的 status 列。
以下示例展示了使用委托访问权限的查询。它需要满足以下条件:
- 用户对
connection1拥有bigquery.objectRefs.read权限。 connection1的服务账号对该对象具有storage.objects.get权限。connection2的服务账号具有 Agent Platform User 角色。
SELECT AI.GENERATE(
("Describe this image:",
OBJ.MAKE_REF("gs://cloud-samples-data/vision/demo-img.jpg", "us.connection1")),
connection_id => "us.connection2");
在 VPC Service Controls 边界内,AI 函数无法处理使用委托访问权限的 ObjectRef 值。委托访问权限会为对象生成签名的 HTTPS 网址,而签名网址无法跨越边界。该函数会将以下错误之一写入结果中的 status 列:
INVALID_ARGUMENT: HTTP links are not supported for requests restricted by VPCSC.如果您的边界限制了 Agent Platform,就会发生此错误。Cannot fetch content from the provided URL如果您的边界限制了 Cloud Storage,则会出现此错误。
由于对象表的 ref 列始终使用对象表的连接作为授权方,因此将 ref 传递给边界内的 AI 函数始终会返回此错误。如需分析对象,请改为传递单个参数 OBJ.MAKE_REF(uri) 值,该值使用直接访问,并将 Cloud Storage URI 发送到模型,而无需生成签名网址。
最佳做法
在决定是使用直接访问还是委托访问时,请考虑以下最佳实践:
- 对于在单个项目中同时进行数据存储区和分析的小型团队,请使用直接访问。数据管理员使用 Identity and Access Management 向用户授予对 BigQuery 数据和 Cloud Storage 数据的访问权限。用户可以根据需要创建
ObjectRef值,而无需授权方使用自己的凭据分析对象。 - 对于跨多个项目运营的大型团队,请使用委托访问权限,尤其是在数据存储区和分析分离的情况下。数据管理员可以设置连接,并使用连接作为授权方提前创建
ObjectRef值以供分析。此方法适用于对象表,或通过对 URI 列表使用OBJ.MAKE_REF来实现。然后,数据管理员可以与分析师共享存储ObjectRef值的表。分析师无需访问原始存储桶即可分析对象。由于委托访问权限会授予对连接的服务账号可以访问的所有对象的访问权限,而不管对象表或标准表上的行级访问权限政策如何,因此请将每个连接的 Cloud Storage 权限范围限定为仅限其用户有权访问的存储桶或托管文件夹。
错误
使用 ObjectRef 值的函数会通过以下两种方式报告错误:
- 查询失败:查询可能会失败,并显示出错提示,且不返回任何结果。
- 返回错误值:查询成功,但函数可能会将错误作为返回值的一部分写入。如需了解返回值的格式,请参阅您所用函数的参考页面。
当函数返回 ObjectRef 值时,该值的 details 字段可能包含 errors 字段。如果存在,则该字段的值是一个错误数组。每个错误都具有以下架构:
| 名称 | Type | Mode | 说明 | 示例 |
|---|---|---|---|---|
code |
INT64 |
REQUIRED |
标准 HTTP 错误代码。 | 400 |
message |
STRING |
REQUIRED |
描述性、人性化的出错提示。 | "Connection credential for myproject.us.nonexistent_connection cannot be used. Either the connection does not exist, or the user does not have sufficient permissions (bigquery.objectRefs.read)" |
source |
STRING |
REQUIRED |
触发错误的函数的名称。 | "OBJ.MAKE_REF" |
以下是两种常见的错误类型:
- 对象错误:提供的对象 URI 或版本不存在。
- 授权方错误:连接不存在,或者用户无权将其用于委托访问。
以下查询展示了如何从 Objectref 列中选择包含错误的 ObjectRef 值:
SELECT ref
FROM mydataset.images
WHERE ref.details.errors IS NOT NULL;
后续步骤
- 在表架构中指定
ObjectRef列。 - 分析多模态数据。
- 详细了解 ObjectRef 函数。