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。
後續步驟
- 如要進一步瞭解 Cloud Bigtable,請參閱說明文件。
- 查看更深入的 Cloud Bigtable 程式碼研究室
- 自行試用其他 Google Cloud Platform 功能。歡迎參考我們的教學課程。
- 瞭解如何使用 OpenTSDB 整合監控時間序列資料