Getting Started with Bigtable
This example is a very simple "hello world" application, written in C++, that illustrates how to:
- Connect to a Cloud Bigtable instance.
- Create a new table.
- Write data to the table.
- Read the data back.
- Delete the table.
Running the example
This example uses the Cloud Bigtable C++ Client Library to communicate with Cloud Bigtable.
To run the example program, follow the instructions for the example on GitHub.
Including the Necessary Headers
The example uses the following headers:
#include "google/cloud/bigtable/admin/bigtable_table_admin_client.h"
#include "google/cloud/bigtable/resource_names.h"
#include "google/cloud/bigtable/table.h"
Introduce aliases to make the example more readable
namespace cbt = ::google::cloud::bigtable;
namespace cbta = ::google::cloud::bigtable_admin;
using ::google::cloud::StatusOr;
Connecting to Cloud Bigtable to manage tables
To manage tables, connect to Cloud Bigtable using bigtable_admin::MakeBigtableTableAdminConnection()
:
// Connect to the Cloud Bigtable Admin API.
cbta::BigtableTableAdminClient table_admin(
cbta::MakeBigtableTableAdminConnection());
// Create an object to access the Cloud Bigtable Data API.
cbt::Table table(cbt::MakeDataConnection(),
cbt::TableResource(project_id, instance_id, table_id));
See Also
bigtable_admin::BigtableTableAdminClient
for more information on how to perform administrative operations on tables.
Creating a table
Create a table with 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));
See Also
bigtable::BigtableTableAdminClient
for additional operations to list, read, modify, and delete tables.
See Also
https://cloud.google.com/bigtable/docs/overview for an overview of the Cloud Bigtable storage model, including an introduction to important Cloud Bigtable concepts, such as row keys, column families, columns, and cells.
See Also
https://cloud.google.com/bigtable/docs/schema-design for suggestions on how to design your table schema.
Connecting to Cloud Bigtable to read and write data
To read and write data, connect to Cloud Bigtable using bigtable::MakeDataConnection()
:
// Create an object to access the Cloud Bigtable Data API.
cbt::Table table(cbt::MakeDataConnection(),
cbt::TableResource(project_id, instance_id, table_id));
See Also
bigtable::Table
for the functions to read and write data to Cloud Bigtable.
Writing Rows to a table
To write a single row use 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;
}
See Also
Table::BulkApply()
to modify multiple rows in a single request.
See Also
DeleteFromFamily()
, DeleteFromRow()
, DeleteFromColumn()
to delete some (or all) the cells in a row.
See Also
One of the overloads for SetCell()
allows setting an explicit timestamp, which is an idempotent mutation and thus can be automatically retried on transient errors.
Creating filter for the column families
Use a filter to select only a subset of the cells in a row, in this case, we will select only the rows in the family
column family and the c0
column:
cbt::Filter filter = cbt::Filter::ColumnRangeClosed("family", "c0", "c0");
See Also
bigtable::Filter
to filter the column families, columns, and even the timestamps returned by ReadRow()
.
Reading data back: get a single row by its key
Get a row directly using its key with 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";
See Also
bigtable::Filter
to filter the column families, columns, and even the timestamps returned by ReadRow()
.
See Also
Table::ReadRows()
to iterate over multiple rows.
Reading data back: scanning all table rows
Use Table::ReadRows()
to scan all of the rows in a table.
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";
}
}
See Also
bigtable::RowRange
to read only a portion of the table.
See Also
bigtable::RowSet
to form arbitrary groups of ranges and specific row keys in a Table::ReadRows()
request.
See Also
bigtable::Row
for details of the contents in a row.
Deleting a table
Delete a table with BigtableTableAdminClient::DeleteTable()
.
google::cloud::Status status = table_admin.DeleteTable(table.table_name());
if (!status.ok()) throw std::runtime_error(status.message());
Putting it all together
Here is the full example
#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];
// Create a namespace alias to make the code easier to read.
namespace cbt = ::google::cloud::bigtable;
namespace cbta = ::google::cloud::bigtable_admin;
using ::google::cloud::StatusOr;
// Connect to the Cloud Bigtable Admin API.
cbta::BigtableTableAdminClient table_admin(
cbta::MakeBigtableTableAdminConnection());
// Create an object to access the Cloud Bigtable Data API.
cbt::Table table(cbt::MakeDataConnection(),
cbt::TableResource(project_id, instance_id, table_id));
// 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));
// Modify (and create if necessary) a row.
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;
}
cbt::Filter filter = cbt::Filter::ColumnRangeClosed("family", "c0", "c0");
// Read a single row.
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";
// Read all rows.
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";
}
}
// Delete the table
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;
}