1. 概要

Cassandraは、パフォーマンスを損なうことなく高可用性と水平スケーラビリティを提供するNoSQLデータベースです。

Cassandraから最高のパフォーマンスを引き出すには、目前のビジネス上の問題に固有のクエリパターンを中心にスキーマを慎重に設計する必要があります。

この記事では、Cassandraでデータモデリングにアプローチする方法に関するいくつかの重要な概念を確認します。

先に進む前に、 Cassandra with Java の記事を読んで、Javaを使用してCassandraに接続する方法と基本を理解することができます。

2. パーティションキー

Cassandraは、データがクラスター内の複数のノードに分割されて保存される分散データベースです。

パーティションキーは1つ以上のデータフィールドで構成され、パーティショナーがハッシュを介してトークンを生成し、クラスター全体にデータを均一に分散するために使用します

3. クラスタリングキー

クラスタリングキーは1つ以上のフィールドで構成されており、同じパーティションキーを使用して行をクラスタリングまたはグループ化し、並べ替えられた順序で格納するのに役立ちます。

Cassandraに時系列データを格納していて、時系列でデータを取得したいとします。 時系列データフィールドを含むクラスタリングキーは、このユースケースのデータを効率的に取得するのに非常に役立ちます。

注:パーティションキーとクラスタリングキーの組み合わせが主キーを構成し、Cassandraクラスター内のすべてのレコードを一意に識別します。

4. クエリパターンに関するガイドライン

Cassandraでのデータモデリングを開始する前に、クエリパターンを特定し、それらが次のガイドラインに準拠していることを確認する必要があります。

  1. 各クエリは、単一のパーティションからデータをフェッチする必要があります
  2. Cassandraには単一のパーティションに格納できる列の数に制限があるため、パーティションに格納されるデータの量を追跡する必要があります
  3. 同じデータに対して異なる種類のクエリパターンをサポートするために、データを非正規化して複製することは問題ありません

上記のガイドラインに基づいて、実際のユースケースと、それらのCassandraデータモデルをモデル化する方法を見てみましょう。

5. 実世界のデータモデリングの例

5.1. Facebookの投稿

さまざまなユーザーのFacebook投稿をCassandraに保存しているとします。 一般的なクエリパターンの1つは、特定のユーザーによって作成された上位の「N」投稿をフェッチすることです。

したがって、上記のガイドラインに従って、特定のユーザーのすべてのデータを単一のパーティションに保存する必要があります。

また、投稿のタイムスタンプをクラスタリングキーとして使用すると、上位の「N」投稿をより効率的に取得するのに役立ちます。

このユースケースのCassandraテーブルスキーマを定義しましょう。

CREATE TABLE posts_facebook (
  user_id uuid,
  post_id timeuuid, 
  content text,
  PRIMARY KEY (user_id, post_id) )
WITH CLUSTERING ORDER BY (post_id DESC);

それでは、ユーザーAnnaの上位20件の投稿を検索するクエリを作成しましょう。

SELECT content FROM posts_facebook WHERE user_id = "Anna_id" LIMIT 20

5.2. 全国のジム

多くの国のさまざまな都市や州にまたがるさまざまなパートナージムの詳細を保存していて、特定の都市のジムを取得したいとします。

また、ジムを開業日で並べ替えた結果を返す必要があるとします。

上記のガイドラインに基づいて、特定の州と国の特定の都市にあるジムを1つのパーティションに保存し、オープン日とジム名をクラスタリングキーとして使用する必要があります。

この例のCassandraテーブルスキーマを定義しましょう。

CREATE TABLE gyms_by_city (
 country_code text,
 state text,
 city text,
 gym_name text,
 opening_date timestamp,
 PRIMARY KEY (
   (country_code, state_province, city), 
   (opening_date, gym_name)) 
 WITH CLUSTERING ORDER BY (opening_date ASC, gym_name ASC);

それでは、米国内のフェニックス市の開業日までに最初の10のジムを取得するクエリを見てみましょう。 アリゾナ州:

SELECT * FROM gyms_by_city
  WHERE country_code = "us" AND state = "Arizona" AND city = "Phoenix"
  LIMIT 10

次に、米国内のフェニックス市に最近オープンした10のジムを取得するクエリを見てみましょう。 アリゾナ州:

SELECT * FROM gyms_by_city
  WHERE country_code = "us" and state = "Arizona" and city = "Phoenix"
  ORDER BY opening_date DESC 
  LIMIT 10

注:最後のクエリの並べ替え順序は、テーブルの作成時に定義された並べ替え順序とは逆であるため、Cassandraが最初にデータをフェッチしてからメモリに並べ替えるため、クエリの実行速度が低下します。

5.3. Eコマースの顧客と製品

eコマースストアを運営していて、CustomerおよびProductの情報をCassandra内に保存しているとします。 このユースケースに関連する一般的なクエリパターンのいくつかを見てみましょう。

  1. 顧客情報を取得する
  2. 製品情報を取得する
  3. 特定の製品が好きなすべての顧客を取得します
  4. すべての製品を特定の顧客のいいね!

まず、CustomerProductの情報を格納するために別々のテーブルを使用することから始めます。 ただし、上記の3番目と4番目のクエリをサポートするには、かなりの量の非正規化を導入する必要があります。

これを実現するために、さらに2つのテーブル「Customer_by_Product」と「Product_by_Customer」を作成します。

この例のCassandraテーブルスキーマを見てみましょう。

CREATE TABLE Customer (
  cust_id text,
  first_name text, 
  last_name text,
  registered_on timestamp, 
  PRIMARY KEY (cust_id));

CREATE TABLE Product (
  prdt_id text,
  title text,
  PRIMARY KEY (prdt_id));

CREATE TABLE Customer_By_Liked_Product (
  liked_prdt_id text,
  liked_on timestamp,
  title text,
  cust_id text,
  first_name text, 
  last_name text, 
  PRIMARY KEY (prdt_id, liked_on));

CREATE TABLE Product_Liked_By_Customer (
  cust_id text, 
  first_name text,
  last_name text,
  liked_prdt_id text, 
  liked_on timestamp,
  title text,
  PRIMARY KEY (cust_id, liked_on));

注:クエリ、特定の顧客による最近高く評価された製品、および特定の製品を最近高く評価した顧客の両方をサポートするために、クラスタリングキーとして「liked_on」列を使用しました。

クエリを見て、最近製品「Pepsi」を気に入った10人の顧客を見つけましょう。

SELECT * FROM Customer_By_Liked_Product WHERE title = "Pepsi" LIMIT 10

そして、「 Anna 」という名前の顧客が最近気に入った製品(最大10個)を見つけるクエリを見てみましょう。

SELECT * FROM Product_Liked_By_Customer 
  WHERE first_name = "Anna" LIMIT 10

6. 非効率的なクエリパターン

Cassandraがデータを保存する方法が原因で、次のような一部のクエリパターンはまったく効率的ではありません。

  • 複数のパーティションからのデータのフェッチ–これには、コーディネーターが複数のノードからデータをフェッチし、一時的にヒープに保存してから、結果をユーザーに返す前にデータを集約する必要があります。
  • 結合ベースのクエリ–分散型であるため、Cassandraは、リレーショナルデータベースと同じようにクエリでテーブル結合をサポートしていません。その結果、クエリで結合します。速度が低下し、不整合や可用性の問題が発生する可能性もあります

7. 結論

このチュートリアルでは、Cassandraでデータモデリングに取り組む方法に関するいくつかのベストプラクティスについて説明しました。

Cassandraクラスターから最高のパフォーマンスを得る正しいデータモデルを設計するには、コアコンセプトを理解し、クエリパターンを事前に特定する必要があります。