動的テーブルの増分更新は、基本的な集約関数 (COUNT、SUM、MIN/MAX、COUNT DISTINCT) に加え、このトピックに記載されている拡張関数もサポートしています。
関数のサポート一覧
| 関数 | 説明 | サポート対象バージョン |
|---|---|---|
| ROW_NUMBER / RANK | TopN 処理用のウィンドウ関数です。パーティション内で行に順位を付け、上位 N 件のレコードをフィルタリングします。サポートされるのは ROW_NUMBER と RANK のみです。auto_refresh_mode を auto に設定すると、自動の増分更新を有効化できます。 |
V4.2 以降 |
| COUNT, SUM, MIN/MAX, COUNT DISTINCT | 基本的な集約関数 | すべてのバージョン |
| hg_id_encoding_int4 / hg_id_encoding_int8 | text 型の UID を int32 または int64 にマッピングし、マッピング内容をユーザーマッピングテーブルに自動的に書き込みます。RoaringBitmap と組み合わせて、長期間にわたるユニークビジター (UV) の算出によく使用されます。 | V4.1 以降 |
| min_by / max_by | ある列の値が最小または最大となる行から、別の列の値を返します。 | V4.0 以降 |
| RB_BUILD_AGG | int32 または int64 列から RoaringBitmap を構築します。 | V3.1 以降 |
| string_agg | デリミタを使用して列の値を文字列に連結します。string_agg([distinct]) 構文を使用するには V3.1.10 以降が必要です。 |
V3.1 以降 |
| array_agg | 列の値を配列に集約します。array_agg([distinct]) 構文を使用するには V3.1.10 以降が必要です。 |
V3.1 以降 |
| any_value | GROUP BY クエリにおいて、各グループから非決定的な値を返します。int 型と bytea 型のみサポートします。 |
V3.1.5 以降 |
ROW_NUMBER / RANK
Hologres V4.2 以降では、動的テーブルの増分更新で ROW_NUMBER() と RANK() のウィンドウ関数がサポートされています。これらの関数を使用して行をパーティション分割して順位付けし、各パーティションから上位 N 件のレコードをフィルタリングできます。これは、リアルタイムな TopN のマテリアライズで一般的なパターンです。
構文
SELECT [column_list]
FROM (
SELECT [column_list],
ROW_NUMBER() OVER ([PARTITION BY partition_column[, ...]]
ORDER BY order_column [ASC|DESC][, ...]) AS rownum
FROM table_name)
WHERE rownum <= N [AND conditions]
引数:
-
PARTITION BY partition_column:任意。順位付けの前に、行をパーティションにグループ化します。 -
ORDER BY order_column [ASC|DESC]:必須。各パーティション内の順位付けの順序を定義します。 -
rownum <= N:必須。各パーティションから上位 N 行のみを保持します。
注意事項
-
Hologres V4.2 以降でサポートされています。
-
サポートされるのは
ROW_NUMBER()とRANK()のみです。DENSE_RANK、LAG、LEADなど、その他のウィンドウ関数はサポートされていません。 -
auto_refresh_modeをautoに設定すると、Hologres は動的テーブルの増分モードを自動的に導出します。
例
次の例では、商品ごとに注文金額の上位 3 件を維持し、5 分ごとに増分更新される動的テーブルを作成します。
-- ソーステーブルを作成します
CREATE TABLE orders (
order_id bigint,
product_id bigint,
amount bigint
);
INSERT INTO orders
SELECT i, i % 100, (random() * 1000000)::bigint
FROM generate_series(1, 10000) i;
-- TopN 用の動的テーブルを作成します
CREATE DYNAMIC TABLE top3_orders
WITH (
freshness = '5 minutes',
auto_refresh_mode = 'incremental'
) AS
SELECT order_id, product_id, amount
FROM (
SELECT order_id, product_id, amount,
ROW_NUMBER() OVER (PARTITION BY product_id ORDER BY amount DESC) AS rownum
FROM orders)
WHERE rownum <= 3;
-- 特定の商品に対する結果をクエリします
SELECT * FROM top3_orders WHERE product_id = 1;
hg_id_encoding_int4 / hg_id_encoding_int8
hg_id_encoding_int4 と hg_id_encoding_int8 は、text 型の UID 列を int32 または int64 にマッピングし、マッピング内容をユーザーマッピングテーブルに自動的に書き込みます。これらの関数を動的テーブルの増分更新および RoaringBitmap と組み合わせて使用することで、長期間にわたる UV を算出できます。
エンドツーエンドの例については、「Hologres 動的テーブルを使用して任意の長期間の UV を算出する」をご参照ください。
構文
hg_id_encoding_int4(<user_id>, '<mapping_tablename>')
hg_id_encoding_int8(<user_id>, '<mapping_tablename>')
引数
| 引数 | 型 | 説明 |
|---|---|---|
user_id |
text | マッピング対象の UID 列です。NULL 値はサポートされません。NULL を渡すとエラーが発生します。 |
mapping_tablename |
text | ユーザーマッピングテーブルの名前です。関数を呼び出す前に、このテーブルを作成してください。 |
動作
新しい UID から整数へのマッピングをユーザーマッピングテーブルに書き込みます。UID がすでにテーブルに存在する場合は既存のマッピングが保持され、重複レコードは挿入されません。
注意事項
-
Hologres V4.1 以降でサポートされています。
-
ユーザーマッピングテーブルには、プライマリキーと、(プライマリキー以外に) ちょうど 1 つの Serial フィールドが必要です。
-
text 型の単一列プライマリキーのみをサポートします。
例
-- ソーステーブルを作成します
CREATE TABLE base_table(user_id text);
INSERT INTO base_table VALUES('a');
-- ユーザーマッピングテーブルを作成します
CREATE TABLE uid_mapping(user_id text PRIMARY KEY, id serial);
-- UID を整数にマッピングし、uid_mapping に書き込みます
SELECT user_id, hg_id_encoding_int4(user_id, 'uid_mapping') AS res
FROM base_table;
-- マッピングテーブルをクエリして確認します
-- user_id | id
-- --------+----
-- a | 1
min_by / max_by
min_by と max_by は、ある列の値が最小または最大となる行から、別の列の値を返します。
構文
min_by(expr1, expr2)
max_by(expr1, expr2)
引数
| 引数 | 説明 |
|---|---|
expr2 |
比較に使用する列です (最小値または最大値を特定します)。 |
expr1 |
この列の値が、一致した行から返されます。 |
戻り値
expr2 が最小 (min_by) または最大 (max_by) となる行の expr1 の値です。
注意事項
Hologres V4.0 以降でサポートされています。
例
次の例では、イベントのタイムスタンプに基づいて、各ユーザーの最初と最後のイベントを追跡する動的テーブルを作成します。
-- ソーステーブルを作成します
DROP TABLE IF EXISTS detail;
CREATE TABLE detail (
userid text,
event_id text,
create_time timestamptz
);
INSERT INTO detail(userid, event_id, create_time) VALUES
('user_1', 'e1', '2024-12-20 10:00:00+08'),
('user_1', 'e2', '2024-12-20 11:30:00+08'),
('user_1', 'e3', '2024-12-21 09:15:00+08'),
('user_2', 'e4', '2024-12-20 08:05:00+08'),
('user_2', 'e5', '2024-12-22 14:20:00+08'),
('user_3', 'e6', '2024-12-21 16:45:00+08');
-- 動的テーブルを作成します
DROP TABLE IF EXISTS detail_user_first_last_event;
CREATE DYNAMIC TABLE detail_user_first_last_event
WITH (
auto_refresh_mode = 'incremental',
computing_resource = 'local',
freshness = '3 minutes'
)
AS
SELECT
userid,
min_by(event_id, create_time) AS first_event_id,
max_by(event_id, create_time) AS last_event_id,
date_trunc('day', max(create_time))::date AS dt
FROM detail
GROUP BY userid;
string_agg
string_agg は、列の NULL 以外の値を、固定のデリミタで区切って 1 つの文字列に連結します。
構文
string_agg([distinct] column_expr, const_expr)
引数
| 引数 | 型 | 説明 |
|---|---|---|
column_expr |
text、char、または varchar | 集約対象の列です。 |
const_expr |
text 定数 | 連結した値の間に挿入されるデリミタです。 |
注意事項
-
ORDER BY句はサポートされていません。 -
string_agg([distinct])構文を使用するには Hologres V3.1.10 以降が必要です。 -
基本の
string_aggは Hologres V3.1 以降でサポートされています。
例
CREATE DYNAMIC TABLE string_agg_test_dt
WITH (
freshness = '3 minutes',
refresh_mode = 'incremental')
AS
SELECT day,
string_agg(gameversion, ',') AS gameversion_list
FROM base_table GROUP BY day;
array_agg
array_agg は、列の NULL 以外の値を配列に収集します。
構文
array_agg([distinct] expr)
引数
| 引数 | 型 | 説明 |
|---|---|---|
expr |
boolean、任意の数値型、text、または bytea | 配列に集約する列です。 |
注意事項
-
ORDER BY句はサポートされていません。 -
array_agg([distinct])構文を使用するには Hologres V3.1.10 以降が必要です。 -
基本の
array_aggは Hologres V3.1 以降でサポートされています。
例
CREATE DYNAMIC TABLE array_agg_test_dt
WITH (
freshness = '3 minutes',
refresh_mode = 'incremental')
AS
SELECT day,
array_agg(gameversion) AS gameversion_list
FROM base_table GROUP BY day;
any_value
GROUP BY クエリにおいて、any_value は各集約グループから非決定的な値を返します。
構文
any_value(expr)
引数
| 引数 | 型 | 説明 |
|---|---|---|
expr |
int または bytea | 値が返される列です。 |
注意事項
-
Hologres V3.1.5 以降でサポートされています。
-
exprには、int 型と bytea 型のみ指定できます。 -
戻り値は非決定的です。
例
CREATE DYNAMIC TABLE dt_t0
WITH (
freshness = '1 minutes',
auto_refresh_mode = 'auto'
)
AS
SELECT a, any_value(c), sum(b) FROM t0 GROUP BY a;