Cassandra ユーザー向け Cloud Bigtable

1. はじめに

この Codelab は、Apache Cassandra から Google Cloud Bigtable にクエリを移行する方を対象としたガイドです。

この Codelab では、

  • Cloud Bigtable エミュレータを使用する
  • 時系列のユースケースを確認する
  • テーブルと列ファミリーを作成する
  • CQL の Insert、Update、Select、Delete に相当する Cloud Bigtable Java の機能について学ぶ

Google Cloud Platform の使用経験をどのように評価されますか。

初心者 中級者 上級者

このチュートリアルの利用方法をお選びください。

<ph type="x-smartling-placeholder"></ph> 通読のみ 内容を読んで演習を済ませる をご覧ください。

2. 設定

ここでは、主要なコンセプトをすばやく理解できるように、わずか数行のサンプル データセットを表示します。

Cassandra

各ステップには同等の Cassandra クエリが存在するため、必要に応じてローカル クラスタに沿って操作するか、クリック デプロイ Cassandra クラスタをすばやく設定して SSH で接続します。

手順を進める場合は、キースペースを作成して使用します。ここではレプリケーション戦略は重要ではありません。

cqlsh> create keyspace mykeyspace with replication = {'class':'SimpleStrategy','replication_factor' : 2};
cqlsh> use mykeyspace;

Cloud Bigtable

テーブルには Cloud Bigtable インスタンスが必要です。エミュレータを使用すると、ローカル インスタンスを無料でセットアップできます。Cloud Bigtable でキースペースを作成する必要はありません。レプリケーションはインスタンス構成によって処理されます。

次のコマンドを使用して、エミュレータを起動します。

gcloud beta emulators bigtable start

次に、別のシェル ウィンドウまたはタブで、次のコマンドを使用してエミュレータの環境変数を設定します。

$(gcloud beta emulators bigtable env-init) #Sets BIGTAB`LE_EMULATOR_HOST

次に、コードサンプルの実行に使用する Java プロジェクトを作成し、Maven、Gradle、または SBT で Cloud Bigtable クライアントをインポートします。次に、新しい Java ファイルで、データ クライアントへの接続を作成します。

BigtableDataSettings settings =
    BigtableDataSettings.newBuilder().setProjectId(projectId).setInstanceId(instanceId).build();

try {
  dataClient = BigtableDataClient.create(settings);
} catch (Exception e) {
  System.out.println("Error during data client connection: \n" + e.toString());
}

3. テーブルの作成

Cassandra テーブルと Cloud Bigtable テーブルの両方で、各行にキーが関連付けられています。Cassandra キーにはパーティション キーとクラスタリング列があり、これらは別々にすることも重複することも可能です。Cloud Bigtable のキー全体は、分割(パーティション)と順序付けに使用されます。これら 2 つのシステムは、主キー/行キーの構成という点では非常によく似ています。どちらのシステムも基本的には辞書順に並べられたリストであり、キーはノード間の行分散の主要な形式として機能します。ほとんどの場合、Cloud Bigtable では同じキーを再利用できます。

この Codelab では、Cloud Bigtable を使用してスマートフォンやタブレットに関する時系列データを保存します(Bigtable タブレットとは異なります)。テーブルを作成する手順は次のとおりです。

Cassandra

cqlsh:mykeyspace> create table mobileTimeSeries (
           deviceid text,
           devicetype text,
           date date,
           connected_cell map<timestamp,Boolean>, 
           os_build text, 
           os_name text,
           PRIMARY KEY((devicetype, deviceid), date));

Cloud Bigtable

テーブルと列ファミリーは Java クライアントを使用して作成できますが、cbt ツールで次のコマンドを使用するのが最も簡単です。

cbt createtable mobile-time-series families=stats_summary

Cloud Bigtable は NoSQL データベースであるため、テーブルの作成時にスキーマを定義する必要はありませんが、実行するクエリを検討し、その行キーを最適化する必要があります。

キーの移行の最も一般的な方法は、すべてのパーティション キーとクラスタリング列を単純に結合して、Cloud Bigtable 行キーを表す文字列を形成することです。通常は、Key Visualizer を使用した鍵配布のデバッグに役立つ文字列ベースの鍵を使用することをおすすめします。ハッシュ「#」などの区切り文字を使用できます。行と列の間の関係を見ていきます。

この例では、行キー「[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]」を使用します。

4. インサート

挿入は、Cassandra と Cloud Bigtable の間でよく似ています。ここでは、行キー「[DEVICE_TYPE]#[DEVICE_ID]#[YYYYMMDD]」を使用して行を 1 つ挿入してから、複数の行を挿入します。

Cassandra

シングル

cqlsh:mykeyspace> insert into mobileTimeSeries (deviceid, devicetype, date, connected_cell, os_build) values ('4c410523', 'phone',toDate(now()), {toTimeStamp(now()): true}, 'PQ2A.190405.003');

Batch

cqlsh:mykeyspace> BEGIN BATCH
insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-01', 'chromeos', '12155.0.0-rc1');
insert into mobileTimeSeries (deviceid, devicetype, date, os_name, os_build) values ('a0b81f74', 'tablet', '2019-01-02','chromeos', '12145.0.0-rc6');
APPLY BATCH;

Cloud Bigtable

シングル

使用する行キーとデータでミューテーションを作成し、データ クライアントでミューテーションを適用します。スマートフォンのデータ行と、そのスマートフォンの接続とオペレーティング システムに関する情報を追加します。

try {
  System.currentTimeMillis();
  long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00

  String rowKey = "phone#4c410523#20190501";
  ByteString one = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 1});

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(
              COLUMN_FAMILY_NAME,
              ByteString.copyFrom("connected_cell".getBytes()),
              timestamp,
              one)
          .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "PQ2A.190405.003");

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during Write: \n" + e.toString());
}

Batch

batchMutation オブジェクトに複数のミューテーションを定義してから、データ クライアントを使用して 1 回の API 呼び出しですべてのミューテーションを適用します。モバイル タブレットのオペレーティング システムの名前とバージョンに関する数日分のデータを追加します。

try {
  long timestamp = (long) 1556712000 * 1000; // Timestamp of June 1, 2019 12:00

  BulkMutation bulkMutation =
      BulkMutation.create(tableId)
          .add(
              "tablet#a0b81f74#20190501",
              Mutation.create()
                  .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
                  .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc1"))
          .add(
              "tablet#a0b81f74#20190502",
              Mutation.create()
                  .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "chromeos")
                  .setCell(COLUMN_FAMILY_NAME, "os_build", timestamp, "12155.0.0-rc6"));

  dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
  System.out.println("Error during WriteBatch: \n" + e.toString());
}

5. 更新情報

ここでは、まだ書き込まれていないセルを更新し、以前のバージョンを維持したままセルに新しい値を書き込みます。

Cassandra

セルの追加

cqlsh:mykeyspace> UPDATE mobileTimeSeries SET os_name = 'android' WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';

セルの更新

cqlsh:mykeyspace> UPDATE mobileTimeSeries SET connected_cell = connected_cell +  {toTimeStamp(now()): false} WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-06';

Cloud Bigtable

Cloud Bigtable では、更新を書き込みと同じように扱うだけです。

セルの追加

これはセルの書き込みと同じですが、以前に書き込んだことのない列を指定します。ここでは、スマートフォンの行にオペレーティング システム名を追加します。

try {
  long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30

  String rowKey = "phone#4c410523#20190501";

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(COLUMN_FAMILY_NAME, "os_name", timestamp, "android");

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during update: \n" + e.toString());
}

セルを更新しています

ここでは、スマートフォンのモバイル接続状況に関する新しいデータを追加します。セルのバージョンを使用すると、時系列データの一部を簡単に保存できます。書き込みのタイムスタンプを指定するだけで、セルの新しいバージョンを追加できます。データをクリーンアップするには、ガベージ コレクションを使用して、一定数または一定時間が経過したバージョンを削除します。

try {
  long timestamp = (long) 1556713800 * 1000; // Timestamp of June 1, 2019 12:30

  String rowKey = "phone#4c410523#20190501";

  ByteString zero = ByteString.copyFrom(new byte[] {0, 0, 0, 0, 0, 0, 0, 0});

  RowMutation rowMutation =
      RowMutation.create(tableId, rowKey)
          .setCell(
              COLUMN_FAMILY_NAME,
              ByteString.copyFrom("connected_cell".getBytes()),
              timestamp,
              zero);

  dataClient.mutateRow(rowMutation);
} catch (Exception e) {
  System.out.println("Error during update2: \n" + e.toString());
}

6. 選択

次に、テーブルに書き込んだデータを取得します。CQL の SELECT ステートメントを移行するときは、列、WHERE 句によるフィルタ、group by などの制限および集計関数など、SELECT ステートメントのいくつかの側面を考慮する必要があります。ここでは、基本的な考え方を理解するために 2 つのシンプルな SELECT ステートメントを見ていきますが、選択の詳細についてはドキュメントをご覧ください。Cloud Bigtable には、Get と Scan という 2 種類の取得オペレーションがあります。Get は 1 行を取得し、Scan は行の範囲を取得します。

Cassandra

シングル

cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='phone' AND deviceid = '4c410523' AND date = '2019-09-04';

複数

cqlsh:mykeyspace> SELECT * FROM mobileTimeSeries WHERE devicetype='tablet' AND deviceid = 'a0b81f74' AND date >= '2019-09-04';

Cloud Bigtable

独身

行検索を使用すると、指定した日付における特定のスマートフォンのデータがすべて 1 行にまとめられます。これにより、タイムスタンプが付けられたバージョンの値が返されるため、connect_cell の 2 行でタイムスタンプの異なる値になったことを確認できます。

try {
  String rowKey = "phone#4c410523#20190501";

  Row row = dataClient.readRow(tableId, rowKey);
  for (RowCell cell : row.getCells()) {

    System.out.printf(
        "Family: %s    Qualifier: %s    Value: %s    Timestamp: %s%n",
        cell.getFamily(),
        cell.getQualifier().toStringUtf8(),
        cell.getValue().toStringUtf8(),
        cell.getTimestamp());
  }
} catch (Exception e) {
  System.out.println("Error during lookup: \n" + e.toString());
}

複数

レンジスキャンを使用すると、指定したモバイル タブレットの月別データが複数の行に分散して表示されます。フィルタを使って特定のバージョンのデータのみを取得したり、値でフィルタしたりできます。

try {
  Query query = Query.create(tableId).range("tablet#a0b81f74#201905", "tablet#a0b81f74#201906");
  ServerStream<Row> rowStream = dataClient.readRows(query);
  for (Row row : rowStream) {
    System.out.println("Row Key: " + row.getKey().toStringUtf8());
    for (RowCell cell : row.getCells()) {

      System.out.printf(
          "Family: %s    Qualifier: %s    Value: %s    Timestamp: %s%n",
          cell.getFamily(),
          cell.getQualifier().toStringUtf8(),
          cell.getValue().toStringUtf8(),
          cell.getTimestamp());
    }
  }
} catch (Exception e) {
  System.out.println("Error during scan: \n" + e.toString());
}

7. 削除

ここで、テーブルに追加したデータを削除します。まず、個々の行を削除してから、複数の行を削除します。

Cassandra の CQL では、すべてのプライマリ列が指定されている場合に、単一行の削除と範囲の削除が可能です。Bigtable では、ある範囲をスキャンしてから行レベルの削除を実行することで、これを実現できます。結果は同じですが、各削除がそれぞれ独自のオペレーションとなるため、より多くのオペレーションが得られます。

Cassandra

シングル

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='phone' and deviceid = '4c410523';

複数

cqlsh:mykeyspace> DELETE from mobileTimeSeries where devicetype='tablet' and deviceid = 'a0b81f74';

Cloud Bigtable

シングル

ここでは、特定のスマートフォンと日付のデータを削除します。行キーを使用して行を 1 つずつ削除します。

try {
  String rowKey = "phone#4c410523#20190501";

  RowMutation mutation = RowMutation.create(tableId, rowKey).deleteRow();

  dataClient.mutateRow(mutation);
} catch (Exception e) {
  System.out.println("Error during Delete: \n" + e.toString());
}

複数

ここで、特定のモバイル タブレットのデータをすべて削除します。複数の行を削除する CQL クエリを移行するには、スキャンを実行し、結果として得られる行キーのセットを使用して各行を削除する必要があります。

try {
  Query query = Query.create(tableId).prefix("tablet#a0b81f7");
  ServerStream<Row> rowStream = dataClient.readRows(query);
  BulkMutation bulkMutation = BulkMutation.create(tableId);
  for (Row row : rowStream) {
    bulkMutation.add(row.getKey(), Mutation.create().deleteRow());
  }

  dataClient.bulkMutateRows(bulkMutation);
} catch (Exception e) {
  System.out.println("Error during DeleteMultiple: \n" + e.toString());
}

8. 最終処理

クリーンアップ

Cassandra

この手順に沿う Cassandra クラスタを作成した場合は、通常どおりに自由に削除できます。

Cloud Bigtable

既存の Cloud Bigtable インスタンスにテーブルを作成した場合は、cbt コマンドを使用してテーブルを削除できます。

cbt deletetable mobile-time-series

エミュレータを使用した場合は、エミュレータを起動したターミナルで Ctrl+C キーを押すだけで、エミュレータを停止するだけですべての作業を消去できます。

次のステップ