GraphQL 集計を使用すると、SQL GROUP BY や集計関数と同様に、API を介してカウント、合計、平均などの集計データを直接取得できます。 クライアントですべてのレコードをフェッチして概要を計算する代わりに、特定のフィールドでデータをグループ化し、集計値を計算するようにサーバーに依頼できます。 これは、レポートや分析を作成する場合に役立ちます。たとえば、カテゴリごとの製品数や作成者ごとの投稿の平均評価を 1 回のクエリで取得する場合などです。
集計クエリ はグループ化された結果を返します。各結果は、特定のフィールド値を共有するレコードのグループと、そのグループの計算された集計メトリックを表します。 このドキュメントでは、架空の e コマース スキーマで GraphQL 集計機能を使用する方法、抽出できるデータの種類、クエリの例、注意すべき重要な制限と動作について説明します。
スキーマの例: E コマース ストア
このスキーマでは、製品はカテゴリに属しています。 各 Product
には、価格と評価 (集計する数値) などのフィールドと、(カテゴリ フィールドによる) Category
との関係があります。
Category
には名前があります。 このスキーマを使用して、集計クエリを示します。
たとえば、簡略化された GraphQL 型は次のようになります。
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
機能と集計機能の使用に焦点を当ててみましょう。
集計クエリを使用する理由
GraphQL で集計クエリを使用すると、手動で処理することなく、データに関する質問にすばやく答えることができます。 たとえば、次のような分析情報を抽出できます。
- 合計数: "各カテゴリに含まれる製品の数" など
- 合計と平均: "カテゴリごとの総収益は何ですか?" や "カテゴリ別の製品の平均評価" などです。
- 最小値/最大値: " 各カテゴリで最も高い価格と最低価格のアイテムは何ですか?
- 個別の値: "お客様の出身の一意の都市の数" や "すべてのブログ投稿で使用されている個別のタグを一覧表示する" などです。
アプリケーションですべてのレコードを取得し、これらの分析情報を計算する代わりに、集計クエリを使用してサーバーで実行できます。 これにより、データ転送が削減され、グループ化と計算にデータベースの最適化が使用されます。
集計クエリの基本
集計を実行するには、GraphQL クエリで groupBy
引数を指定してデータをグループ化する方法を定義し、結果の集計フィールド (カウントや合計など) を要求します。 応答には、グループ化されたレコードの一覧が含まれており、それぞれにグループのキー値と集計されたメトリックが含まれます。
例 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])
は、category_id
フィールドで製品をグループ化するように Fabric GraphQL エンジンに指示します。 - 結果の選択では、
id
フィールドにgroup
とcount
集計を要求します。id
カウントすると、そのグループ内の製品が効果的にカウントされます。
結果は次のようになります。 応答内の各項目は、1 つのカテゴリ グループを表します。
groupBy
オブジェクトには、グループ化キーが含まれています。 ここには category_id
値が含まれており、 count { id }
はそのカテゴリ内の製品の数を示します。
{
"data": {
"products": {
"groupBy": [
{
"fields": {
"category_id": 1
},
"aggregations": {
"count": 3
}
},
{
"fields": {
"category_id": 2
},
"aggregations": {
"count": 2
}
},
...
]
}
}
}
この出力は、カテゴリ 1 に 3 つの製品があり、カテゴリ 2 に 2 があることを示しています。
例 2: 合計と平均
1 つのクエリで複数の集計メトリックを要求できます。 カテゴリごとに、すべての製品の合計価格と平均評価が必要だとします。
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
句でフィルター処理できます。 たとえば、前の例を変更して、2 より大きい結果のみを返すことができます。
query {
products {
groupBy(fields: [category_id])
{
fields {
category_id
}
aggregations {
distinctProductCategoryCount: count(field: id, distinct: true, having: {
gt: 2
})
}
}
}
}
結果は、2 つ以上の製品を含む唯一のカテゴリを持つ 1 つの値を返します。
{
"data": {
"products": {
"groupBy": [
{
"fields": {
"category_id": 1
},
"aggregations": {
"distinctProductCategoryCount": 3
}
}
]
}
}
}
使用可能な集計関数
使用できる関数は実装によって異なりますが、一般的な集計操作は次のとおりです。
- count – グループ内のレコードの数 (またはフィールドの null 以外の値)。
- sum – 数値フィールド内のすべての値の合計。
- avg – 数値フィールドの値の平均 (平均)。
- min – フィールドの最小値。
- max – フィールドの最大値。
GraphQL API では、これらは通常、 count(field: id)
、 sum(field: price)
などの例に示すように、関数名とターゲット フィールドを指定することによって要求されます。各関数は、適用された 1 つ以上のフィールドを選択できるオブジェクトを返します。 たとえば、 sum(field: price)
はそのグループの価格フィールドの合計を与え、 count(field: id)
は実質的に項目の数である ID の数を示します。
注
現在、 count
、 sum
、 avg
、 min
、 max
などの集計操作は、 数値 フィールドまたは定量的フィールドでのみ機能します。 たとえば、整数、浮動小数点数、日付などです。 テキスト フィールドでは使用できません。 たとえば、文字列の "average" を取得することはできません。 他の型 (連結や辞書の最小/最大など、将来可能な関数のテキストなど) で集計を実行するサポートは計画されていますが、まだ使用できません。
制限事項とベスト プラクティス
GraphQL で集計を使用する場合、考慮すべき重要な規則と制限事項がいくつかあります。 これにより、クエリが有効であること、および結果が予測可能であることを確認できます (特に、結果をページ分割する場合)。
集計項目と未加工アイテムは相互に排他的です。 現時点では、グループ化されたサマリー データと、同じクエリ内のアイテムの生リストの両方を 同時に取得することはできません。 コレクションの
groupBy
集計クエリは、通常の項目リストではなく、グループ化されたデータを返します。 たとえば、API では、products(...)
クエリは、groupBy
が使用されていない場合は製品の一覧 を返すか 、groupBy
が使用されている場合はグループ化された結果の一覧を返しますが、一度に両方を返すわけではありません。 上記の集計例では、group
フィールドと集計フィールドが表示されますが、通常のitems
製品の一覧は表示されません。 1 つのクエリ内のグループと共に通常の項目を要求しようとすると、GraphQL エンジンはエラーを返すか、その選択を許可しません。 生データと集計データの両方が必要な場合は、2 つの個別のクエリを実行するか、この制限を解除する可能性のある将来の更新を待つ必要があります。 この設計では、応答構造を明確に保つため、クエリは "集計モード" または "リスト アイテム モード" になります。グループ化された結果の並べ替え (
orderBy
と主キー): 集計されたグループを取得する場合、明示的な並べ替え順序を指定しない限り、グループが返される順序は保証されません。 集計クエリでorderBy
またはsort
引数を使用して、特にグループ化キーが本質的に一意でない場合や、明らかな既定の順序がない場合に、結果でグループを並べ替える方法を定義することを強くお勧めします。 たとえば、category
という名前でグループ化した場合、結果はカテゴリ名のアルファベット順、最も多い順、または挿入順で返すべきでしょうか?orderBy
がないと、データベースによって決定された任意の順序でグループ化が返される場合があります。 さらに、制限/オフセットまたはカーソルの改ページ位置を使用してグループ化された結果を改ページ処理する場合は、改ページ位置を正しく機能させるために安定した並べ替え順序が必要です。 多くのシステムでは、主キーがそのキーによって各グループを自然に識別できるようにするグループ化の一部である場合、結果は既定で並べ替えられます。 ただし、 groupBy フィールドに主キーが存在しない場合は、一貫性のある順序を取得するためにorderBy
句を指定する必要があります。個別の集計の使用法: 集計内の重複する値を無視する必要がある場合は、 個別 の修飾子を使用する必要があります。 たとえば、
count(field: category_id, distinct: true)
は一意のカテゴリをカウントします。 これは、 このグループ内の個別の X の数を知りたい場合に便利です。 個別は合計または平均にも適用できます。たとえば、sum (field: price, distinct: true)
はグループごとに 1 回だけ一意の価格値を加算します。 このケースはあまり一般的ではありませんが、完全性のために用意されています。 重複がデータを歪めるシナリオでは、個別の集計を使用します。 たとえば、結合によって製品が複数回出現する可能性がある場合は、個別のカウントによって 1 回だけカウントされます。
これらの制限とガイドラインを念頭に置くことで、強力な分析情報を得る効果的な GraphQL 集計クエリを構築できます。 集計機能はレポートと分析のユース ケースに役立ちますが、クエリを慎重に構成する必要があります。
groupBy
フィールドが選択した出力フィールドと一致していることを常に再確認し、特にページ分割時に予測可能な順序の並べ替えを追加し、データ型に対して個別および集計関数を適切に使用します。