Amazon QLDBを触ってみた。
全体構成
- QLDBはテーブルとジャーナルで構成される
- テーブル
- データとメタデータを過去の状態を含めてもつ
- selectの実行先
- ジャーナル
- 変更履歴をもつ
- insert、update、deleteの実行先
- テーブル
ジャーナル
- ドキュメントに行ったすべての変更の完全で不変な履歴全体をもつ
- 追加していくだけで、変更削除はできない
- データだけでなく実行されたクエリも記録する
ブロック
- ジャーナルにコミットされたオブジェクト
- トランザクション:ブロック = 1:n
- エントリ、ブロックハッシュを含む
エントリ
- ドキュメントリビジョン、それらをコミットした PartiQL ステートメントを含む
テーブル
- ドキュメントリビジョンのコレクション
- ドキュメントの最新のリビジョンだけでなく、過去のイテレーションもすべて含まれる
ドキュメント
- データのこと
- Amazon Ionというフォーマットで表す
- 構造化データと非構造化データの両方を一緒に保存できる抽象データモデル
- JSONの拡張フォーマット
- 1レコードに1つのドキュメントIDがメタデータとして付与されている
例
Vehicle.json
{
VIN: "1N4AL11D75C109151",
Type: "Sedan",
Year: 2011,
Make: "Audi",
Model: "A5",
Color: "Silver"
}
ネストして保持も可能
VehicleRegistration.json
{
VIN: "KM8SRDHF6EU074761",
LicensePlateNumber: "CA762X",
State: "WA",
City: "Kent",
PendingPenaltyTicketAmount: 130.75,
ValidFrom: 2017-09-14T,
ValidTo: 2020-06-25T,
Owners: {
PrimaryOwner: { PersonId: "IN7MvYtUjkp1GMZu0F6CG9" },
SecondaryOwners: []
}
}
ドキュメントリビジョン
- ドキュメントの更新を表す仕組み
- ドキュメントIDと0から始めるバージョン番号で表す
- ドキュメントとドキュメントIDとバージョン番号を含むメタデータで構成される
例
data:{
VIN: "KM8SRDHF6EU074761",
LicensePlateNumber: "CA762X",
State: "WA",
City: "Kent",
PendingPenaltyTicketAmount: 130.75,
ValidFrom: 2017-09-14T,
ValidTo: 2020-06-25T,
Owners: {
PrimaryOwner: { PersonId: "IN7MvYtUjkp1GMZu0F6CG9" },
SecondaryOwners: []
}
},
metadata:{
id:"JOzfB3lWqGU727mpPeWyxg",
version:0,
txTime:2019-06-05T20:53:321d-3Z,
txId:"HgXAkLjAtV0HQ4lNYdzX60"
}
ユーザーテーブル、カレントビュー、ユーザービュー
- 削除されていない最新の各ドキュメントが格納される
- 最新かどうかはジャーナルにコミットされたトランザクションに基づく
システムテーブル、コミット済みビュー
- 各ドキュメントとそのシステム生成メタデータを格納する
- ユーザーテーブル作成時にシステムによって作成されるテーブル
- ユーザーテーブルと1対1の関係
- 「_ql_committed_」+ユーザーテーブル名で命名される
- 過去のイテレーションは履歴として保存される
blockAddress
- ドキュメントリビジョンがコミットされた台帳のジャーナルのブロックの場所
- strandId:ブロックを含むジャーナルストランドの一意の ID
- sequenceNo:ストランド内でブロックの場所を指定するインデックス番号
hash
- ドキュメントリビジョンを一意に表す SHA-256 値
- ハッシュは data フィールドと metadata フィールドを対象とする
- 暗号検証に使用
data
- 最新のドキュメント
metadata
- システムによって生成される各ドキュメントごとのメタデータ
- id:システムによって割り当てられたドキュメント ID
- version:ドキュメントリビジョンごとに増えていく 0 から始まる整数
- txTime:ジャーナルにドキュメントリビジョンがコミットされたときのタイムスタンプ
- txId:ドキュメントリビジョンをコミットしたトランザクションの一意の ID
例
{
blockAddress:{
strandId:"JdxjkR9bSYB5jMHWcI464T",
sequenceNo:14
},
hash:{{wPuwH60TtcCvg/23BFp+redRXuCALkbDihkEvCX22Jk=}},
data:{
VIN: "KM8SRDHF6EU074761",
LicensePlateNumber: "CA762X",
State: "WA",
City: "Kent",
PendingPenaltyTicketAmount: 130.75,
ValidFrom: 2017-09-14T,
ValidTo: 2020-06-25T,
Owners: {
PrimaryOwner: { PersonId: "IN7MvYtUjkp1GMZu0F6CG9" },
SecondaryOwners: []
}
},
metadata:{
id:"JOzfB3lWqGU727mpPeWyxg",
version:0,
txTime:2019-06-05T20:53:321d-3Z,
txId:"HgXAkLjAtV0HQ4lNYdzX60"
}
}
information_schema
- ユーザーテーブルのメタデータをもつ
- tableId:テーブル ID
- name:テーブル名
- indexes:テーブルのインデックスのリスト
- status:テーブルの現在のステータス (ACTIVE または INACTIVE)
例
{
tableId: "5PLf9SXwndd63lPaSIa0O6",
name: "VehicleRegistration",
indexes: [{ expr: "[VIN]" }, { expr: "[LicensePlateNumber]" }],
status: "ACTIVE"
}
チュートリアル
Amazon QLDB でのデータと履歴の使用をなぞってみた
台帳作成
データ投入
クエリ
- 基本的なSQLは投げられる
- ネストされたデータもSQLで取得可能
取得元.json
{
VIN: "1N4AL11D75C109151",
LicensePlateNumber: "LEWISR261LL",
State: "WA",
City: "Tokyo",
PendingPenaltyTicketAmount: 90.25,
ValidFromDate: 2017-08-21T,
ValidToDate: 2020-05-11T,
Owners: {
PrimaryOwner: {
PersonId: "IN7MvYtUjkp1GMZu0F6CG9"
},
SecondaryOwners: [{PersonId:"5Ufgdlnj06gF5CWcOIu64s"}]
}
}
実行SQL.sql
SELECT
r.VIN,
o.PersonId
FROM
VehicleRegistration AS r, @r.Owners.PrimaryOwner AS o
WHERE
r.VIN = '1N4AL11D75C109151'
取得したデータ.json
{
VIN: "1N4AL11D75C109151",
PersonId: "IN7MvYtUjkp1GMZu0F6CG9"
}
更新
実行SQL.sql
UPDATE VehicleRegistration AS r
SET r.Owners.PrimaryOwner.PersonId = 'IN7MvYtUjkp1GMZu0F6CG9',
r.City = 'Tokyo'
WHERE r.VIN = '1N4AL11D75C109151'
検証
sampleLedger-2020-02-22.ion.txt
{
"digest":"h5pUdLTTNpjgMFE3omBszf2tTtlGWHpty8GM1Zxuzo4=",
"digestTipAddress":"{strandId:\"JOzfHtF3bQL8pjtQlU37Fu\",sequenceNo:107}",
"ledger":"sampleLedger",
"date":"2020-02-22T07:53:34.448Z"
}
感想
- 台帳作成がマネジメントコンソール上で完結していてすごく楽
- 数クリック作成されるのはこれまでのブロックチェーンサービスと違って良い体験
- RDSのSQLのように半構造のドキュメントを扱えるのは良い
- 更新履歴の持ち方や整合性を考える必要がなくなるのはすごく良い
- 検証するユースケースはよく分からない…………