C# Hello World

이 코드 샘플은 C#으로 작성된 'hello world' 애플리케이션입니다. 이 샘플은 다음 작업을 완료하는 방법을 보여줍니다.

  • 인증 설정
  • Bigtable 인스턴스에 연결
  • 새 테이블 만들기
  • 테이블에 데이터 쓰기
  • 데이터 다시 읽기
  • 테이블 삭제

인증 설정

이 페이지의 .NET 샘플을 로컬 개발 환경에서 사용하려면 gcloud CLI를 설치 및 초기화한 다음 사용자 인증 정보로 애플리케이션 기본 사용자 인증 정보를 설정하세요.

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

    gcloud init
  3. Create local authentication credentials for your user account:

    gcloud auth application-default login

자세한 내용은 다음을 참조하세요: Set up authentication for a local development environment.

샘플 실행

이 코드는 .NET용 Google Cloud 클라이언트 라이브러리에서 C# Admin APIC# Data API 라이브러리를 사용하여 Bigtable과 통신합니다.

이 샘플 프로그램을 실행하려면 GitHub의 .NET Bigtable 샘플 안내를 따르세요. 빌드 및 실행빠른 시작 단계를 완료하면 Hello World 애플리케이션에서 사용할 리소스를 만들 수 있습니다. HelloWorld.cs 파일을 수정하여 만든 리소스의 이름을 추가해야 합니다.

Cloud 클라이언트 라이브러리를 Bigtable과 함께 사용

샘플 애플리케이션을 Bigtable에 연결하여 몇 가지 간단한 작업을 보여줍니다.

Bigtable에 연결

시작하려면 Bigtable 연결에 사용할 2개의 클라이언트 객체를 만듭니다. 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 객체를 생성합니다. 테이블에는 각 값별로 한 버전만 보관하는 column family가 한 개 있습니다.

// 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);

row key를 통해 행 읽기

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은 각 값별로 버전 1개만 반환합니다.

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

요약 정리

다음은 주석이 없는 전체 코드 샘플입니다.



using Google.Cloud.Bigtable.Admin.V2;
using Google.Cloud.Bigtable.Common.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;
        }
    }
}