Exemple : Application "Hello World" en C++

Cet exemple présente une application très simple "Hello World", écrite en C++, et montre comment :

  • se connecter à une instance Cloud Bigtable ;
  • créer une table ;
  • Écrire des données dans une table
  • Relire les données
  • Supprimer la table

Exécuter l'exemple

Cet exemple utilise le package Cloud Bigtable de la bibliothèque cliente Google Cloud pour C++ afin de communiquer avec Cloud Bigtable.

Pour exécuter cet exemple de programme, suivez les instructions disponibles sur GitHub.

Utiliser la bibliothèque cliente Cloud avec Cloud Bigtable

L'exemple d'application permet de se connecter à Cloud Bigtable et décrit quelques opérations simples.

Installer et importer la bibliothèque cliente

Téléchargez ou clonez la bibliothèque cliente Cloud Bigtable pour C++ à partir de GitHub, puis compilez-la. Suivez les instructions de compilation disponibles dans le fichier README figurant à la racine.

Incluez les en-têtes obligatoires.

#include "google/cloud/bigtable/table.h"
#include "google/cloud/bigtable/table_admin.h"

Se connecter à Cloud Bigtable

Utilisez TableAdmin.CreateDefaultAdminClient() afin de créer un client d'administration que vous utiliserez pour créer une table.

cbt::TableAdmin table_admin(
    cbt::CreateDefaultAdminClient(project_id, cbt::ClientOptions()),
    instance_id);

Créer une table

Définissez un schéma pour la table possédant une famille de colonnes. Définissez une règle de récupération de mémoire pour la famille de colonnes afin de conserver au maximum une version de chaque valeur. Utilisez ce schéma pour instancier un objet de table à l'aide de TableAdmin.CreateTable(). Créez ensuite un client de données que vous pourrez utiliser pour transférer des données vers et depuis votre table.

// Define the desired schema for the Table.
cbt::GcRule gc_rule = cbt::GcRule::MaxNumVersions(1);
cbt::TableConfig schema({{"family", gc_rule}}, {});

// Create a table.
StatusOr<google::bigtable::admin::v2::Table> returned_schema =
    table_admin.CreateTable(table_id, schema);

// Create an object to access the Cloud Bigtable Data API.
cbt::Table table(cbt::CreateDefaultDataClient(project_id, instance_id,
                                              cbt::ClientOptions()),
                 table_id);

Écrire des lignes dans une table

Parcourez une liste de chaînes de salutation pour créer des lignes de table. À chaque itération, utilisez SingleRowMutation() pour définir une ligne et attribuez-lui une clé de ligne et une valeur. Appelez ensuite Table.Apply() pour appliquer la mutation à la ligne.

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

Créer un filtre

Avant de lire les données que vous avez écrites, créez un filtre à l'aide de Filter.ColumnRangeClosed() afin de limiter les données renvoyées par Cloud Bigtable. Ce filtre indique à Cloud Bigtable de ne renvoyer que la version la plus récente de chaque valeur, même si la table contient des versions antérieures qui n'ont pas fait l'objet d'une récupération de mémoire.

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

Lire une ligne à l'aide de sa clé

Appelez la fonction Table.ReadRow() en lui transmettant la clé de ligne et le filtre afin d'obtenir une version pour chaque valeur de cette ligne.

StatusOr<std::pair<bool, cbt::Row>> result = table.ReadRow("key-0", filter);
if (!result) throw std::runtime_error(result.status().message());
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";

Analyser toutes les lignes de la table

Utilisez Table.ReadRows() pour lire une plage de lignes de la table.

for (StatusOr<cbt::Row> const& row : table.ReadRows(
         cbt::RowRange::InfiniteRange(), cbt::Filter::PassAllFilter())) {
  if (!row) throw std::runtime_error(row.status().message());
  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";
  }
}

Supprimer une table

Supprimez la table à l'aide de DeleteTable().

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

Synthèse

Voici l'exemple complet sans commentaires.



#include "google/cloud/bigtable/table.h"
#include "google/cloud/bigtable/table_admin.h"
#include "google/cloud/bigtable/examples/bigtable_examples_common.h"
#include "google/cloud/internal/getenv.h"
#include "google/cloud/internal/random.h"
#include "google/cloud/testing_util/crash_handler.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;
  using google::cloud::StatusOr;

  cbt::TableAdmin table_admin(
      cbt::CreateDefaultAdminClient(project_id, cbt::ClientOptions()),
      instance_id);

  cbt::GcRule gc_rule = cbt::GcRule::MaxNumVersions(1);
  cbt::TableConfig schema({{"family", gc_rule}}, {});

  StatusOr<google::bigtable::admin::v2::Table> returned_schema =
      table_admin.CreateTable(table_id, schema);

  cbt::Table table(cbt::CreateDefaultDataClient(project_id, instance_id,
                                                cbt::ClientOptions()),
                   table_id);

  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::runtime_error(result.status().message());
  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 (StatusOr<cbt::Row> const& row : table.ReadRows(
           cbt::RowRange::InfiniteRange(), cbt::Filter::PassAllFilter())) {
    if (!row) throw std::runtime_error(row.status().message());
    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_id);
  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();

  cbt::TableAdmin admin(
      cbt::CreateDefaultAdminClient(project_id, cbt::ClientOptions{}),
      instance_id);

  examples::CleanupOldTables("hw-tbl-", admin);

  auto generator = google::cloud::internal::DefaultPRNG(std::random_device{}());
  auto table_id = examples::RandomTableId("hw-tbl-", generator);

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

}  // namespace

int main(int argc, char* argv[]) {
  google::cloud::testing_util::InstallCrashHandler(argv[0]);

  google::cloud::bigtable::examples::Example example({
      {"auto", RunAll},
      {"hello-world", BigtableHelloWorld},
  });
  return example.Run(argc, argv);
}