使用 GraphQL 聚合将 Microsoft Fabric 数据转换为可作的见解。 可以要求 Fabric 对数据进行分组和计算服务器端摘要,而不是检索成千上万的单个记录并在应用程序中进行处理,从而显著提高性能并减少数据传输。
GraphQL 聚合的工作方式类似于 SQL GROUP BY 操作,但通过 GraphQL API 实现。 可以计算每个类别的项目数、计算收入总计、查找平均评级,或确定 Lakehouse 和仓库表中的最小值/最大值(全部在单个高效查询中)。
主要优势:
- 服务器端处理:利用 Fabric 的优化查询引擎进行计算
- 减少数据传输:获取摘要而不是原始记录
- 单个查询效率:用一个聚合替换多个客户端操作
本指南介绍如何使用实际的电子商务示例生成聚合查询,涵盖从基本分组到高级函数和重要限制的所有内容。
谁应使用聚合
GraphQL 聚合对于以下方面非常有用:
- 应用程序开发人员 构建需要汇总Fabric数据的定制仪表板和分析应用程序
- 数据工程师 创建数据 API,以从 Fabric 数据湖和仓库中提供预先计算的指标和关键绩效指标 (KPI)
- BI 开发人员 构建自定义分析解决方案,以使用聚合构造数据补充 Power BI
- 集成开发人员 创建需要 Fabric 摘要统计信息的应用程序和工作流
- 数据分析师 构建自助分析解决方案,这些解决方案需要从 Fabric 数据中获取分组和聚合的见解
如果要检索数据以显示图表、计算总计、生成报表或分析趋势,聚合可以显著提高应用程序的性能并减少数据传输。
可以回答的常见业务问题
GraphQL 聚合擅长回答有关 Fabric 数据的分析问题:
- 计数和分组: “每个类别中的产品数?” 或 “每月订单数?”
- 财务计算: “按区域划分的总收入是多少?” 或 “按客户细分的平均订单值?”
- 性能指标: “每个类别中最高和最低评级的产品是什么?
- 客户见解: “本月访问的唯一客户数?” 或 “哪些城市拥有最活跃的用户?”
这些查询非常适合用于生成仪表板、生成报表和支持分析应用程序,需要汇总的数据,而不是单个记录。
先决条件
在使用 GraphQL 聚合之前,请确保具备:
- 具有适当权限的 Microsoft Fabric 工作区
- 包含要聚合数据的表的 Lakehouse 或仓库
- 为您的 Fabric 项目配置的 GraphQL 终结点的 API
- 基本熟悉 GraphQL 查询语法
运行这些查询的位置
快速入门:使用 Fabric 工作区中 GraphQL 编辑器的 API 测试本文中的所有示例。 编辑器提供架构浏览、查询验证和即时结果。
对于应用程序:使用任何用于编程语言的 GraphQL 客户端库,将查询作为 HTTP POST 请求发送到 GraphQL 终结点。
用于开发:GraphQL Playground、Insomnia 或 Postman 等工具适用于查询开发和测试。
注释
本文中的示例一旦完成了对 GraphQL 终结点的 API 配置,就可以直接复制运行。 出于简洁考虑,一些示例已被缩短,可能需要根据您的特定模式进行调整。
示例方案:Fabric 中的电子商务数据
对于本指南,我们使用存储在Microsoft Fabric lakehouse 或仓库中的虚构电子商务数据集。 此方案演示如何使用 GraphQL 聚合分析零售数据。
在此示例中,产品数据属于类别,每个 Product 包含诸如价格和评级之类的字段(这些数值非常适合用于聚合),并与 Category 存在关系。 通过 Fabric 的用于 GraphQL 的 API 公开这些表时,生成的架构可能如下所示:
type Category {
id: ID!
name: String!
products: [Product!]! # one-to-many relationship
}
type Product {
id: Int!
name: String!
price: Float!
rating: Int!
category_id: Int!
category: Category! # many-to-one relationship
}
type ProductResult { # automatically generated, adding groupBy capabilities
items: [Product!]!
endCursor: String
hasNextPage: Boolean!
groupBy(fields: [ProductScalarFields!]): [ProductGroupBy!]!
}
type Query {
products(
first: Int
after: String
filter: ProductFilterInput
orderBy: ProductOrderByInput
): ProductResult!
}
在此示例中, products 查询可以返回常规项列表,或者如果使用 groupBy 聚合结果。 让我们专注于使用此查询的groupBy和聚合功能。
注释
不能在同一查询中检索普通项和分组结果。 有关更多详细信息,请参阅 聚合和原始项互斥。
可用的聚合函数
可用的确切功能取决于实现,但常见的聚合操作包括:
- count – 组中的记录计数(或字段的非空值的数量)。
- sum – 数值字段中所有值的和。
- avg – 数值字段中值的平均值(平均值)。
- min – 字段中的最小值。
- max – 字段中的最大值。
在 GraphQL 聚合中,可以指定函数名称和目标字段,如示例count(field: id)sum(field: price)等所示。每个函数返回一个对象,允许你选择应用于的一个或多个字段。
注释
在 Microsoft Fabric 的 GraphQL API 中,聚合操作(例如count、sum、avg、min和max)当前仅适用于数值型或定量型字段(整数、浮点数)。 不能直接在文本或日期字段上使用它们。 例如,无法计算字符串字段的“平均值”。 在 Fabric 的未来更新中,可能会添加对其他数据类型(例如文本串联或词典最小/最大值)执行聚合的支持。
聚合查询基础知识
若要在 Fabric 的 GraphQL API 中执行聚合,请在查询中指定一个 groupBy 参数,以定义如何对数据进行分组,并在结果中请求聚合字段(如计数或总和)。 Fabric 的 GraphQL 引擎会针对基础 Lakehouse 或仓库表有效地处理这些查询,并返回包含其键值和计算聚合指标的分组记录的列表。
示例 1:对每个类别的产品进行计数
让我们按类别对产品进行分组,并计算每个组中的产品数量。 查询可能如下所示:
query {
products {
groupBy(fields: [category_id])
{
fields {
category_id # grouped key values
}
aggregations {
count(field: id) # count of products in each group (count of "id")
}
}
}
}
在本查询中:
-
groupBy(fields: [category_id])告知 Fabric GraphQL 引擎按category_id字段对产品进行分组。 - 在结果选择中,你请求
group,并对count字段执行id聚合。 使用id能有效统计该组中的产品。
结果如下所示: 响应中的每个项都表示一个类别组。 对象 groupBy 包含分组键。 在这里,它包括 category_id 该值,并提供 count { id } 该类别中的产品数:
{
"data": {
"products": {
"groupBy": [
{
"fields": {
"category_id": 1
},
"aggregations": {
"count": 3
}
},
{
"fields": {
"category_id": 2
},
"aggregations": {
"count": 2
}
},
// Sample shortened for brevity
]
}
}
}
此输出告诉我们类别 1 有三个产品,第 2 类有 2 个,等等。
示例 2:求和和平均值
我们可以在一个查询中请求多个聚合指标。 假设我们想要,对于每个类别,所有产品的总价格和平均评级:
query {
products {
groupBy(fields: [category_id])
{
fields {
category_id
}
aggregations {
count(field: id) # number of products in the category
sum(field: price) # sum of all product prices in the category
avg(field: rating) # average rating of products in the category
}
}
}
}
此查询将返回以下结果:
{
"data": {
"products": {
"groupBy": [
{
"fields": {
"category_id": 1
},
"aggregations": {
"count": 3,
"sum": 2058.98,
"avg": 4
}
},
{
"fields": {
"category_id": 2
},
"aggregations": {
"count": 2,
"sum": 109.94,
"avg": 4
}
},
...
]
}
}
}
每个组对象包括类别和计算聚合,例如产品数、价格之和以及该类别中的平均分级。
示例 3:按多个字段分组
可以按多个字段进行分组以获取多级分组。 例如,如果你的产品有一个 rating 字段,则可以按两者 category_id 进行分组, rating 然后计算该组的平均值 price :
query {
products {
groupBy(fields: [category_id, rating])
{
fields {
category_id
rating
}
aggregations {
avg(field: price)
}
}
}
}
这将按类别 和 分级的唯一组合对产品进行分组,如下所示:
{
"fields": {
"category_id": 10,
"rating": 4
},
"aggregations": {
"avg": 6.99
}
}
依此类推处理数据中的每个类别评分对。
小窍门
按多个字段分组时,显式排序对于可预测结果尤为重要。 请参阅 “对分组结果进行排序需要显式指定顺序”。
示例 4:使用独特的
聚合功能支持 不同的 修饰符来计算或考虑唯一值。 例如,若要了解产品集合中存在多少个不同类别,可以使用非重复计数:
query {
products {
groupBy(fields: [category_id])
{
fields {
category_id
}
aggregations {
count(field: id, distinct: true)
}
}
}
}
此查询返回一个结果,其中包含每个类别的唯一产品数。 结果如下所示:
{
"data": {
"products": {
"groupBy": [
{
"fields": {
"category_id": 1
},
"aggregations": {
"count": 3
}
},
{
"fields": {
"category_id": 2
},
"aggregations": {
"count": 2
}
},
...
]
}
}
}
小窍门
有关何时以及如何适当地使用去重的更多指南,请参阅适当地使用去重聚合。
示例 5:使用别名
可以为聚合创建别名,以便为聚合结果提供有意义的易于理解的名称。 例如,可以将上一示例中的聚合命名为distinctProductCategoryCount,因为它通过计数独特的产品类别来更好地理解结果。
query {
products {
groupBy(fields: [category_id])
{
fields {
category_id
}
aggregations {
distinctProductCategoryCount: count(field: id, distinct: true)
}
}
}
}
结果与自定义别名类似,但更有意义:
{
"data": {
"products": {
"groupBy": [
{
"fields": {
"category_id": 1
},
"aggregations": {
"distinctProductCategoryCount": 3
}
},
{
"fields": {
"category_id": 2
},
"aggregations": {
"distinctProductCategoryCount": 2
}
},
...
]
}
}
}
示例 6:使用 having 子句
可以使用 having 子句筛选聚合结果。 例如,可以修改前面的示例,以仅返回大于两个的结果:
query {
products {
groupBy(fields: [category_id])
{
fields {
category_id
}
aggregations {
distinctProductCategoryCount: count(field: id, distinct: true, having: {
gt: 2
})
}
}
}
}
结果返回一个值,其唯一类别包含两个以上的产品:
{
"data": {
"products": {
"groupBy": [
{
"fields": {
"category_id": 1
},
"aggregations": {
"distinctProductCategoryCount": 3
}
}
]
}
}
}
限制和最佳做法
在 Microsoft Fabric 的用于 GraphQL 的 API 中使用聚合时,需要考虑一些重要的规则和限制。 遵循这些最佳做法并了解这些限制,可以生成有效的 GraphQL 聚合查询,从而生成强大的见解,同时确保可预测的结果,尤其是在使用大型数据集或实现分页时。
聚合功能对于报告和分析用例非常有用,但它确实需要仔细构建查询。 始终仔细核对groupBy字段是否与所选的输出字段一致,为了实现可预测的顺序特别是在分页时,请添加排序,并根据数据类型适当地使用去重和聚合函数。
以下部分介绍需要了解的三个关键领域: 聚合和原始项互斥, 排序分组结果需要显式排序,并 适当地使用不同的聚合。
聚合和原始项互斥
目前,不能 同时检索同一查询中已分组的摘要数据和原始项列表。 在查询中使用 groupBy 时,API 会切换到“聚合模式”,并仅返回分组结果。 此设计使响应结构明确 - 每个查询都处于“聚合模式”或“列表项模式”中,但绝不是两者。
这在实践中的工作原理:
查询 products(...) 返回以下任一项:
- 在未使用
groupBy时的单个产品列表 - 分组结果列表,其中包含聚合数据(使用
groupBy时)
请注意上面的聚合示例中,响应包含 groupBy 和聚合字段,但缺少通常 items 的产品列表。
如果同时尝试以下两种情况,会发生什么情况:
如果尝试在同一查询中请求普通项和组,GraphQL 引擎将返回错误或不允许该选择。
解决方法:
如果需要原始数据和聚合数据,请运行两个单独的查询:一个用于原始数据,另一个用于聚合数据。 此方法可让你完全控制这两个数据集,并且可以根据特定的缓存和性能要求进行优化。
对分组结果进行排序需要显式排序
除非指定显式排序,否则聚合组将按不可预知的顺序返回。 始终使用 orderBy 或 sort 参数来确保一致、有意义的结果。
为什么显式排序很重要:
-
不可预知的默认顺序:如果没有
orderBy,组可能会以任意数据库确定的顺序返回 - 分页要求:稳定排序顺序对于一致的分页行为至关重要
- 用户体验:可预测排序可改善数据解释和应用程序可靠性
必须指定排序:
-
groupBy 字段中没有主键:如果分组字段不包含主键,则必须添加
orderBy - 非唯一分组键:按类别名称或日期等字段分组时
- 分页方案:当您计划使用限制/偏移分页或游标分页时
最佳做法:
- 按照聚合值排序(例如,从最高计数开始)以获得分析见解
- 对基于类别的分组使用字母排序
- 组合多个排序条件以满足复杂的排序需求
适当地使用不同的聚合
distinct修饰符在执行聚合之前会消除重复值,确保在数据包含重复项时进行准确的计算。
常见用例:
-
唯一计数:
count(field: category_id, distinct: true)计算每个组中存在的不同类别数 -
去重后的总和:
sum(field: price, distinct: true)每个组仅添加一次每个唯一的价格 - 联接场景:当产品由于表联接出现多次时,Distinct 确保每个项目只被计数一次。
何时使用唯一:
- 你的数据包含合法重复项,这些重复项将会影响计算结果。
- 你正在处理联接的表,这些表创建了重复的行。
- 需要计算唯一值而不是总出现次数
性能注意事项:
不同的操作需要更多的处理。 仅在必要时使用,以确保数据准确性。