論理データモデリング
クエリを定義したので、Cassandra テーブルの設計を開始できます。最初に、各クエリに対応するテーブルを含む論理モデルを作成し、概念モデルからエンティティとリレーションシップを取得します。
各テーブルに名前を付けるには、クエリ対象のプライマリエンティティタイプを識別し、それをエンティティ名の先頭として使用します。他の関連エンティティの属性でクエリする場合は、それらをテーブル名に追加し、by
で区切ります。たとえば、hotels_by_poi
です。
次に、テーブルのプライマリキーを識別し、必要なクエリ属性に基づいてパーティションキー列を追加し、一意性を保証し、必要なソート順序をサポートするためにクラスタリング列を追加します。
プライマリキーの設計は非常に重要です。各パーティションに格納されるデータ量と、ディスク上のデータの編成方法が決まり、Cassandra が読み取りを処理する速度に影響します。
クエリによって識別された追加の属性を追加して、各テーブルを完成させます。これらの追加属性のいずれかがパーティションキーのすべてのインスタンスで同じである場合は、列を静的としてマークします。
これはかなり複雑なプロセスの簡単な説明だったので、詳細な例を通して作業する必要があります。最初に、論理モデルを表すために使用できる表記法を紹介します。
Cassandra コミュニティ内の何人かの人々は、データモデルを図式形式でキャプチャするための表記法を提案しています。このドキュメントでは、Artem Chebotko によって普及した表記法を使用しています。これは、設計におけるクエリとテーブル間の関係を視覚化するシンプルで有益な方法を提供します。この図は、論理データモデルの Chebotko 表記法を示しています。

各テーブルは、タイトルと列のリストとともに表示されます。プライマリキー列は、パーティションキー列の **K** や、クラスタリング列を表す **C**↑ または **C**↓ などの記号で識別されます。テーブルに入力される線またはテーブル間の線は、各テーブルがサポートするように設計されたクエリを示しています。
ホテル論理データモデル
下の図は、ホテル、観光スポット、部屋、アメニティに関連するクエリの Chebotko 論理データモデルを示しています。すぐに気付くことの 1 つは、Cassandra 設計には、リレーショナル設計にあった部屋やアメニティ専用のテーブルが含まれていないことです。これは、ワークフローがこの直接アクセスを必要とするクエリを識別しなかったためです。

これらの各テーブルの詳細を見ていきましょう。
最初のクエリ Q1 は、観光スポットの近くのホテルを見つけることなので、このテーブルを hotels_by_poi
と呼びます。名前付きの観光スポットで検索することは、観光スポットがプライマリキーの一部であるべきであるという手がかりです。ワークフローによると、ユーザーは検索を開始するため、観光スポットを名前で参照します。
特定の観光スポットの近くに複数のホテルがある可能性があるため、各ホテルに一意のパーティションがあることを確認するために、プライマリキーに別のコンポーネントが必要になります。そのため、ホテルキーをクラスタリング列として追加します.
テーブルのプライマリキーを設計する際の重要な考慮事項は、一意のデータ要素を定義していることを確認することです。そうしないと、誤ってデータを上書きする危険性があります。
2 番目のクエリ (Q2) については、特定のホテルに関する情報を取得するためのテーブルが必要です。1 つの方法は、ホテルのすべての属性を hotels_by_poi
テーブルに配置することでしたが、アプリケーションワークフローで必要な属性のみを追加しました。
ワークフロー図から、hotels_by_poi
テーブルは、各ホテルの基本情報を含むホテルのリストを表示するために使用され、アプリケーションは返されたホテルの一意の識別子を知っていることがわかります。ユーザーが詳細を表示するホテルを選択すると、Q2 を使用してホテルの詳細を取得できます。Q1 からすでに hotel_id
があるため、それを探しているホテルへの参照として使用します。したがって、2 番目のテーブルは単に hotels
と呼ばれます。
別のオプションは、poi_names
のセットを hotels テーブルに格納することでした。これは同様に有効なアプローチです。経験を通して、アプリケーションに最適なアプローチを学ぶことができます。
Q3 は Q1 の逆です。観光スポットの近くのホテルではなく、ホテルの近くの観光スポットを探します。ただし、今回は、pois_by_hotel
テーブルで表される各観光スポットの詳細にアクセスする必要があります。以前と同様に、一意性を保証するために、観光スポット名をクラスタリングキーとして追加します。
この時点で、ユーザーが滞在したいと考えている夜に選択したホテルで利用可能な部屋を見つけるのに役立つクエリ Q4 をサポートする方法を考えてみましょう。このクエリには、開始日と終了日の両方が含まれていることに注意してください。単一の日付ではなく範囲をクエリしているため、日付をクラスタリングキーとして使用する必要があることがわかります。hotel_id
をプライマリキーとして使用して、各ホテルの部屋データを単一のパーティションにグループ化します。これにより、検索が非常に高速になります。これを available_rooms_by_hotel_date
テーブルと呼びましょう。
範囲を検索するには、clustering columns <clustering-columns>
を使用して、範囲クエリでアクセスする必要がある属性を格納します。クラスタリング列の順序が重要であることを忘れないでください。
available_rooms_by_hotel_date
テーブルの設計は、**ワイドパーティション** パターンのインスタンスです。このパターンは、同様のモデルをサポートするデータベースについて説明する場合、**ワイドロウ** パターント呼ばれることもありますが、ワイドパーティションは Cassandra の観点からより正確な説明です。このパターンの本質は、単一のクエリでパーティション内の複数の行に高速にアクセスできるように、パーティション内に複数の関連する行をグループ化することです。
データモデルのショッピング部分を締めくくるために、amenities_by_room
テーブルを追加して Q5 をサポートします。これにより、ユーザーは希望の滞在日に利用可能な部屋の 1 つの設備を表示できます。
予約論理データモデル
それでは、予約クエリを見てみましょう。この図は、予約の論理データモデルを示しています。これらのテーブルは非正規化された設計を表していることに気付くでしょう。同じデータが複数のテーブルに表示され、キーが異なります。

Q6 を満たすために、reservations_by_guest
テーブルを使用して、ゲスト名で予約を検索できます。セルフサービスの Web サイトのゲストまたはゲストを支援しようとしているコールセンターエージェントに代わってクエリ Q7 が使用されていると想像できます。ゲスト名が必ずしも一意ではないため、ここにもゲスト ID をクラスタリング列として含めます。
特に Q8 と Q9 は、顧客だけでなく、スタッフ、さらには分析チーム、サプライヤーなど、アプリケーションのさまざまな利害関係者をサポートするクエリを作成することを忘れないでください。
ホテルのスタッフは、ホテルが完売または販売不足になっている日付など、ホテルのパフォーマンスに関する洞察を得るために、日付順に今後の予約の記録を見たい場合があります。Q8 は、指定されたホテルの予約を日付順に取得することをサポートしています。
最後に、guests
テーブルを作成します。これは、ゲスト情報を格納するために使用される単一の場所を提供します。この場合、ゲストレコードに個別の一意の識別子を指定します。これは、ゲストの名前が同じになることは珍しくないためです。多くの組織では、guests
テーブルなどの顧客データベースは、個別の顧客管理アプリケーションの一部であるため、他のゲストアクセスパターンは例から省略されました。
パターンとアンチパターン
他のタイプのソフトウェア設計と同様に、Cassandra のデータモデリングには、よく知られているパターンとアンチパターンがいくつかあります。このホテルモデルで最も一般的なパターンの 1 つであるワイドパーティションパターンをすでに使用しています。
**時系列** パターンは、ワイドパーティションパターンの拡張です。このパターンでは、特定の時間間隔での一連の測定値がワイドパーティションに格納されます。ここで、測定時間はパーティションキーの一部として使用されます。このパターンは、ビジネス分析、センサーデータ管理、科学実験などの分野で頻繁に使用されます。
時系列パターンは、測定値以外のデータにも役立ちます。銀行アプリケーションの例を考えてみましょう。各顧客の残高を行に格納できますが、さまざまな顧客が自分の残高を確認したり、取引を行ったりすると、読み取りと書き込みの競合が多くなる可能性があります。残高が誤って更新されないように、書き込みをトランザクションでラップしたくなるかもしれません。対照的に、時系列スタイルの設計では、各トランザクションをタイムスタンプ付きの行として格納し、現在の残高を計算する作業はアプリケーションに任せます。
多くの新規ユーザーが陥る設計上の罠の1つは、Cassandraをキューとして使用しようとすることです。キュー内の各項目は、ワイドパーティションにタイムスタンプとともに格納されます。項目はキューの末尾に追加され、先頭から読み取られ、読み取られた後に削除されます。これは魅力的な設計であり、特に時系列パターンとの明らかな類似性を考えるとそうです。このアプローチの問題点は、削除された項目がトゥームストーン <asynch-deletes>
になり、Cassandraがキューの先頭から読み取るためにスキャンする必要があることです。時間の経過とともに、トゥームストーンの数が増加すると、読み取りパフォーマンスが低下し始めます。
キューのアンチパターンは、データの削除に依存する設計は、パフォーマンスが低下する可能性のある設計であることを示しています。
本書の内容は、『Cassandra, The Definitive Guide』(O'Reilly Media, Inc. 出版)から抜粋したものです。著作権 © 2020 Jeff Carpenter, Eben Hewitt. All rights reserved. 許可を得て使用しています。