C++ の Hello World

この例は、C++ で記述された単純な「Hello World」アプリケーションで、以下の処理を行います。

  • 認証の設定
  • Bigtable インスタンスに接続する
  • 新しいテーブルを作成する
  • テーブルにデータを書き込む
  • そのデータを読み取る
  • テーブルを削除する

認証を設定する

ローカル開発環境でこのページの C++ サンプルを使用するには、gcloud CLI をインストールして初期化し、ユーザー認証情報を使用してアプリケーションのデフォルト認証情報を設定します。

  1. Install the Google Cloud CLI.
  2. To initialize the gcloud CLI, run the following command:

    gcloud init
  3. 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.

詳細については Set up authentication for a local development environment をご覧ください。

サンプルの実行

この例では C++ 用 Google Cloud クライアント ライブラリ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]

テーブルの作成

1 つの列ファミリーを含むテーブルのスキーマを定義します。列ファミリーのガベージ コレクション ルールを設定して、各値に最大で 1 つのバージョンが保持されるようにします。このスキーマに従い、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 を使用して 1 行を定義し、それに行キーと値を割り当てます。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() 関数を呼び出して行キーとフィルタを渡し、その行に含まれる値ごとに 1 つのバージョンを取得します。

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;
}