C++ hello world

本範例是以 C++ 編寫的簡易「hello world」應用程式,說明如何執行以下操作:

  • 設定驗證方法
  • 連線至 Bigtable 執行個體。
  • 建立新的資料表。
  • 將資料寫入資料表。
  • 讀取資料。
  • 刪除資料表。

設定驗證方法

如要在本機開發環境中使用本頁的 C++ 範例,請安裝並初始化 gcloud CLI,然後使用使用者憑證設定應用程式預設憑證。

  1. Install the Google Cloud CLI.

  2. If you're using an external identity provider (IdP), you must first sign in to the gcloud CLI with your federated identity.

  3. To initialize the gcloud CLI, run the following command:

    gcloud init
  4. If you're using a local shell, then create local authentication credentials for your user account:

    gcloud auth application-default login

    You don't need to do this if you're using Cloud Shell.

    If an authentication error is returned, and you are using an external identity provider (IdP), confirm that you have signed in to the gcloud CLI with your federated identity.

詳情請參閱 Set up authentication for a local development environment

執行範例

本範例使用 Google Cloud C++ 用戶端程式庫Cloud Bigtable 套件,與 Bigtable 進行通訊。

如要執行這個範例程式,請按照 GitHub 上的操作說明進行。

搭配 Bigtable 使用 Google Cloud 用戶端程式庫

這個應用程式範例會連線至 Bigtable,示範部分簡易作業。

安裝及匯入用戶端程式庫

從 GitHub 下載或複製 Bigtable C++ 用戶端程式庫,然後進行編譯。按照頂層 README 上的編譯器操作說明進行操作。

加入必要的標頭。

#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h"
#include "google/cloud/bigtable/resource_names.h"
#include "google/cloud/bigtable/table.h"

連線至 Bigtable

使用 MakeBigtableTableAdminConnection() 建構 BigtableTableAdminClient,用於建立資料表。

// Connect to the Cloud Bigtable Admin API.
cbta::BigtableTableAdminClient table_admin(
    cbta::MakeBigtableTableAdminConnection());

//! [connect data]
// Create an object to access the Cloud Bigtable Data API.
cbt::Table table(cbt::MakeDataConnection(),
                 cbt::TableResource(project_id, instance_id, table_id));
//! [connect data]

建立資料表

為具有一個資料欄系列的資料表定義結構定義,並為該資料欄系列設定垃圾收集規則,讓每個值最多只有一個版本。利用該結構定義使用 BigtableTableAdminClient::CreateTable() 將資料表物件例項化。然後建立一個資料用戶端,以便將資料輸入和輸出資料表。

// Define the desired schema for the Table.
google::bigtable::admin::v2::Table t;
auto& families = *t.mutable_column_families();
families["family"].mutable_gc_rule()->set_max_num_versions(1);

// Create a table.
std::string instance_name = cbt::InstanceName(project_id, instance_id);
StatusOr<google::bigtable::admin::v2::Table> schema =
    table_admin.CreateTable(instance_name, table_id, std::move(t));

將資料列寫入資料表

循環處理問候語字串清單,以在資料表中建立一些新的資料列。 在每個疊代作業中,使用 SingleRowMutation 定義資料列,並為其指派資料列索引鍵和值。然後呼叫 Table::Apply(),將變異套用到該資料列。

std::vector<std::string> greetings{"Hello World!", "Hello Cloud Bigtable!",
                                   "Hello C++!"};
int i = 0;
for (auto const& greeting : greetings) {
  // Each row has a unique row key.
  //
  // Note: This example uses sequential numeric IDs for simplicity, but
  // this can result in poor performance in a production application.
  // Since rows are stored in sorted order by key, sequential keys can
  // result in poor distribution of operations across nodes.
  //
  // For more information about how to design a Bigtable schema for the
  // best performance, see the documentation:
  //
  //     https://cloud.google.com/bigtable/docs/schema-design
  std::string row_key = "key-" + std::to_string(i);
  google::cloud::Status status = table.Apply(cbt::SingleRowMutation(
      std::move(row_key), cbt::SetCell("family", "c0", greeting)));

  if (!status.ok()) throw std::runtime_error(status.message());
  ++i;
}

建立篩選器

讀取已寫入的資料前,請先使用 Filter::ColumnRangeClosed() 建立篩選器,藉此限制 Bigtable 傳回的資料。即使資料表中含有已過期但尚未透過垃圾收集程序移除的舊儲存格,篩選器仍能指示 Bigtable 僅傳回每個值的最新版本。

cbt::Filter filter = cbt::Filter::ColumnRangeClosed("family", "c0", "c0");

依索引鍵讀取資料列

呼叫 Table::ReadRow() 函式並傳入資料列索引鍵和篩選器,即可取得該資料列中每個資料值的一個版本。

StatusOr<std::pair<bool, cbt::Row>> result = table.ReadRow("key-0", filter);
if (!result) throw std::move(result).status();
if (!result->first) {
  std::cout << "Cannot find row 'key-0' in the table: " << table.table_name()
            << "\n";
  return;
}
cbt::Cell const& cell = result->second.cells().front();
std::cout << cell.family_name() << ":" << cell.column_qualifier() << "    @ "
          << cell.timestamp().count() << "us\n"
          << '"' << cell.value() << '"' << "\n";

掃描所有資料表資料列

使用 Table::ReadRows() 讀取資料表中特定範圍的資料列。

for (auto& row : table.ReadRows(cbt::RowRange::InfiniteRange(),
                                cbt::Filter::PassAllFilter())) {
  if (!row) throw std::move(row).status();
  std::cout << row->row_key() << ":\n";
  for (cbt::Cell const& c : row->cells()) {
    std::cout << "\t" << c.family_name() << ":" << c.column_qualifier()
              << "    @ " << c.timestamp().count() << "us\n"
              << "\t\"" << c.value() << '"' << "\n";
  }
}

刪除資料表

使用 BigtableTableAdminClient::DeleteTable() 刪除資料表。

google::cloud::Status status = table_admin.DeleteTable(table.table_name());
if (!status.ok()) throw std::runtime_error(status.message());

全面整合使用

以下是沒有註解的完整範例。



#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h"
#include "google/cloud/bigtable/resource_names.h"
#include "google/cloud/bigtable/table.h"
#include "google/cloud/bigtable/examples/bigtable_examples_common.h"
#include "google/cloud/bigtable/testing/random_names.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/internal/random.h"
#include "google/cloud/log.h"
#include <iostream>

namespace {

using ::google::cloud::bigtable::examples::Usage;

void BigtableHelloWorld(std::vector<std::string> const& argv) {
  if (argv.size() != 3) {
    throw Usage{"hello-world <project-id> <instance-id> <table-id>"};
  }
  std::string const& project_id = argv[0];
  std::string const& instance_id = argv[1];
  std::string const& table_id = argv[2];

  namespace cbt = ::google::cloud::bigtable;
  namespace cbta = ::google::cloud::bigtable_admin;
  using ::google::cloud::StatusOr;

  cbta::BigtableTableAdminClient table_admin(
      cbta::MakeBigtableTableAdminConnection());

  cbt::Table table(cbt::MakeDataConnection(),
                   cbt::TableResource(project_id, instance_id, table_id));

  google::bigtable::admin::v2::Table t;
  auto& families = *t.mutable_column_families();
  families["family"].mutable_gc_rule()->set_max_num_versions(1);

  std::string instance_name = cbt::InstanceName(project_id, instance_id);
  StatusOr<google::bigtable::admin::v2::Table> schema =
      table_admin.CreateTable(instance_name, table_id, std::move(t));

  std::vector<std::string> greetings{"Hello World!", "Hello Cloud Bigtable!",
                                     "Hello C++!"};
  int i = 0;
  for (auto const& greeting : greetings) {
    std::string row_key = "key-" + std::to_string(i);
    google::cloud::Status status = table.Apply(cbt::SingleRowMutation(
        std::move(row_key), cbt::SetCell("family", "c0", greeting)));

    if (!status.ok()) throw std::runtime_error(status.message());
    ++i;
  }

  cbt::Filter filter = cbt::Filter::ColumnRangeClosed("family", "c0", "c0");

  StatusOr<std::pair<bool, cbt::Row>> result = table.ReadRow("key-0", filter);
  if (!result) throw std::move(result).status();
  if (!result->first) {
    std::cout << "Cannot find row 'key-0' in the table: " << table.table_name()
              << "\n";
    return;
  }
  cbt::Cell const& cell = result->second.cells().front();
  std::cout << cell.family_name() << ":" << cell.column_qualifier() << "    @ "
            << cell.timestamp().count() << "us\n"
            << '"' << cell.value() << '"' << "\n";

  for (auto& row : table.ReadRows(cbt::RowRange::InfiniteRange(),
                                  cbt::Filter::PassAllFilter())) {
    if (!row) throw std::move(row).status();
    std::cout << row->row_key() << ":\n";
    for (cbt::Cell const& c : row->cells()) {
      std::cout << "\t" << c.family_name() << ":" << c.column_qualifier()
                << "    @ " << c.timestamp().count() << "us\n"
                << "\t\"" << c.value() << '"' << "\n";
    }
  }

  google::cloud::Status status = table_admin.DeleteTable(table.table_name());
  if (!status.ok()) throw std::runtime_error(status.message());
}

void RunAll(std::vector<std::string> const& argv) {
  namespace examples = ::google::cloud::bigtable::examples;
  namespace cbt = ::google::cloud::bigtable;

  if (!argv.empty()) throw Usage{"auto"};
  if (!examples::RunAdminIntegrationTests()) return;
  examples::CheckEnvironmentVariablesAreSet({
      "GOOGLE_CLOUD_PROJECT",
      "GOOGLE_CLOUD_CPP_BIGTABLE_TEST_INSTANCE_ID",
  });
  auto const project_id =
      google::cloud::internal::GetEnv("GOOGLE_CLOUD_PROJECT").value();
  auto const instance_id = google::cloud::internal::GetEnv(
                               "GOOGLE_CLOUD_CPP_BIGTABLE_TEST_INSTANCE_ID")
                               .value();

  auto generator = google::cloud::internal::DefaultPRNG(std::random_device{}());
  auto table_id = cbt::testing::RandomTableId(generator);

  std::cout << "\nRunning the BigtableHelloWorld() example" << std::endl;
  BigtableHelloWorld({project_id, instance_id, table_id});
}

}  // namespace

int main(int argc, char* argv[]) try {
  google::cloud::bigtable::examples::Example example({
      {"auto", RunAll},
      {"hello-world", BigtableHelloWorld},
  });
  return example.Run(argc, argv);
} catch (std::exception const& ex) {
  std::cerr << ex.what() << "\n";
  ::google::cloud::LogSink::Instance().Flush();
  return 1;
}