ユーザー定義の集計関数

プレビュー版のサポートについては、bigquery-sql-preview-support@google.com までメールでお問い合わせください。

このドキュメントでは、BigQuery でユーザー定義集計関数(UDAF)を作成、呼び出し、削除する方法について説明します。

UDAF を使用すると、コードを含む式を使用して集計関数を作成できます。UDAF は入力列を受け取り、行のグループに対して一度に計算を実行し、その結果を単一の値として返します。

SQL UDAF を作成する

このセクションでは、BigQuery で永続的または一時的な SQL UDAF を作成する方法について説明します。

永続的な SQL UDAF を作成する

永続的な SQL UDAF を作成して、複数のクエリで UDAF を再利用できます。永続的な UDAF をオーナー間で共有し、安全に呼び出すことができます。UDAF でデータの変更や外部システムとの通信を行うことはできません。また、Google Cloud Observability などのアプリケーションにログを送信することもできません。

永続的な UDAF を作成するには、TEMP キーワードまたは TEMPORARY キーワードを指定せずに CREATE AGGREGATE FUNCTION ステートメントを使用します。関数のパスにデータセットを含める必要があります。

たとえば、次のクエリは、ScaledAverage という永続的な UDAF を作成します。

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

一時的な SQL UDAF を作成する

一時的な SQL UDAF を作成することもできます。この UDAF は 1 つのクエリ、スクリプト、セッション、またはプロシージャのスコープ内にのみ存在します。

一時的な 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 エンティティが UDAF を含むプロジェクト内に存在している場合を除き、これらのエンティティの参照にはプロジェクト ID を含める必要があります。

たとえば、次のステートメントについて考えてみましょう。

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_tableproject1 に存在するため、ステートメントは成功します。ただし、別のプロジェクトから上記のステートメントを実行すると、ステートメントは失敗します。このエラーを修正するには、テーブル参照にプロジェクト 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 UDAF の結果を初期化、集計、統合、確定する 4 つの JavaScript 関数(initialStateaggregatemergefinalize)を含める必要があります。詳細については、JavaScript UDAF で許可されている SQL 型エンコードをご覧ください。

  • initialState 関数によって返される値、または aggregate 関数か merge 関数が呼び出された後に state 引数に残される値は、シリアル化可能でなければなりません。関数やシンボル フィールドなど、シリアル化できない集計データを処理する場合は、付属の serialize 関数と deserialize 関数を使用する必要があります。詳細については、JavaScript UDAF でデータをシリアル化およびシリアル化解除するをご覧ください。

永続的な JavaScript UDAF を作成する

永続的な JavaScript UDAF を作成して、複数のクエリで UDAF を再利用できます。永続的な UDAF をオーナー間で共有し、安全に呼び出すことができます。UDAF でデータの変更や外部システムとの通信を行うことはできません。また、Google Cloud Observability などのアプリケーションにログを送信することもできません。

永続的な UDAF を作成するには、TEMP キーワードまたは TEMPORARY キーワードを指定せずに CREATE AGGREGATE FUNCTION ステートメントを使用します。関数のパスにデータセットを含める必要があります。

次のクエリは、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 は 1 つのクエリ、スクリプト、セッション、プロシージャのスコープ内にのみ存在します。

一時的な 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"nullundefined など)。
  • 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 関数が実行される前に実行されます。グローバル変数は、initialStateaggregatemergefinalize の各関数の場合のように、集計グループごとに繰り返さない 1 回限りの初期化処理を行う必要がある場合に便利です。

集計状態を格納するためにグローバル変数を使用しないでください。代わりに、集計状態を、エクスポートされた関数に渡されるオブジェクトに制限します。グローバル変数は、特定の集計オペレーションに固有ではない、コストのかかるオペレーションのキャッシュにのみ使用します。

次のクエリでは、SumOfPrimes 関数で合計を計算しますが、計算には素数のみが含まれます。JavaScript 関数本体には、最初に初期化される 2 つのグローバル変数、primesmaxTested があります。また、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 ライブラリを組み込む

JavaScript UDAF は、OPTIONS 句の library オプションを使用して拡張できます。このオプションを使用すると、JavaScript UDAF の外部コード ライブラリを指定し、import 宣言でそれらのライブラリをインポートできます。

次の例では、bar.js のコードは、JavaScript UDAF の関数本体のすべてのコードで使用できます。

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 である JavaScript UDF とは異なり、JavaScript UDAF の関数本体は、いくつかのエクスポートされた組み込み関数を含む JavaScript モジュールであり、これらの関数が集計プロセスのさまざまな段階で呼び出されます。これらの組み込み関数の一部は必須ですが、他の関数は省略可能です。JavaScript 関数を追加することもできます。

必須の JavaScript 集計関数

JavaScript 関数を含めることはできますが、JavaScript 関数本体には、次のエクスポート可能な JavaScript 関数を含める必要があります。

  • initialState([nonAggregateParam]): まだ行が集計されていない集計状態を表す JavaScript オブジェクトを返します。

  • aggregate(state, aggregateParam[, ...][, nonAggregateParam]): 1 行のデータが集計され、集計結果を保存するために状態が更新されます。値は返しません。

  • 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): (serialize 関数でシリアル化された)serializedState を、serializeaggregatemergefinalize の各関数に渡すことができる集計状態にシリアル化解除します。

組み込みの 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 の ObjectArray、または 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 は、組み込みの集計関数と同じ方法で呼び出すことができます。詳細については、集計関数呼び出しをご覧ください。関数のパスにデータセットを含める必要があります。

次の例では、クエリで 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 値を含む行を無視または含める

JavaScript UDAF が IGNORE NULLS 引数で呼び出されると、BigQuery は、集計引数が NULL と評価される行を自動的にスキップします。このような行は集計から完全に除外され、JavaScript の aggregate 関数には渡されません。RESPECT NULLS 引数が指定されている場合、NULL フィルタリングは無効になり、NULL 値に関係なくすべての行が JavaScript UDAF に渡されます。

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 を削除するには、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 はルーティンの一種です。データセット内のすべてのルーティンを一覧表示するには、ルーティンを一覧表示をご覧ください。

パフォーマンスのヒント

クエリのパフォーマンスを改善するには、次の点に注意してください。

  • 入力を事前にフィルタしてください。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 の割り当ての詳細については、割り当てと上限をご覧ください。