適用於 Cassandra 使用者的 Cloud BigTable

1. 簡介

這個程式碼研究室適用於將查詢從 Apache Cassandra 遷移至 Google Cloud Bigtable 的使用者。

在本程式碼研究室中

  • 使用 Cloud Bigtable 模擬器
  • 瞭解時間序列用途
  • 建立資料表和資料欄系列
  • 瞭解 CQL 插入、更新、選取和刪除的 Cloud Bigtable Java 對等項目

您對 Google Cloud Platform 使用經驗的評價如何?

新手 中級 還算容易

您會如何使用這個教學課程?

僅供閱讀 閱讀並完成練習

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 的索引鍵均用於分割 (分區) 和排序。就主鍵/資料列索引鍵建構而言,這兩個系統非常相似。基本上,兩個系統都是按照字母順序排列的清單,其中鍵是節點間的主要資料列分佈格式。在大部分的情況下,您可以為 Cloud Bigtable 重複使用相同的金鑰。

在本程式碼研究室中,您將使用 Cloud Bigtable 來儲存關於手機和平板電腦的時間序列資料 (避免與 Bigtable Tablet 混淆)。以下是建立資料表的操作說明。

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]」的資料列索引鍵,依序插入一列和多個資料列。

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

針對大量變更物件定義多個異動,然後使用資料用戶端,透過單一 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 選取陳述式時,您必須考慮某些面向,例如資料欄、篩選位置子句,以及限制和匯總函式,例如分組依據。在這裡,雖然只需查看兩個簡單的選取陳述式,瞭解基本概念,但不妨參閱說明文件,進一步瞭解如何選取。在 Cloud Bigtable 中,擷取作業有兩種類型:Get 和 Scan。GET 擷取一個資料列,掃描則會擷取資料列範圍。

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

單身

使用資料列查詢,取得特定日期範圍內的特定手機資料,且全都位於同一列。這樣會傳回每個加上時間戳記的值版本,所以您應該會看到不同時間戳記的 Linked_cell 資料。

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

單曲

您可以在這裡刪除特定手機和日期的資料,使用資料列索引鍵,一次刪除一列。

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。

後續步驟