重複データの除去
はじめに
分散システムでセンサーデータを収集・転送する場合、一時的なネットワーク切断やデバイス設定によって同じデータが再送されることがあります。データ損失を防ぐための再送でも、データベースには重複レコードが格納されます。大量データを扱うアプリケーションで重複の識別・除去を実装すると、処理が複雑になり性能が低下する場合があります。
Machbase は、データベース内で重複転送を除去する機能を提供します。設定した時間ウィンドウに基づいて重複する入力を自動検出・除去するため、アプリケーション側に複雑な処理を実装せずにデータの整合性を維持できます。この機能は TAG テーブルで使用します。
基本概念
TAG テーブルの作成時に、重複チェックの対象期間を設定します。挿入時のシステム時刻から過去にさかのぼる時間ウィンドウです。新しい行を挿入するとき、次の処理を行います。
- 識別: 入力行の
PRIMARY KEY列(通常は Tag ID またはname)とBASETIME列(タイムスタンプ)を既存の行と比較します。 - 検索:
PRIMARY KEYとBASETIMEが両方とも完全に一致する行を探します。 - 時間条件: 一致する行が存在し、その
BASETIMEが今回の挿入時の システム時刻 からさかのぼった設定期間内にある場合、入力行を重複と判定します。 - 処理: 重複と判定した入力行を自動的に破棄し、TAG テーブルには保存しません。
指定した時間ウィンドウ内では、最初の書き込みを保持する「first-write-wins」の動作になります。Tag ID とタイムスタンプの組み合わせが初めて現れたときに保存し、その時刻が現在のシステム時刻に対する対象期間内にある間は、同じ組み合わせの再挿入を無視します。比較する列は PRIMARY KEY と BASETIME だけです。センサー値などの他の列が異なっても、キーと時刻が一致すれば重複と判定します。
設定
TAG テーブルの作成時に、次のテーブルプロパティを指定します。
TAG_DUPLICATE_CHECK_DURATION: 重複検出の対象期間を分単位で指定します。
構文:
CREATE TAG TABLE table_name (
name_column datatype PRIMARY KEY,
time_column DATETIME BASETIME,
value_column datatype [SUMMARIZED]
[, additional_columns...]
)
TAG_DUPLICATE_CHECK_DURATION = duration_in_minutes;duration_in_minutes: 対象期間を指定する分単位の整数。- 最小値:
1(分)。 - 最大値:
43200(分)。 - デフォルト:
0(無効)。
- 最小値:
設定の確認:
システムカタログビューを検索して、TAG テーブルに設定された期間を確認できます。
テーブル ID の取得:
SELECT id FROM m$sys_tables WHERE name = 'YOUR_TABLE_NAME'; -- テーブル名は大文字で指定プロパティ値の検索:
SELECT value FROM m$sys_table_property WHERE id = {table_id_from_step_1} AND name = 'TAG_DUPLICATE_CHECK_DURATION';
設定の変更 TAG_DUPLICATE_CHECK_DURATION は次のように変更できます。
ALTER TABLE {table_name} set TAG_DUPLICATE_CHECK_DURATION={分単位の期間};動作と制約
この機能を使用する際は、次の動作と制約を確認してください。
- 単位と範囲: 分単位で指定し、最大は 43200 分(30 日)です。
- データ削除との関係: 重複チェックは、対象期間内に元のデータが存在することに依存します。同一データの再到着前に元の行を削除すると、比較対象がなくなるため、新しい最初の書き込みとして受け入れます。
- 保持する行: 同じ主キーと BASETIME の組み合わせでは、対象期間内で最初に受け入れた行を保持し、後続の重複を破棄します。最後の書き込みを保持する「last-write-wins」が必要な用途には適しません。
- 整合性モデル: 大量のリアルタイム取り込みでは、最新の挿入が内部構造の重複チェックに反映されるまで、わずかな遅延が発生する場合があります。分散データシステムの結果整合性に見られる動作です。
- 転送先での重複除去: Machbase データベース内で重複を除去します。送信元からの重複転送を防ぐ機能ではありません。
- リソースへの影響: 送信前にアプリケーションで除去する方式と比べ、取り込み時のチェックにデータベースの CPU と I/O を追加で使用します。
例
重複除去を有効にした TAG テーブルを作成し、その動作を確認します。
1. スキーマの定義:
-- 前の実行でテーブルが存在する場合は削除
DROP TABLE IF EXISTS dup_tag;
-- dup_tag という TAG テーブルを作成
-- 1440 分(1 日)のウィンドウで重複をチェック
CREATE TAG TABLE dup_tag (
name VARCHAR(20) PRIMARY KEY,
time DATETIME BASETIME,
value DOUBLE SUMMARIZED -- 値列(重複除去自体には SUMMARIZED は任意)
)
TAG_DUPLICATE_CHECK_DURATION=1440; -- 1440 分(1 日)の対象期間で重複除去を有効化2. データの挿入:
次の INSERT 文を順番に実行するものとします。例では、各挿入時のシステム時刻が進み、2024-01-02 同士、2024-01-04 同士の重複を検査するときに、それぞれのタイムスタンプが 1 日の対象期間内にあることを前提としています。過去の固定日時を現在の時刻でそのまま実行しても、この前提は満たせません。
-- 最初のレコードを挿入
INSERT INTO dup_tag VALUES('tag1', '2024-01-01 09:00:00 000:000:001', 0); -- 保持(最初のデータ)
INSERT INTO dup_tag VALUES('tag1', '2024-01-02 09:00:00 000:000:001', 0); -- 保持(最初の行と日付・時刻が異なる)
INSERT INTO dup_tag VALUES('tag1', '2024-01-02 09:00:00 000:000:002', 0); -- 保持(この時刻の最初のデータ)
-- 直前の行と同じ name・time の重複を挿入
-- value は異なる(1 と 0)が、重複として扱う
-- 対象期間内の既存レコードと (name, time) が一致するため。
INSERT INTO dup_tag VALUES('tag1', '2024-01-02 09:00:00 000:000:002', 1); -- 破棄(name と time が重複)
-- 後日のレコードを挿入
INSERT INTO dup_tag VALUES('tag1', '2024-01-03 09:00:00 000:000:003', 0); -- 保持(新しいタイムスタンプ)
-- 別のタグ tag2 に同じタイムスタンプの複数の重複を挿入
INSERT INTO dup_tag VALUES('tag2', '2024-01-04 09:00:00 000:000:001', 0); -- 保持(この時刻の tag2 の最初のデータ)
INSERT INTO dup_tag VALUES('tag2', '2024-01-04 09:00:00 000:000:001', 1); -- 破棄(name と time が重複)
INSERT INTO dup_tag VALUES('tag2', '2024-01-04 09:00:00 000:000:001', 2); -- 破棄(name と time が重複)
-- tag2 に異なるタイムスタンプのレコードを挿入
INSERT INTO dup_tag VALUES('tag2', '2024-01-04 09:00:00 000:000:002', 1); -- 保持(この時刻の最初のデータ)
INSERT INTO dup_tag VALUES('tag2', '2024-01-04 09:00:00 000:000:003', 2); -- 保持(この時刻の最初のデータ)3. データの確認:
各 name と time の組み合わせについて、有効な対象期間内で最初に書き込まれた行だけが格納されていることを確認します。
-- tag1 のデータを検索
SELECT * FROM dup_tag WHERE name = 'tag1';
/* tag1 の想定出力:
ROWNUM | NAME | TIME | VALUE
------ | ---- | --------------------------------- | -----
1 | tag1 | 2024-01-01 09:00:00 000:000:001 | 0.0
2 | tag1 | 2024-01-02 09:00:00 000:000:001 | 0.0
3 | tag1 | 2024-01-02 09:00:00 000:000:002 | 0.0 -- value が 1 の重複行は破棄された
4 | tag1 | 2024-01-03 09:00:00 000:000:003 | 0.0
*/
-- tag2 のデータを検索
SELECT * FROM dup_tag WHERE name = 'tag2';
/* tag2 の想定出力:
ROWNUM | NAME | TIME | VALUE
------ | ---- | --------------------------------- | -----
1 | tag2 | 2024-01-04 09:00:00 000:000:001 | 0.0 -- この時刻の value が 1 と 2 の重複行は破棄された
2 | tag2 | 2024-01-04 09:00:00 000:000:002 | 1.0
3 | tag2 | 2024-01-04 09:00:00 000:000:003 | 2.0
*/