ClickHouse/docs/ja/guides/developer/cascading-materialized-views.md
2024-11-18 11:58:58 +09:00

13 KiB
Raw Blame History

slug title description keywords
/ja/guides/developer/cascading-materialized-views カスケードされたMaterialized View ソーステーブルから複数のMaterialized Viewを使用する方法。
materialized view
集計

カスケードされたMaterialized View

この例では、まずMaterialized Viewを作成し、次にそのMaterialized ViewにさらにカスケードさせたMaterialized Viewを作成する方法を示します。このページでは、その方法、多くの可能性、および制限を確認できます。異なるユースケースは、2番目のMaterialized Viewをソースとして使用してMaterialized Viewを作成することで解決できます。


例:

ドメイン名ごとの毎時のビュー数という架空のデータセットを使用します。

目的

  1. 各ドメイン名ごとに月ごとに集計されたデータを必要とする。
  2. 各ドメイン名ごとに年ごとに集計されたデータも必要とする。

以下のオプションから選択できます:

  • SELECTリクエスト中にデータを読み取り、集計するクエリを書く
  • データを新しい形式で取り込み時に準備する
  • データを特定の集計形式で取り込み時に準備する

Materialized Viewを使用してデータを準備すると、ClickHouseが必要とするデータ量と計算を制限できるため、SELECTリクエストがより高速になります。

Materialized Viewのソーステーブル

ソーステーブルを作成します。目標が個々の行ではなく集計データのレポートであるため、データを解析し、その情報をMaterialized Viewに渡し、実際の受信データを破棄できます。これにより目的が達成され、ストレージが節約できるため、Nullテーブルエンジンを使用します。

CREATE DATABASE IF NOT EXISTS analytics;
CREATE TABLE analytics.hourly_data
(
    `domain_name` String,
    `event_time` DateTime,
    `count_views` UInt64
)
ENGINE = Null

:::note Nullテーブルに対してMaterialized Viewを作成できます。したがって、テーブルに書き込まれるデータはビューに影響を与えますが、元の生データは破棄されます。 :::

月次集計テーブルとMaterialized View

最初のMaterialized Viewについては、Targetテーブルを作成する必要があります。この例では、analytics.monthly_aggregated_dataというテーブルを作成し、月別およびドメイン名別にビューの合計を保存します。

CREATE TABLE analytics.monthly_aggregated_data
(
    `domain_name` String,
    `month` Date,
    `sumCountViews` AggregateFunction(sum, UInt64)
)
ENGINE = AggregatingMergeTree
ORDER BY (domain_name, month)

ターゲットテーブルにデータを転送するMaterialized Viewは次のようになります

CREATE MATERIALIZED VIEW analytics.monthly_aggregated_data_mv
TO analytics.monthly_aggregated_data
AS
SELECT
    toDate(toStartOfMonth(event_time)) AS month,
    domain_name,
    sumState(count_views) AS sumCountViews
FROM analytics.hourly_data
GROUP BY
    domain_name,
    month

年次集計テーブルとMaterialized View

次に、前のターゲットテーブルmonthly_aggregated_dataにリンクされる2番目のMaterialized Viewを作成します。

まず、ドメイン名ごとに年別に集計されたビューの合計を格納する新しいターゲットテーブルを作成します。

CREATE TABLE analytics.year_aggregated_data
(
    `domain_name` String,
    `year` UInt16,
    `sumCountViews` UInt64
)
ENGINE = SummingMergeTree()
ORDER BY (domain_name, year)

このステップでカスケードを定義します。FROM文はmonthly_aggregated_dataテーブルを使用します。これは、データフローが次のようになることを意味します:

  1. データはhourly_dataテーブルに到着します。
  2. ClickHouseは、受信したデータを最初のMaterialized Viewであるmonthly_aggregated_dataテーブルに転送します。
  3. 最後に、ステップ2で受信したデータがyear_aggregated_dataに転送されます。
CREATE MATERIALIZED VIEW analytics.year_aggregated_data_mv
TO analytics.year_aggregated_data
AS
SELECT
    toYear(toStartOfYear(month)) AS year,
    domain_name,
    sumMerge(sumCountViews) as sumCountViews
FROM analytics.monthly_aggregated_data
GROUP BY
    domain_name,
    year

:::note Materialized Viewを使用する際の一般的な誤解は、データがテーブルから読み取られるということです。これはMaterialized Viewの動作ではありません。転送されるデータはテーブルの最終結果ではなく、挿入されたブロックです。

この例でmonthly_aggregated_dataで使用されるエンジンがCollapsingMergeTreeであると仮定した場合、私たちの2番目のMaterialized Viewyear_aggregated_data_mvに転送されるデータは、圧縮されたテーブルの最終結果ではなく、SELECT ... GROUP BYで定義されたフィールドを持つデータブロックが転送されます。

CollapsingMergeTree、ReplacingMergeTree、またはSummingMergeTreeを使用してカスケードMaterialized Viewを作成する予定がある場合は、ここで説明されている制限を理解する必要があります。 :::

サンプルデータ

カスケードMaterialized Viewをテストするために、データを挿入します

INSERT INTO analytics.hourly_data (domain_name, event_time, count_views)
VALUES ('clickhouse.com', '2019-01-01 10:00:00', 1),
       ('clickhouse.com', '2019-02-02 00:00:00', 2),
       ('clickhouse.com', '2019-02-01 00:00:00', 3),
       ('clickhouse.com', '2020-01-01 00:00:00', 6);

analytics.hourly_dataの内容をSELECTすると、テーブルエンジンがNullであるため、次のようになりますが、データは処理されます。

SELECT * FROM analytics.hourly_data
Ok.

0 rows in set. Elapsed: 0.002 sec.

少量のデータセットを使用することで、予想される結果を確認し、比較することができます。少量のデータセットでフローが正しいことを確認したら、大量のデータに移行することができます。

結果

ターゲットテーブルをクエリしてsumCountViewsフィールドを選択しようとすると、バイナリ表現(いくつかのターミナルで)を目にすることがあります。これは、値が数値としてではなく、AggregateFunction型として格納されているためです。集計の最終結果を得るには、-Mergeサフィックスを使用する必要があります。

AggregateFunctionに格納された特殊文字を見るためのクエリ

SELECT sumCountViews FROM analytics.monthly_aggregated_data
┌─sumCountViews─┐
│               │
│               │
│               │
└───────────────┘

3 rows in set. Elapsed: 0.003 sec.

代わりに、Mergeサフィックスを使用してsumCountViewsの値を取得してみましょう:

SELECT
   sumMerge(sumCountViews) as sumCountViews
FROM analytics.monthly_aggregated_data;
┌─sumCountViews─┐
│            12 │
└───────────────┘

1 row in set. Elapsed: 0.003 sec.

AggregatingMergeTreeAggregateFunctionsumとして定義されているため、sumMergeを使用できます。AggregateFunctionavgを使用すると、avgMergeを使用します。

SELECT
    month,
    domain_name,
    sumMerge(sumCountViews) as sumCountViews
FROM analytics.monthly_aggregated_data
GROUP BY
    domain_name,
    month

これで、Materialized Viewが定義した目標に答えていることを確認できます。

ターゲットテーブルmonthly_aggregated_dataにデータが保存されているため、各ドメイン名ごとに月ごとに集計されたデータを取得できます:

SELECT
   month,
   domain_name,
   sumMerge(sumCountViews) as sumCountViews
FROM analytics.monthly_aggregated_data
GROUP BY
   domain_name,
   month
┌──────month─┬─domain_name────┬─sumCountViews─┐
│ 2020-01-01 │ clickhouse.com │             6 │
│ 2019-01-01 │ clickhouse.com │             1 │
│ 2019-02-01 │ clickhouse.com │             5 │
└────────────┴────────────────┴───────────────┘

3 rows in set. Elapsed: 0.004 sec.

各ドメイン名ごとの年ごとに集計されたデータ:

SELECT
   year,
   domain_name,
   sum(sumCountViews)
FROM analytics.year_aggregated_data
GROUP BY
   domain_name,
   year
┌─year─┬─domain_name────┬─sum(sumCountViews)─┐
│ 2019 │ clickhouse.com │                  6 │
│ 2020 │ clickhouse.com │                  6 │
└──────┴────────────────┴────────────────────┘

2 rows in set. Elapsed: 0.004 sec.

複数のソーステーブルを単一のターゲットテーブルに結合する

Materialized Viewは、複数のソーステーブルを同じ宛先テーブルに結合するためにも使用できます。これは、UNION ALLと同様のロジックを持つMaterialized Viewを作成するのに役立ちます。

まず、異なるメトリックセットを表す2つのソーステーブルを作成します

CREATE TABLE analytics.impressions
(
    `event_time` DateTime,
    `domain_name` String
) ENGINE = MergeTree ORDER BY (domain_name, event_time)
;

CREATE TABLE analytics.clicks
(
    `event_time` DateTime,
    `domain_name` String
) ENGINE = MergeTree ORDER BY (domain_name, event_time)
;

次に、結合されたメトリックセットを持つTargetテーブルを作成します:

CREATE TABLE analytics.daily_overview
(
    `on_date` Date,
    `domain_name` String,
    `impressions` SimpleAggregateFunction(sum, UInt64),
    `clicks` SimpleAggregateFunction(sum, UInt64)
) ENGINE = AggregatingMergeTree ORDER BY (on_date, domain_name)

同じTargetテーブルを指す2つのMaterialized Viewを作成します。不足しているカラムを明示的に含める必要はありません

CREATE MATERIALIZED VIEW analytics.daily_impressions_mv
TO analytics.daily_overview
AS                                                
SELECT
    toDate(event_time) AS on_date,
    domain_name,
    count() AS impressions,
    0 clicks         ---<<<--- これを省略すると、デフォルトで0になります
FROM                                              
    analytics.impressions
GROUP BY
    toDate(event_time) AS on_date,
    domain_name
;

CREATE MATERIALIZED VIEW analytics.daily_clicks_mv
TO analytics.daily_overview
AS
SELECT
    toDate(event_time) AS on_date,
    domain_name,
    count() AS clicks,
    0 impressions    ---<<<--- これを省略すると、デフォルトで0になります
FROM
    analytics.clicks
GROUP BY
    toDate(event_time) AS on_date,
    domain_name
;

これで、挿入された値はTargetテーブルのそれぞれのカラムに集計されます:

INSERT INTO analytics.impressions (domain_name, event_time)
VALUES ('clickhouse.com', '2019-01-01 00:00:00'),
       ('clickhouse.com', '2019-01-01 12:00:00'),
       ('clickhouse.com', '2019-02-01 00:00:00'),
       ('clickhouse.com', '2019-03-01 00:00:00')
;

INSERT INTO analytics.clicks (domain_name, event_time)
VALUES ('clickhouse.com', '2019-01-01 00:00:00'),
       ('clickhouse.com', '2019-01-01 12:00:00'),
       ('clickhouse.com', '2019-03-01 00:00:00')
;

Targetテーブルで統合されたインプレッションとクリック:

SELECT
    on_date,
    domain_name,
    sum(impressions) AS impressions,
    sum(clicks) AS clicks
FROM
    analytics.daily_overview
GROUP BY
    on_date,
    domain_name
;

このクエリは次のような出力になります:

┌────on_date─┬─domain_name────┬─impressions─┬─clicks─┐
│ 2019-01-01 │ clickhouse.com │           2 │      2 │
│ 2019-03-01 │ clickhouse.com │           1 │      1 │
│ 2019-02-01 │ clickhouse.com │           1 │      0 │
└────────────┴────────────────┴─────────────┴────────┘

3 rows in set. Elapsed: 0.018 sec.