こんにちは、MLBお兄さんこと松村です。
シカゴ・カブスの今永昇太投手は、ここまで3試合の先発登板でいまだに防御率が 0.00 という、素晴らしい成績を残しています。
今回は Azure Cosmos DB for NoSQL のデザインパターン解説記事の第6弾です。
前回は「イベントソーシング (Event sourcing) パターン」を解説しました。
今回は「マテリアライズド・ビュー (Materialized View) パターン」について解説をします。
このデザインパターンについては、Cosmos DB の GitHub リポジトリやブログで紹介されていますので、詳しく読みたい方はこちらもご覧ください。
Materialized View は、日本語訳では「具現化されたビュー」と表記されることがあります。
Materialized View パターンを雑に言えば、「複雑なクエリを頻繁に実行するなら、そのクエリのために集計したビューを作り、クエリを単純にする」方法です。
このパターンは Azure アーキテクチャーセンターでも取り上げられています。
RDB では CREATE VIEW
クエリでビューを作成するため、ビューで参照するデータには元のテーブルが存在します。
しかし NoSQL の場合は、元のデータの作成・更新をトリガーとして、マテリアライズド・ビューのためのテーブルのデータの準備が必要となります。
Cosmos DB でマテリアライズド・ビューを使用するケースは、分析クエリや集計されたデータへのアクセスのためです。
ただし大規模な分析や集計を行う場合、 Azure Cosmos DB 分析ストア と Azure Synapse Link for Azure Cosmos DB の利用を検討しましょう。
サンプルコードがリポジトリで公開されていますので、あわせて確認してください。
マテリアライズド・ビューのためのデータを作るには、Change Feed を利用します。
元のデータクラス
public class Sales { public string id { get; set; } = Guid.NewGuid().ToString(); public int CustomerId { get; set; } public int OrderId { get; set; } public DateTime OrderDate {get; set;} = DateTime.UtcNow; public int Qty { get; set;} public string Product { get; set; } public double Total { get; set; } }
マテリアライズド・ビューのためのデータクラス
データの詰替えはコンストラクタで行っています。
public class SalesByProduct { public string id { get; set; } = Guid.NewGuid().ToString(); public DateTime OrderDate { get; set; } public int Qty { get; set;} public double Total { get; set; } public string Product { get; set; } public SalesByProduct(){} public SalesByProduct(Sales salesItem){ this.OrderDate = salesItem.OrderDate; this.Product = salesItem.Product; this.Qty = salesItem.Qty; this.Total = salesItem.Total; } }
Change Feed 処理
[FunctionName("MaterializedViewProcessor")] public static async Task Run([CosmosDBTrigger( databaseName: "Sales", containerName: "Sales", Connection = "CosmosDBConnection", LeaseContainerName = "leases", CreateLeaseContainerIfNotExists=true)]IReadOnlyList<Sales> input, [CosmosDB(databaseName: "Sales", containerName: "SalesByProduct", Connection="CosmosDBConnection", CreateIfNotExists=true, PartitionKey="/Product")] IAsyncCollector<SalesByProduct> salesByProduct, ILogger log) { if (input != null && input.Count > 0) { log.LogInformation("Document count: " + input.Count); foreach (Sales document in input){ await salesByProduct.AddAsync(new SalesByProduct(document)); } } }
コード自体はシンプルですね。
Materialized View パターンで大事なのは、都度集計するのか、集計のためのテーブルを準備するのか、というデータ設計のほうだと思いますね。
サービス一覧 www.alterbooth.com cloudpointer.tech www.alterbooth.com