BigQuery
是 Google 推出的全托管式、无需运维、费用低廉的分析数据库。借助 BigQuery,您可以查询数 TB 的数据,而不必管理任何基础设施,也无需数据库管理员。BigQuery 使用 SQL,并且支持随用随付模式。BigQuery 让您可以专心分析数据,发掘有意义的数据洞见。
在本实验中,您将在 BigQuery 内深入处理半结构化数据(注入 JSON、数组数据类型)。对您的架构进行反规范化,将其制作成包含嵌套和重复字段的单个表,这样可以提升性能,但用于处理数组数据的 SQL 语法可能会很复杂。您将练习加载和查询各种半结构化数据集、排查相关问题,以及解除这些数据集的嵌套。
您将执行的操作
在本实验中,您将学习如何完成以下操作:
加载和查询半结构化数据,包括解除这些数据的嵌套。
对有关半结构化数据的查询进行问题排查。
设置和要求
点击“开始实验”按钮前的注意事项
请阅读以下说明。实验是计时的,并且您无法暂停实验。计时器在您点击
开始实验
后即开始计时,显示 Google Cloud 资源可供您使用多长时间。
此实操实验可让您在真实的云环境中开展实验活动,免受模拟或演示环境的局限。我们会为您提供新的临时凭据,让您可以在实验规定的时间内用来登录和访问 Google Cloud。
为完成此实验,您需要:
能够使用标准的互联网浏览器(建议使用 Chrome 浏览器)。
注意
:请使用无痕模式或无痕浏览器窗口运行此实验。这可以避免您的个人账号与学生账号之间发生冲突,这种冲突可能导致您的个人账号产生额外费用。
完成实验的时间 - 请注意,实验开始后无法暂停。
注意
:如果您已有自己的个人 Google Cloud 账号或项目,请不要在此实验中使用,以避免您的账号产生额外的费用。
如何开始实验并登录 Google Cloud 控制台
点击
开始实验
按钮。如果该实验需要付费,系统会打开一个弹出式窗口供您选择付款方式。左侧是
实验详细信息
面板,其中包含以下各项:
打开 Google Cloud 控制台
按钮
进行该实验时必须使用的临时凭据
帮助您逐步完成本实验所需的其他信息(如果需要)
点击
打开 Google Cloud 控制台
(如果您使用的是 Chrome 浏览器,请右键点击并选择
在无痕式窗口中打开链接
)。
该实验会启动资源并打开另一个标签页,显示
登录
页面。
提示
:请将这些标签页安排在不同的窗口中,并将它们并排显示。
注意
:如果您看见
选择账号
对话框,请点击
使用其他账号
。
如有必要,请复制下方的
用户名
,然后将其粘贴到
登录
对话框中。
{{{user_0.username | "<用户名>"}}}
您也可以在
实验详细信息
面板中找到
用户名
。
点击
下一步
。
复制下面的
密码
,然后将其粘贴到
欢迎
对话框中。
{{{user_0.password | "<密码>"}}}
您也可以在
实验详细信息
面板中找到
密码
。
点击
下一步
。
重要提示:
您必须使用实验提供的凭据。请勿使用您的 Google Cloud 账号凭据。
注意
:在本次实验中使用您自己的 Google Cloud 账号可能会产生额外费用。
继续在后续页面中点击以完成相应操作:
接受条款及条件。
由于该账号为临时账号,请勿添加账号恢复选项或双重验证。
请勿注册免费试用。
片刻之后,系统会在此标签页中打开 Google Cloud 控制台。
注意:
如需查看列有 Google Cloud 产品和服务的菜单,请点击左上角的
导航菜单
。
打开 BigQuery 控制台
在 Google Cloud 控制台中,选择
导航菜单
>
BigQuery
。
您会看到
欢迎在 Cloud 控制台中使用 BigQuery
消息框,其中提供了指向快速入门指南和版本说明的链接。
点击
完成
。
BigQuery 控制台即会打开。
任务 1. 创建新数据集来存储表
在 BigQuery 中,点击您的项目 ID 旁边的三点状图标,然后选择
创建数据集
:
在传统的关系型数据库 SQL 中,看到重复的姓名,您会立即想到将上表拆分为两个单独的表:“水果”和“用户”。该过程称为
标准化
(即一个表拆分为多个表)。对于 mySQL 等事务型数据库,这是一种常用方法。
对于数据仓储,数据分析师通常会采取相反的方法(即反规范化),将多个单独的表合并为一个大型报表。
现在,您将学习一种不同的方法,将不同粒度级别的数据全部存储在一个使用重复字段的表中:
Fruit (array)
Person
#standardSQL
SELECT
['raspberry', 'blackberry', 'strawberry', 'cherry', 1234567] AS fruit_array
您应该会收到如下所示的错误消息:
Error:
Array elements of types {INT64, STRING} do not have a common supertype at [3:1]
数组中元素的数据类型必须相同(全都是字符串、全都是数字)。
以下是要查询的最终表:
#standardSQL
SELECT person, fruit_array, total_cost FROM `data-to-insights.advanced.fruit_store`;
点击
运行
。
查看结果后,点击
JSON
标签页即可查看结果的嵌套结构。
将半结构化 JSON 加载到 BigQuery 中
如果您有需要注入到 BigQuery 中的 JSON 文件,该怎么办?
在数据集内创建一个新表
fruit_details
。
点击
fruit_store
数据集。
您随即会看到
创建表
选项。
注意:
您可能需要将浏览器窗口拉宽才能看到“创建表”选项。
在表中添加以下详细信息:
来源
:在
基于以下数据源创建表
下拉菜单中,选择
Google Cloud Storage
。
从 Cloud Storage 存储桶中选择文件
:
data-insights-course/labs/optimizing-for-performance/shopping_cart.json
文件格式
:JSONL(以换行符分隔的 JSON)
将新表命名为
fruit_details
。
勾选
架构(自动检测)
对应的复选框。
点击
创建表
。
在架构中,请注意
fruit_array
已标记为 REPEATED,这表示它是数组。
BigQuery 原生支持数组
数组的值必须采用同一种数据类型
在 BigQuery 中,数组称为 REPEATED 字段
点击“检查我的进度”以验证是否完成了以下目标:
创建新的数据集和表来存储数据
任务 3. 使用 ARRAY_AGG() 创建您自己的数组
您的表中还没有数组吗?您可以自行创建!
复制并粘贴
以下查询,探索此公共数据集:
SELECT
fullVisitorId,
date,
v2ProductName,
pageTitle
FROM `data-to-insights.ecommerce.all_sessions`
WHERE visitId = 1501570398
ORDER BY date
点击
运行
,然后查看结果。
现在,使用
ARRAY_AGG()
函数,将字符串值聚合到数组中。
复制并粘贴
以下查询,探索此公共数据集:
SELECT
fullVisitorId,
date,
ARRAY_AGG(v2ProductName) AS products_viewed,
ARRAY_AGG(pageTitle) AS pages_viewed
FROM `data-to-insights.ecommerce.all_sessions`
WHERE visitId = 1501570398
GROUP BY fullVisitorId, date
ORDER BY date
点击
运行
,然后查看结果
date,
ARRAY_AGG(v2ProductName) AS products_viewed,
ARRAY_LENGTH(ARRAY_AGG(v2ProductName)) AS num_products_viewed,
ARRAY_AGG(pageTitle) AS pages_viewed,
ARRAY_LENGTH(ARRAY_AGG(pageTitle)) AS num_pages_viewed
FROM `data-to-insights.ecommerce.all_sessions`
WHERE visitId = 1501570398
GROUP BY fullVisitorId, date
ORDER BY date
date,
ARRAY_AGG(DISTINCT v2ProductName) AS products_viewed,
ARRAY_LENGTH(ARRAY_AGG(DISTINCT v2ProductName)) AS distinct_products_viewed,
ARRAY_AGG(DISTINCT pageTitle) AS pages_viewed,
ARRAY_LENGTH(ARRAY_AGG(DISTINCT pageTitle)) AS distinct_pages_viewed
FROM `data-to-insights.ecommerce.all_sessions`
WHERE visitId = 1501570398
GROUP BY fullVisitorId, date
ORDER BY date
点击“检查我的进度”以验证是否完成了以下目标:
执行查询来查看浏览过的非重复产品的数量
您可以使用数组执行一些非常实用的操作,例如:
使用
ARRAY_LENGTH(<array>)
查找元素数量
使用
ARRAY_AGG(DISTINCT <field>)
删除重复的元素
使用
ARRAY_AGG(<field> ORDER BY <field>)
对元素进行排序
限制
ARRAY_AGG(<field> LIMIT 5)
任务 4. 查询包含数组的表
与我们的课程数据集
data-to-insights.ecommerce.all_sessions
相比,用于 Google Analytics 的 BigQuery 公共数据集
bigquery-public-data.google_analytics_sample
包含更多字段和行。更重要的是,该数据集已经以原生方式将字段值(例如产品、页面和交易)存储为 ARRAY。
复制并粘贴
以下查询,探索可用数据,看看能否找到包含重复值(数组)的字段:
SELECT
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
WHERE visitId = 1501570398
运行
查询。
在结果中
向右滚动
,直至您看到
hits.product.v2ProductName
字段(我们稍后会介绍多个字段别名)。
visitId,
hits.page.pageTitle
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
WHERE visitId = 1501570398
您会收到以下错误消息:
Error:
Cannot access field page on a value with type ARRAY<STRUCT<hitNumber INT64, time INT64, hour INT64, ...>> at [3:8]
您必须先将数组重新拆分为多行,然后才能正常查询 REPEATED 字段(数组)。
例如,
hits.page.pageTitle
数组目前以单行形式存储,如下所示:
['homepage','product page','checkout']
该数组需要拆分为多行:
['homepage',
'product page',
'checkout']
如何使用 SQL 实现这一点?
回答:
对数组字段使用 UNNEST() 函数:
SELECT DISTINCT
visitId,
h.page.pageTitle
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`,
UNNEST(hits) AS h
WHERE visitId = 1501570398
LIMIT 10
我们稍后会更详细地介绍 UNNEST(),但现在您只需知道:
您需要对数组使用 UNNEST() 函数,才能将数组元素重新拆分为多行
UNNEST() 始终跟在 FROM 子句中表名称的后面(概念上可视为预联接的表)
点击“检查我的进度”以验证是否完成了以下目标:
执行查询来对数组字段使用 UNNEST()
任务 5. STRUCT 简介
您可能想过,为什么字段别名
hit.page.pageTitle
看起来像是三个字段合而为一,并以英文句点分隔。就像 ARRAY 值可让您灵活地深入了解字段粒度一样,您可以使用另一种数据类型,将相关字段归为一组,从而扩充您的架构。
该 SQL 数据类型就是
STRUCT
数据类型。
理解 STRUCT 的最简单方法是,从概念上将其视为已经预联接到主表的单独表。
STRUCT 的特点如下:
包含一个或多个字段
每个字段可以具有相同或不同的数据类型
拥有自己的别名
听起来很像表,对吧?
探索包含 STRUCT 的数据集
若要打开
bigquery-public-data
数据集,请点击
+添加
,选择
按名称为项目加星标
,然后输入名称
bigquery-public-data
点击
加星标
。
“探索器”部分会显示
bigquery-public-data
项目。
打开
bigquery-public-data
。
查找并打开
google_analytics_sample
数据集。
点击 ga_sessions(366)_ 表。
开始滚动浏览架构,并使用浏览器的查找功能回答下列问题。
totals.*,
device.*
FROM `bigquery-public-data.google_analytics_sample.ga_sessions_20170801`
WHERE visitId = 1501570398
LIMIT 10
注意:
.*
语法会指示 BigQuery 返回该 STRUCT 的所有字段(就像我们联接单独的表
totals.*
时一样)。
通过将大型报表存储为 STRUCT(预联接的“表”)和 ARRAY(粒度更深),您可以:
避免对 32 个表执行 JOIN 操作,获得显著的性能优势
在需要时从 ARRAY 获取粒度数据,但如果您不需要,也不会受到处罚(BigQuery 会将各列单独存储在磁盘上)
将所有业务情境汇总在一个表中,而不必担心 JOIN 键以及哪些表包含您需要的数据
任务 6. 练习使用 STRUCT 和数组
下一个数据集是跑步者绕着跑道跑一圈的时间。每一圈称为一个“分段”。
利用此查询,试用 STRUCT 语法并注意结构体容器内的不同字段类型:
#standardSQL
SELECT STRUCT("Rudisha" as name, 23.4 as split) as runner
您从字段别名中发现了什么?由于字段嵌套在结构体内(name 和 split 是 runner 的子集),因此最终需要使用点表示法。
如果跑步者在一场比赛中有多个分段时间(例如每圈时间),该怎么办?
当然是使用数组!
运行下面的查询进行确认:
#standardSQL
SELECT STRUCT("Rudisha" as name, [23.4, 26.3, 26.4, 26.1] as splits) AS runner
来源
:在
基于以下数据源创建表
下拉菜单下,选择
Google Cloud Storage
。
从 Cloud Storage 存储桶中选择文件
:
data-insights-course/labs/optimizing-for-performance/race_results.json
文件格式
:JSONL(以换行符分隔的 JSON)
在
架构
中,点击
以文本形式修改
滑块,然后添加以下内容:
"name": "race",
"type": "STRING",
"mode": "NULLABLE"
"name": "participants",
"type": "RECORD",
"mode": "REPEATED",
"fields": [
"name": "name",
"type": "STRING",
"mode": "NULLABLE"
"name": "splits",
"type": "FLOAT",
"mode": "REPEATED"
将新表命名为
race_results
。
点击
创建表
。
加载作业成功后,预览新创建的表的架构:
哪个字段属于 STRUCT?您是怎么知道的?
participants
字段属于 STRUCT,因为其类型为 RECORD。
哪个字段属于 ARRAY?
participants.splits
字段是父级
participants
结构体内的浮点数数组。该字段的模式为 REPEATED,这表示它是数组。该数组的值是单个字段内的多个值,因此称为嵌套值。
点击“检查我的进度”以验证是否完成了以下目标:
创建数据集和表来注入 JSON 数据
练习查询嵌套和重复字段
我们来看看所有参赛者的 800 米比赛结果:
#standardSQL
SELECT * FROM racing.race_results
系统返回了多少行?
回答:
1 行
如果您想要列出每位跑步者的姓名和比赛类型,该怎么办?
运行以下架构,看看会发生什么情况:
#standardSQL
SELECT race, participants.name
FROM racing.race_results
Error:
Cannot access field name on a value with type ARRAY<STRUCT<name STRING, splits ARRAY<FLOAT64>>>> at [2:27]
就像使用聚合函数时忘记添加 GROUP BY 一样,以下列表中有两种不同的粒度级别。一行用于比赛类型,三行用于参赛者姓名。那么,如何将…
participants.name
在传统的关系型 SQL 中,如果您有一个比赛类型表和一个参赛者表,该如何从这两个表中获取信息?您会使用 JOIN 将两者联接起来。在此示例中,参赛者 STRUCT(在概念上与表非常相似)已经成为比赛类型表的一部分,但尚未与您的非 STRUCT 字段“race”正确关联。
您可以使用 SQL 命令将 800 米比赛与第一个表中的各位参赛者关联起来,能想到是哪两个单词组成的命令吗?
回答:
CROSS JOIN
现在,尝试运行以下内容:
#standardSQL
SELECT race, participants.name
FROM racing.race_results
CROSS JOIN
participants # this is the STRUCT (it is like a table within a table)
Table name "participants" missing dataset while no default dataset is set in the request
.
虽然参赛者 STRUCT 与表类似,但从技术上讲仍然是
racing.race_results
表中的字段。
将数据集名称添加到查询中:
#standardSQL
SELECT race, participants.name
FROM racing.race_results
CROSS JOIN
race_results.participants # full STRUCT name
然后点击
运行
。
哇!您已成功列出每场比赛的所有参赛者!
FROM racing.race_results AS r, r.participants
如果有多个比赛类型(800 米、100 米、200 米),CROSS JOIN 是否会将每位参赛者的姓名与每场可能的比赛关联起来,就像笛卡尔积一样?
回答
:不会。这属于相互关联的交叉联接,只能拆分与单个行相关联的元素。
如需了解更多讨论内容,请参阅
使用 ARRAY 和 STRUCT
STRUCT 要点回顾:
SQL
STRUCT
只是一个用来容纳其他数据字段的容器,这些字段可以采用不同的数据类型。结构体一词是指数据结构。回想一下之前的示例:
STRUCT(``"Rudisha" as name, [23.4, 26.3, 26.4, 26.1] as splits``)`` AS runner
结构体会被赋予别名(例如上面的 runner),并且在概念上可视为主表内的表。
您必须先拆分 STRUCT(和 ARRAY),然后才能对其元素进行操作。使用 UNNEST() 将结构体本身的名称或属于数组的结构体字段括起来,以便将其拆分和展平。
任务 7. 实验问题:STRUCT()
请使用您之前创建的
racing.race_results
表回答下面的问题。
任务:
编写查询,使用 COUNT 计算总参赛人数。
首先,使用下面未编写完全的查询:
#standardSQL
SELECT COUNT(participants.name) AS racer_count
FROM racing.race_results
注意:
请记住,您需要对结构体名称进行交叉联接,并将其放在
FROM
后面,作为额外的数据源。
可能的解决方法:
#standardSQL
SELECT COUNT(p.name) AS racer_count
FROM racing.race_results AS r, UNNEST(r.participants) AS p
任务 8. 实验问题:使用 UNNEST( ) 拆分数组
您可以编写查询,用于列出姓名以 R 开头的参赛者的总比赛时长。将总时长最短的结果排在最前面。使用 UNNEST() 运算符,然后从下面未编写完全的查询着手。
将查询补充完整:
#standardSQL
SELECT
p.name,
SUM(split_times) as total_race_time
FROM racing.race_results AS r
, r.participants AS p
, p.splits AS split_times
WHERE
GROUP BY
ORDER BY
您需要拆分结构体及其中的数组,并将其放在 FROM 子句后面,作为数据源。
在适当的情况下,请务必使用别名。
可能的解决方法:
#standardSQL
SELECT
p.name,
SUM(split_times) as total_race_time
FROM racing.race_results AS r
, UNNEST(r.participants) AS p
, UNNEST(p.splits) AS split_times
WHERE p.name LIKE 'R%'
GROUP BY p.name
ORDER BY total_race_time ASC;
FROM racing.race_results AS r
, UNNEST(r.participants) AS p
, UNNEST(p.splits) AS split_time
WHERE split_time = 23.2;
Google Cloud 培训和认证
…可帮助您充分利用 Google Cloud 技术。
我们的课程
会讲解各项技能与最佳实践,可帮助您迅速上手使用并继续学习更深入的知识。我们提供从基础到高级的全方位培训,并有点播、直播和虚拟三种方式选择,让您可以按照自己的日程安排学习时间。各项
认证
可以帮助您核实并证明您在 Google Cloud 技术方面的技能与专业知识。
上次更新手册的时间:2024 年 2 月 3 日
上次测试实验的时间:2023 年 8 月 25 日