使用者定義的匯總函式

BigQuery 的使用者定義匯總函式 (UDAF) 可讓您使用 SQL 或 JavaScript 程式碼,建構自訂匯總邏輯。您可以將輸入資料欄視為一個群組來處理,一次對多個資料列執行特殊計算,並以單一值的形式傳回結果。

建立 SQL UDAF

本節說明在 BigQuery 中建立永久或暫時 SQL UDAF 的各種方法。

建立永久 SQL UDAF

您可以建立永久 SQL UDAF,在多項查詢中重複使用。在擁有者之間共用時,呼叫永久 UDAF 是安全的。UDAF 無法變更資料、與外部系統通訊,或將記錄傳送至 Google Cloud Observability 或類似應用程式。

如要建立永久 UDAF,請使用CREATE AGGREGATE FUNCTION 陳述式,但不使用 TEMP 或 TEMPORARY 關鍵字。您必須在函式路徑中加入資料集。

舉例來說,下列查詢會建立名為 ScaledAverage 的永久 UDAF:

CREATE AGGREGATE FUNCTION myproject.mydataset.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  AVG(dividend / divisor)
);

建立臨時 SQL UDAF

您可以建立暫時性的 SQL UDAF,也就是只存在於單一查詢、指令碼、工作階段或程序範圍內的 UDAF。

如要建立暫時 UDAF,請使用 CREATE AGGREGATE FUNCTION 陳述式和 TEMP 或 TEMPORARY 關鍵字。

舉例來說,下列查詢會建立名為 ScaledAverage 的臨時 UDAF:

CREATE TEMP AGGREGATE FUNCTION ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  AVG(dividend / divisor)
);

使用匯總和非匯總參數

您可以建立同時包含匯總和非匯總參數的 SQL UDAF。

UDAF 通常會匯總群組中所有資料列的函式參數。不過,您可以使用 NOT AGGREGATE 關鍵字,將函式參數指定為非匯總。

非匯總函式參數是純量函式參數,群組中所有資料列的值都相同。有效的非匯總函式參數必須是常值。在 UDAF 定義中,匯總函式參數只能做為匯總函式呼叫的函式引數。非匯總函式參數的參照可以出現在 UDAF 定義中的任何位置。

舉例來說,下列函式包含名為 dividend 的匯總參數,以及名為 divisor 的非匯總參數:

-- Create the function.
CREATE TEMP AGGREGATE FUNCTION ScaledSum(
  dividend FLOAT64,
  divisor FLOAT64 NOT AGGREGATE)
RETURNS FLOAT64
AS (
  SUM(dividend) / divisor
);

在函式主體中使用預設專案

在 SQL UDAF 的主體中,任何對 BigQuery 實體 (例如資料表或檢視表) 的參照都必須包含專案 ID,除非該實體與 UDAF 位於同一個專案。

例如,請看以下陳述式:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM dataset_a.my_table )
);

如果您在 project1 專案中執行上述陳述式,陳述式會成功,因為 my_table 存在於 project1 中。不過,如果您從其他專案執行上述陳述式,陳述式會失敗。如要修正錯誤,請在資料表參照中加入專案 ID:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM project1.dataset_a.my_table )
);

您也可以參照其他專案或資料集中的實體,而非建立函式的專案或資料集:

CREATE AGGREGATE FUNCTION project1.dataset_a.ScaledAverage(
  dividend FLOAT64,
  divisor FLOAT64)
RETURNS FLOAT64
AS (
  ( SELECT AVG(dividend / divisor) FROM project2.dataset_c.my_table )
);

建立 JavaScript UDAF

本節說明在 BigQuery 中建立 JavaScript UDAF 的各種方式。建立 JavaScript UDAF 時,請遵守下列規則:

  • JavaScript UDAF 的主體必須是以引號括住的字串文字,代表 JavaScript 程式碼。如要進一步瞭解可使用的不同類型引號字串文字,請參閱「引號文字格式」。

  • 僅允許特定類型編碼。詳情請參閱「JavaScript UDAF 允許的 SQL 類型編碼」。

  • JavaScript 函式主體必須包含四個 JavaScript 函式,用於初始化、匯總、合併及完成 JavaScript UDAF 的結果 (initialState、aggregate、merge 和 finalize)。詳情請參閱「必要的 JavaScript 匯總函式」。

  • initialState 函式傳回的任何值,或在呼叫 aggregate 或 merge 函式後留在 state 引數中的任何值,都必須可序列化。如要使用不可序列化的匯總資料 (例如函式或符號欄位),則必須使用內含的 serialize 和 deserialize 函式。詳情請參閱「在 JavaScript UDAF 中序列化及反序列化資料」。

建立永久 JavaScript UDAF

您可以建立永久 JavaScript UDAF,在多項查詢中重複使用。在擁有者之間共用時,呼叫永久 UDAF 是安全的。UDAF 無法變更資料、與外部系統通訊,或將記錄傳送至 Google Cloud Observability 或類似應用程式。

如要建立永久 UDAF,請使用 CREATE AGGREGATE FUNCTION 陳述式,但不使用 TEMP 或 TEMPORARY 關鍵字。您必須在函式路徑中加入資料集。

下列查詢會建立名為 SumPositive 的永久 JavaScript UDAF:

CREATE OR REPLACE AGGREGATE FUNCTION my_project.my_dataset.SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, -1.0, 3.0, -3.0, 5.0, -5.0]) AS x)
SELECT my_project.my_dataset.SumPositive(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 9.0 |
 *-----*/

建立暫時 JavaScript UDAF

您可以建立暫時性的 JavaScript UDAF,也就是說,UDAF 只存在於單一查詢、指令碼、工作階段或程序的範圍內。

如要建立暫時 UDAF,請使用 CREATE AGGREGATE FUNCTION 陳述式和 TEMP 或 TEMPORARY 關鍵字。

下列查詢會建立名為 SumPositive 的臨時 JavaScript UDAF:

CREATE TEMP AGGREGATE FUNCTION SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, -1.0, 3.0, -3.0, 5.0, -5.0]) AS x)
SELECT SumPositive(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 9.0 |
 *-----*/

在 JavaScript UDAF 中加入非匯總參數

您可以建立同時具有匯總和非匯總參數的 JavaScript UDAF。

UDAF 通常會匯總群組中所有資料列的函式參數。不過,您可以使用 NOT AGGREGATE 關鍵字,將函式參數指定為非匯總。

非匯總函式參數是純量函式參數,群組中所有資料列的值都相同。有效的非匯總函式參數必須是常值。在 UDAF 定義中,匯總函式參數只能做為匯總函式呼叫的函式引數。非匯總函式參數的參照可以出現在 UDAF 定義中的任何位置。

在以下範例中,JavaScript UDAF 包含名為 s 的匯總參數,以及名為 delimiter 的非匯總參數:

CREATE TEMP AGGREGATE FUNCTION JsStringAgg(
  s STRING,
  delimiter STRING NOT AGGREGATE)
RETURNS STRING
LANGUAGE js
AS r'''

  export function initialState() {
    return {strings: []}
  }
  export function aggregate(state, s) {
    state.strings.push(s);
  }
  export function merge(state, partialState) {
    state.strings = state.strings.concat(partialState.strings);
  }
  export function finalize(state, delimiter) {
    return state.strings.join(delimiter);
  }

''';

-- Call the JavaScript UDAF.
WITH strings AS (
  SELECT * FROM UNNEST(["aaa", "bbb", "ccc", "ddd"]) AS values)
SELECT JsStringAgg(values, '.') AS result FROM strings;

/*-----------------*
 | result          |
 +-----------------+
 | aaa.bbb.ccc.ddd |
 *-----------------*/

在 JavaScript UDAF 中序列化及反序列化資料

BigQuery 必須序列化 initialState 函式傳回的任何物件,或在呼叫 aggregate 或 merge 函式後留在 state 引數中的任何物件。如果所有欄位都符合下列任一條件,BigQuery 支援序列化物件:

  • JavaScript 原始值 (例如:2、"abc"、null、undefined)。
  • BigQuery 支援序列化所有欄位值的 JavaScript 物件。
  • BigQuery 支援序列化所有元素的 JavaScript 陣列。

下列傳回值可序列化:

export function initialState() {
  return {a: "", b: 3, c: null, d: {x: 23} }
}
export function initialState() {
  return {value: 2.3};
}

下列傳回值無法序列化:

export function initialState() {
  return {
    value: function() {return 6;}
  }
}
export function initialState() {
  return 2.3;
}

如要使用不可序列化的匯總狀態,JavaScript UDAF 必須包含 serialize 和 deserialize 函式。serialize 函式會將匯總狀態轉換為可序列化物件;deserialize 函式則會將可序列化物件轉換回匯總狀態。

在以下範例中,外部程式庫會使用介面計算總和:

export class SumAggregator {
 constructor() {
   this.sum = 0;
 }
 update(value) {
   this.sum += value;
 }
 getSum() {
   return this.sum;
 }
}

下列查詢不會執行,因為 SumAggregator 類別物件中含有函式,因此無法序列化為 BigQuery。

CREATE TEMP AGGREGATE FUNCTION F(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  class SumAggregator {
   constructor() {
     this.sum = 0;
   }

   update(value) {
     this.sum += value;
   }

   getSum() {
     return this.sum;
   }
  }

  export function initialState() {
   return new SumAggregator();
  }

  export function aggregate(agg, value) {
   agg.update(value);
  }

  export function merge(agg1, agg2) {
   agg1.update(agg2.getSum());
  }

  export function finalize(agg) {
   return agg.getSum();
  }

''';

--Error: getSum is not a function
SELECT F(x) AS results FROM UNNEST([1,2,3,4]) AS x;

如果您在上述查詢中加入 serialize 和 deserialize 函式,查詢就會執行,因為 SumAggregator 類別物件會轉換為可由 BigQuery 序列化的物件,然後再轉換回 SumAggregator 類別物件。

CREATE TEMP AGGREGATE FUNCTION F(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  class SumAggregator {
   constructor() {
     this.sum = 0;
   }

   update(value) {
     this.sum += value;
   }

   getSum() {
     return this.sum;
   }
  }

  export function initialState() {
   return new SumAggregator();
  }

  export function aggregate(agg, value) {
   agg.update(value);
  }

  export function merge(agg1, agg2) {
   agg1.update(agg2.getSum());
  }

  export function finalize(agg) {
   return agg.getSum();
  }

  export function serialize(agg) {
   return {sum: agg.getSum()};
  }

  export function deserialize(serialized) {
   var agg = new SumAggregator();
   agg.update(serialized.sum);
   return agg;
  }

''';

SELECT F(x) AS results FROM UNNEST([1,2,3,4]) AS x;

/*-----------------*
 | results         |
 +-----------------+
 | 10.0            |
 *-----------------*/

如要進一步瞭解序列化函式,請參閱「選用的 JavaScript 序列化函式」。

在 JavaScript UDAF 中加入全域變數和自訂函式

JavaScript 函式主體可包含自訂 JavaScript 程式碼,例如 JavaScript 全域變數和自訂函式。

JavaScript 載入 BigQuery 後,系統會先執行全域變數,再執行 initialState 函式。如果您需要執行一次性初始化工作,且不應為每個匯總群組重複執行,則全域變數可能會很有用,就像 initialState、aggregate、merge 和 finalize 函式一樣。

請勿使用全域變數儲存匯總狀態。請改為將匯總狀態限制為傳遞至匯出函式的物件。請只使用全域變數來快取昂貴的作業,且這些作業不屬於任何特定匯總作業。

在下列查詢中,SumOfPrimes 函式會計算總和,但只有質數會納入計算。在 JavaScript 函式主體中,有兩個全域變數 primes 和 maxTested,會先初始化。此外,還有一個名為 isPrime 的自訂函式,可檢查數字是否為質數。

CREATE TEMP AGGREGATE FUNCTION SumOfPrimes(x INT64)
RETURNS INT64
LANGUAGE js
AS r'''

  var primes = new Set([2]);
  var maxTested = 2;

  function isPrime(n) {
    if (primes.has(n)) {
      return true;
    }
    if (n <= maxTested) {
      return false;
    }
    for (var k = 2; k < n; ++k) {
      if (!isPrime(k)) {
        continue;
      }
      if ((n % k) == 0) {
        maxTested = n;
        return false;
      }
    }
    maxTested = n;
    primes.add(n);
    return true;
  }

  export function initialState() {
    return {sum: 0};
  }

  export function aggregate(state, x) {
    x = Number(x);
    if (isPrime(x)) {
      state.sum += x;
    }
  }

  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }

  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([10, 11, 13, 17, 19, 20]) AS x)
SELECT SumOfPrimes(x) AS sum FROM numbers;

/*-----*
 | sum |
 +-----+
 | 60  |
 *-----*/

加入 JavaScript 程式庫

您可以使用 OPTIONS 子句中的 library 選項,擴充 JavaScript UDAF。這個選項可讓您為 JavaScript UDAF 指定外部程式碼程式庫,然後使用 import 宣告匯入這些程式庫。

在以下範例中,JavaScript UDAF 函式主體中的任何程式碼,都能使用 bar.js 中的程式碼:

CREATE TEMP AGGREGATE FUNCTION JsAggFn(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
OPTIONS (library = ['gs://foo/bar.js'])
AS r'''

  import doInterestingStuff from 'bar.js';

  export function initialState() {
    return ...
  }
  export function aggregate(state, x) {
    var result = doInterestingStuff(x);
    ...
  }
  export function merge(state, partial_state) {
    ...
  }
  export function finalize(state) {
    return ...;
  }

''';

必要的 JavaScript 結構

JavaScript UDF 的函式主體是任意形式的 JavaScript,會針對每個資料列執行。JavaScript UDAF 的函式主體則是 JavaScript 模組,包含一些內建的匯出函式,會在匯總程序的各個階段叫用。部分內建函式為必要,其餘則為選用。您也可以新增自己的 JavaScript 函式。

必要的 JavaScript 匯總函式

您可以加入自己的 JavaScript 函式,但 JavaScript 函式主體必須包含下列可匯出的 JavaScript 函式:

  • initialState([nonAggregateParam]):傳回 JavaScript 物件,代表尚未匯總任何資料列的匯總狀態。

  • aggregate(state, aggregateParam[, ...][, nonAggregateParam]):匯總一列資料,並更新狀態來儲存匯總結果。不傳回值。

  • merge(state, partialState, [nonAggregateParam]):將匯總狀態 partialState 合併至匯總狀態 state。當引擎平行匯總不同資料區段,且需要合併結果時,就會使用這個函式。不會傳回值。

  • finalize(finalState, [nonAggregateParam]):在指定最終匯總狀態 finalState 的情況下,傳回匯總函式的最終結果。

如要進一步瞭解必要函式,請參閱「JavaScript UDAF 中的必要函式」。

選用的 JavaScript 序列化函式

如要使用不可序列化的匯總狀態,JavaScript UDAF 必須提供 serialize 和 deserialize 函式。serialize 函式會將匯總狀態轉換為 BigQuery 可序列化物件;deserialize 函式會將 BigQuery 可序列化物件轉換回匯總狀態。

  • serialize(state):傳回可序列化的物件,其中包含匯總狀態的資訊,可透過 deserialize 函式反序列化。

  • deserialize(serializedState):將 serializedState (先前由 serialize 函式序列化) 反序列化為可傳遞至 serialize、aggregate、merge 或 finalize 函式的匯總狀態。

如要進一步瞭解內建的 JavaScript 序列化函式,請參閱「JavaScript UDAF 的序列化函式」。

如要瞭解如何使用 JavaScript UDAF 序列化及反序列化資料,請參閱「在 JavaScript UDAF 中序列化及反序列化資料」。

JavaScript UDAF 中允許的 SQL 類型編碼

在 JavaScript UDAF 中,下列支援的 GoogleSQL 資料類型代表 JavaScript 資料類型,如下所示:

GoogleSQL
資料類型
JavaScript
資料類型
附註
ARRAY Array 不支援陣列的陣列。如要突破這項限制,請使用 Array<Object<Array>> (JavaScript) 和 ARRAY<STRUCT<ARRAY>> (GoogleSQL) 資料類型。
BIGNUMERIC Number 或 String 與 NUMERIC 相同。
BOOL Boolean
BYTES Uint8Array
DATE Date
FLOAT64 Number
INT64 BigInt
JSON 多種類型 GoogleSQL JSON 資料類型可轉換為 JavaScript Object、Array 或其他 GoogleSQL 支援的 JavaScript 資料類型。
NUMERIC Number 或 String 如果 NUMERIC 值可以完全表示為 IEEE 754 浮點值 (範圍 [-253, 253]),且沒有小數部分,則會編碼為 Number 資料類型,否則會編碼為 String 資料類型。
STRING String
STRUCT Object 每個 STRUCT 欄位都是 Object 資料類型中的具名屬性。不支援未命名的 STRUCT 欄位。
TIMESTAMP Date Date 包含微秒欄位,微秒分數為 TIMESTAMP。

呼叫 UDAF

本節說明在 BigQuery 建立永久或暫時 UDAF 後,呼叫 UDAF 的各種方式。

呼叫永久 UDAF

您可以呼叫永久 UDAF,方法與呼叫內建匯總函式相同。詳情請參閱「匯總函式呼叫」。您必須在函式路徑中加入資料集。

在以下範例中,查詢會呼叫名為 WeightedAverage 的永久 UDAF:

SELECT my_project.my_dataset.WeightedAverage(item, weight, 2) AS weighted_average
FROM (
  SELECT 1 AS item, 2.45 AS weight UNION ALL
  SELECT 3 AS item, 0.11 AS weight UNION ALL
  SELECT 5 AS item, 7.02 AS weight
);

系統會產生包含下列結果的表格:

/*------------------*
 | weighted_average |
 +------------------+
 | 4.5              |
 *------------------*/

呼叫臨時 UDAF

您可以呼叫暫時 UDAF,方法與呼叫內建匯總函式相同。詳情請參閱「匯總函式呼叫」。

暫時函式必須包含在多重陳述式查詢或程序中,且該查詢或程序包含 UDAF 函式呼叫。

在以下範例中,查詢會呼叫名為 WeightedAverage 的臨時 UDAF:

CREATE TEMP AGGREGATE FUNCTION WeightedAverage(...)

-- Temporary UDAF function call
SELECT WeightedAverage(item, weight, 2) AS weighted_average
FROM (
  SELECT 1 AS item, 2.45 AS weight UNION ALL
  SELECT 3 AS item, 0.11 AS weight UNION ALL
  SELECT 5 AS item, 7.02 AS weight
);

系統會產生包含下列結果的表格:

/*------------------*
 | weighted_average |
 +------------------+
 | 4.5              |
 *------------------*/

忽略或納入含有 NULL 值的資料列

使用 IGNORE NULLS 引數呼叫 JavaScript UDAF 時,BigQuery 會自動略過任何匯總引數評估為 NULL 的資料列。這類資料列會完全從匯總中排除,不會傳遞至 JavaScript aggregate 函式。如果提供 RESPECT NULLS 引數,系統會停用 NULL 篩選功能,並將每個資料列傳遞至 JavaScript UDAF,無論 NULL 值為何。

如果未提供 IGNORE NULLS 或 RESPECT NULLS 引數,預設引數為 IGNORE NULLS。

以下範例說明預設的 NULL 行為、IGNORE NULLS 行為和 RESPECT NULLS 行為:

CREATE TEMP AGGREGATE FUNCTION SumPositive(x FLOAT64)
RETURNS FLOAT64
LANGUAGE js
AS r'''

  export function initialState() {
    return {sum: 0}
  }
  export function aggregate(state, x) {
    if (x == null) {
      // Use 1000 instead of 0 as placeholder for null so
      // that NULL values passed are visible in the result.
      state.sum += 1000;
      return;
    }
    if (x > 0) {
      state.sum += x;
    }
  }
  export function merge(state, partialState) {
    state.sum += partialState.sum;
  }
  export function finalize(state) {
    return state.sum;
  }

''';

-- Call the JavaScript UDAF.
WITH numbers AS (
  SELECT * FROM UNNEST([1.0, 2.0, NULL]) AS x)
SELECT
  SumPositive(x) AS sum,
  SumPositive(x IGNORE NULLS) AS sum_ignore_nulls,
  SumPositive(x RESPECT NULLS) AS sum_respect_nulls
FROM numbers;

/*-----+------------------+-------------------*
 | sum | sum_ignore_nulls | sum_respect_nulls |
 +-----+------------------+-------------------+
 | 3.0 | 3.0              | 1003.0            |
 *-----+------------------+-------------------*/

刪除 UDAF

本節說明在 BigQuery 建立永久或暫時 UDAF 後,刪除 UDAF 的各種方式。

刪除永久 UDAF

如要刪除永久 UDAF,請使用 DROP FUNCTION 陳述式。您必須在函式路徑中加入資料集。

在以下範例中,查詢會刪除名為 WeightedAverage 的永久 UDAF:

DROP FUNCTION IF EXISTS my_project.my_dataset.WeightedAverage;

刪除暫時 UDAF

如要刪除暫時 UDAF,請使用 DROP FUNCTION 陳述式。

在以下範例中,查詢會刪除名為 WeightedAverage 的臨時 UDAF:

DROP FUNCTION IF EXISTS WeightedAverage;

暫時性 UDAF 會在查詢完成時立即失效。除非您想提早從多重陳述式查詢或程序中移除 UDAF,否則不需要刪除 UDAF。

列出 UDAF

UDAF 是一種常式。如要列出資料集中的所有常式,請參閱「列出常式」。

效能提示

如要提升查詢效能,請考慮下列事項:

  • 預先篩選輸入內容。在 JavaScript 中處理資料的成本高於 SQL,因此建議您盡可能先在 SQL 中篩選輸入內容。

    下列查詢的效率較低,因為它在 UDAF 呼叫中使用 x > 0 篩選輸入內容:

    SELECT JsFunc(x) FROM t;
    

    下列查詢在呼叫 UDAF 前,會先使用 WHERE x > 0 預先篩選輸入內容,因此效率較高:

    SELECT JsFunc(x) FROM t WHERE x > 0;
    
  • 盡可能使用內建匯總函式,而非 JavaScript。在 JavaScript 中重新實作內建匯總函式,速度會比呼叫執行相同作業的內建匯總函式慢。

    下列查詢會實作 UDAF,因此效率較低:

    SELECT SumSquare(x) FROM t;
    

    下列查詢更有效率,因為它實作了內建函式,可產生與先前查詢相同的結果:

    SELECT SUM(x*x) FROM t;
    
  • JavaScript UDAF 適用於無法透過內建函式表示的複雜匯總作業。

  • 有效率地使用記憶體。JavaScript 處理環境為每項查詢提供的記憶體有限。如果 JavaScript UDAF 查詢累積過多本機狀態,可能會因記憶體耗盡而失敗。請特別注意,盡可能縮減匯總狀態物件的大小,並避免匯總狀態累積大量資料列。

    下列查詢效率不佳,因為處理的資料列數量變多時,aggregate 函式會使用無限量的記憶體。

    export function initialState() {
      return {rows: []};
    }
    export function aggregate(state, x) {
      state.rows.push(x);
    }
    ...
    
  • 盡可能使用分區資料表。相較於非分區資料表,JavaScript UDAF 在查詢分區資料表時通常更有效率,因為分區資料表會將資料儲存在許多較小的檔案中,因此可提高平行處理能力。

限制

  • UDAF 的限制與 UDF 相同。詳情請參閱「UDF 限制」。

  • 只有常值、查詢參數和指令碼變數,可以做為 UDAF 的非匯總引數傳入。

  • JavaScript UDAF 函式呼叫不支援使用 ORDER BY 子句。

    SELECT MyUdaf(x ORDER BY y) FROM t; -- Error: ORDER BY is unsupported.
    

定價

UDAF 採用標準 BigQuery 定價模式計費。

配額與限制

UDAF 的配額和限制與 UDF 相同。如要瞭解 UDF 配額,請參閱「配額與限制」。