C# 版 Hello World
本代码示例是一个使用 C# 编写的“hello world”应用,说明如何完成以下任务:
- 设置身份验证
- 连接到 Bigtable 实例
- 新建一个表。
- 将数据写入表中。
- 重新读取这些数据。
- 删除表。
设置身份验证
如需从本地开发环境使用本页面上的 .NET 示例,请安装并初始化 gcloud CLI,然后使用用户凭据设置应用默认凭据。
- 安装 Google Cloud CLI。
-
如需初始化 gcloud CLI,请运行以下命令:
gcloud init
-
为您的 Google 账号创建本地身份验证凭据:
gcloud auth application-default login
如需了解详情,请参阅 为本地开发环境设置身份验证。
运行示例
本代码使用 .NET 版 Google Cloud 客户端库中的 C# Admin API 库和 C# Data API 库与 Bigtable 进行通信。
如需运行此示例程序,请按照 GitHub 上的 .NET Bigtable 示例说明执行操作。完成构建和运行以及快速入门中的步骤,创建可在 Hello World 应用中使用的资源。请务必修改 HelloWorld.cs
文件,添加您所创建资源的名称。
将 Cloud 客户端库与 Bigtable 搭配使用
示例应用会连接到 Bigtable 并演示一些简单操作。
连接到 Bigtable
首先,请创建两个可用于连接到 Bigtable 的客户端对象。C# Admin API BigtableTableAdminClient
可帮助您创建和删除实例与表。C# Data API BigtableClient
可帮助您读取和写入表数据。
// BigtableTableAdminClient API lets us create, manage and delete tables.
BigtableTableAdminClient bigtableTableAdminClient = BigtableTableAdminClient.Create();
// BigtableClient API lets us read and write to a table.
BigtableClient bigtableClient = BigtableClient.Create();
创建表
调用 BigtableTableAdminClient
类中的 CreateTable()
方法,以生成用于存储“hello world”问候语的 Table
对象。该表有一个列族,其中保留了每个值的一个版本。
// Create a table with a single column family.
Console.WriteLine($"Create new table: {tableId} with column family: {columnFamily}, instance: {instanceId}");
// Check whether a table with given TableName already exists.
if (!TableExist(bigtableTableAdminClient))
{
bigtableTableAdminClient.CreateTable(
new InstanceName(projectId, instanceId),
tableId,
new Table
{
Granularity = Table.Types.TimestampGranularity.Millis,
ColumnFamilies =
{
{
columnFamily, new ColumnFamily
{
GcRule = new GcRule
{
MaxNumVersions = 1
}
}
}
}
});
// Confirm that table was created successfully.
Console.WriteLine(TableExist(bigtableTableAdminClient)
? $"Table {tableId} created successfully\n"
: $"There was a problem creating a table {tableId}");
}
else
{
Console.WriteLine($"Table: {tableId} already exists");
}
将行写入表
使用包含三条简单问候语的字符串数组 s_greetings[]
作为要写入表中的数据源。首先,使用 MutateRow()
向该表中写入一行。然后循环遍历该数组的其余部分,以构建一个 MutateRowsRequest
对象(其中,每条问候语都有一个对应条目)。使用 MutateRows()
发出一次性写入所有条目的请求。然后,循环遍历返回的响应,以检查每个条目的状态代码,确保其已成功写入。
// Initialize Google.Cloud.Bigtable.V2.TableName object.
Google.Cloud.Bigtable.Common.V2.TableName tableName = new Google.Cloud.Bigtable.Common.V2.TableName(projectId, instanceId, tableId);
// Write some rows
/* 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 */
Console.WriteLine($"Write some greetings to the table {tableId}");
// Insert 1 row using MutateRow()
s_greetingIndex = 0;
try
{
bigtableClient.MutateRow(tableName, rowKeyPrefix + s_greetingIndex, MutationBuilder());
Console.WriteLine($"\tGreeting: -- {s_greetings[s_greetingIndex],-18}-- written successfully");
}
catch (Exception ex)
{
Console.WriteLine($"\tFailed to write greeting: --{s_greetings[s_greetingIndex]}");
Console.WriteLine(ex.Message);
throw;
}
// Insert multiple rows using MutateRows()
// Build a MutateRowsRequest (contains table name and a collection of entries).
MutateRowsRequest request = new MutateRowsRequest
{
TableNameAsTableName = tableName
};
s_mapToOriginalGreetingIndex = new List<int>();
while (++s_greetingIndex < s_greetings.Length)
{
s_mapToOriginalGreetingIndex.Add(s_greetingIndex);
// Build an entry for every greeting (consists of rowkey and a collection of mutations).
string rowKey = rowKeyPrefix + s_greetingIndex;
request.Entries.Add(Mutations.CreateEntry(rowKey, MutationBuilder()));
}
// Make the request to write multiple rows.
MutateRowsResponse response = bigtableClient.MutateRows(request);
// Check the status code of each entry to ensure that it was written successfully.
foreach (MutateRowsResponse.Types.Entry entry in response.Entries)
{
s_greetingIndex = s_mapToOriginalGreetingIndex[(int)entry.Index];
if (entry.Status.Code == 0)
{
Console.WriteLine($"\tGreeting: -- {s_greetings[s_greetingIndex],-18}-- written successfully");
}
else
{
Console.WriteLine($"\tFailed to write greeting: --{s_greetings[s_greetingIndex]}");
Console.WriteLine(entry.Status.Message);
}
}
Mutation MutationBuilder() =>
Mutations.SetCell(columnFamily, columnName, s_greetings[s_greetingIndex], new BigtableVersion(DateTime.UtcNow));
创建过滤条件
在读取您写入的数据之前,请创建过滤条件,以限制 Bigtable 返回的数据。此过滤条件指示 Bigtable 仅返回每个值的最新版本,即使该表包含符合垃圾回收条件但尚未删除的旧单元也是如此。
RowFilter filter = RowFilters.CellsPerRowLimit(1);
按行键读取行
使用 ReadRow()
方法,并传入您刚刚创建的过滤条件,以获取该行中每个值的一个版本。
// Read from the table.
Console.WriteLine("Read the first row");
int rowIndex = 0;
// Read a specific row. Apply a filter to return latest only cell value accross entire row.
Row rowRead = bigtableClient.ReadRow(
tableName, rowKey: rowKeyPrefix + rowIndex, filter: filter);
Console.WriteLine(
$"\tRow key: {rowRead.Key.ToStringUtf8()} " +
$" -- Value: {rowRead.Families[0].Columns[0].Cells[0].Value.ToStringUtf8(),-16} " +
$" -- Time Stamp: {rowRead.Families[0].Columns[0].Cells[0].TimestampMicros}");
扫描所有表行
调用 ReadRows()
方法并传入过滤条件,以获取表中的所有行。由于您传入了过滤条件,因此 Bigtable 仅会返回每个值的一个版本。
Console.WriteLine("Read all rows using streaming");
// stream the content of the whole table. Apply a filter to return latest only cell values accross all rows.
ReadRowsStream responseRead = bigtableClient.ReadRows(tableName, filter: filter);
Task printRead = PrintReadRowsAsync();
printRead.Wait();
async Task PrintReadRowsAsync()
{
var responseEnumerator = responseRead.GetAsyncEnumerator(default);
while (await responseEnumerator.MoveNextAsync())
{
Row row = responseEnumerator.Current;
Console.WriteLine(
$"\tRow key: {row.Key.ToStringUtf8()} " +
$" -- Value: {row.Families[0].Columns[0].Cells[0].Value.ToStringUtf8(),-16} " +
$" -- Time Stamp: {row.Families[0].Columns[0].Cells[0].TimestampMicros}");
}
}
删除表
使用 DeleteTable()
方法删除表。
// Clean up. Delete the table.
Console.WriteLine($"Delete table: {tableId}");
bigtableTableAdminClient.DeleteTable(name: tableName);
if (!TableExist(bigtableTableAdminClient))
{
Console.WriteLine($"Table: {tableId} deleted successfully");
}
综合应用
以下为不包含注释的完整代码示例。
// Copyright 2018 Google Inc.
using Google.Cloud.Bigtable.Admin.V2;
using Google.Cloud.Bigtable.V2;
using Grpc.Core;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
namespace GoogleCloudSamples.Bigtable
{
public class HelloWorld
{
private const string projectId = "YOUR-PROJECT-ID";
private const string instanceId = "YOUR-INSTANCE-ID";
private const string tableId = "Hello-Bigtable";
private const string columnFamily = "cf";
private const string columnName = "greeting";
private static readonly string[] s_greetings = { "Hello World!", "Hello Bigtable!", "Hello C#!" };
private static List<int> s_mapToOriginalGreetingIndex;
private const string rowKeyPrefix = "greeting";
private static int s_greetingIndex;
private static void DoHelloWorld()
{
try
{
BigtableTableAdminClient bigtableTableAdminClient = BigtableTableAdminClient.Create();
BigtableClient bigtableClient = BigtableClient.Create();
Console.WriteLine($"Create new table: {tableId} with column family: {columnFamily}, instance: {instanceId}");
if (!TableExist(bigtableTableAdminClient))
{
bigtableTableAdminClient.CreateTable(
new InstanceName(projectId, instanceId),
tableId,
new Table
{
Granularity = Table.Types.TimestampGranularity.Millis,
ColumnFamilies =
{
{
columnFamily, new ColumnFamily
{
GcRule = new GcRule
{
MaxNumVersions = 1
}
}
}
}
});
Console.WriteLine(TableExist(bigtableTableAdminClient)
? $"Table {tableId} created successfully\n"
: $"There was a problem creating a table {tableId}");
}
else
{
Console.WriteLine($"Table: {tableId} already exists");
}
Google.Cloud.Bigtable.Common.V2.TableName tableName = new Google.Cloud.Bigtable.Common.V2.TableName(projectId, instanceId, tableId);
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 */
Console.WriteLine($"Write some greetings to the table {tableId}");
s_greetingIndex = 0;
try
{
bigtableClient.MutateRow(tableName, rowKeyPrefix + s_greetingIndex, MutationBuilder());
Console.WriteLine($"\tGreeting: -- {s_greetings[s_greetingIndex],-18}-- written successfully");
}
catch (Exception ex)
{
Console.WriteLine($"\tFailed to write greeting: --{s_greetings[s_greetingIndex]}");
Console.WriteLine(ex.Message);
throw;
}
MutateRowsRequest request = new MutateRowsRequest
{
TableNameAsTableName = tableName
};
s_mapToOriginalGreetingIndex = new List<int>();
while (++s_greetingIndex < s_greetings.Length)
{
s_mapToOriginalGreetingIndex.Add(s_greetingIndex);
string rowKey = rowKeyPrefix + s_greetingIndex;
request.Entries.Add(Mutations.CreateEntry(rowKey, MutationBuilder()));
}
MutateRowsResponse response = bigtableClient.MutateRows(request);
foreach (MutateRowsResponse.Types.Entry entry in response.Entries)
{
s_greetingIndex = s_mapToOriginalGreetingIndex[(int)entry.Index];
if (entry.Status.Code == 0)
{
Console.WriteLine($"\tGreeting: -- {s_greetings[s_greetingIndex],-18}-- written successfully");
}
else
{
Console.WriteLine($"\tFailed to write greeting: --{s_greetings[s_greetingIndex]}");
Console.WriteLine(entry.Status.Message);
}
}
Mutation MutationBuilder() =>
Mutations.SetCell(columnFamily, columnName, s_greetings[s_greetingIndex], new BigtableVersion(DateTime.UtcNow));
RowFilter filter = RowFilters.CellsPerRowLimit(1);
Console.WriteLine("Read the first row");
int rowIndex = 0;
Row rowRead = bigtableClient.ReadRow(
tableName, rowKey: rowKeyPrefix + rowIndex, filter: filter);
Console.WriteLine(
$"\tRow key: {rowRead.Key.ToStringUtf8()} " +
$" -- Value: {rowRead.Families[0].Columns[0].Cells[0].Value.ToStringUtf8(),-16} " +
$" -- Time Stamp: {rowRead.Families[0].Columns[0].Cells[0].TimestampMicros}");
Console.WriteLine("Read all rows using streaming");
ReadRowsStream responseRead = bigtableClient.ReadRows(tableName, filter: filter);
Task printRead = PrintReadRowsAsync();
printRead.Wait();
async Task PrintReadRowsAsync()
{
var responseEnumerator = responseRead.GetAsyncEnumerator(default);
while (await responseEnumerator.MoveNextAsync())
{
Row row = responseEnumerator.Current;
Console.WriteLine(
$"\tRow key: {row.Key.ToStringUtf8()} " +
$" -- Value: {row.Families[0].Columns[0].Cells[0].Value.ToStringUtf8(),-16} " +
$" -- Time Stamp: {row.Families[0].Columns[0].Cells[0].TimestampMicros}");
}
}
Console.WriteLine($"Delete table: {tableId}");
bigtableTableAdminClient.DeleteTable(name: tableName);
if (!TableExist(bigtableTableAdminClient))
{
Console.WriteLine($"Table: {tableId} deleted successfully");
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception while running HelloWorld: {ex.Message}");
}
}
private static bool TableExist(BigtableTableAdminClient bigtableTableAdminClient)
{
GetTableRequest request = new GetTableRequest
{
TableName = new Google.Cloud.Bigtable.Common.V2.TableName(projectId, instanceId, tableId),
View = Table.Types.View.NameOnly
};
try
{
var tables = bigtableTableAdminClient.GetTable(request);
return true;
}
catch (RpcException ex)
{
if (ex.StatusCode == StatusCode.NotFound)
{
return false;
}
throw;
}
}
public static int Main(string[] args)
{
if (projectId == "YOUR-PROJECT" + "-ID")
{
Console.WriteLine("Edit HelloWorld.cs and replace YOUR-PROJECT-ID with your project ID.");
return -1;
}
if (instanceId == "YOUR-INSTANCE" + "-ID")
{
Console.WriteLine("Edit HelloWorld.cs and replace YOUR-INSTANCE-ID with your instance ID.");
return -1;
}
DoHelloWorld();
return 0;
}
}
}