1. Visão geral
O Spanner é um serviço de banco de dados totalmente gerenciado, escalonável horizontalmente e distribuído globalmente, ótimo para cargas de trabalho operacionais relacionais e não relacionais. Além dos recursos principais, o Spanner oferece recursos avançados poderosos que permitem criar aplicativos inteligentes e orientados a dados.
Este codelab se baseia no entendimento básico do Spanner e explora o uso de integrações avançadas para melhorar os recursos de processamento e análise de dados, usando um aplicativo bancário on-line como base.
Vamos nos concentrar em três recursos avançados principais:
- Integração com a Vertex AI:saiba como integrar o Spanner à plataforma de IA do Google Cloud, a Vertex AI. Você vai aprender a invocar modelos da Vertex AI diretamente nas consultas SQL do Spanner, ativando transformações e previsões poderosas no banco de dados, permitindo que nosso aplicativo bancário categorize transações automaticamente para casos de uso como acompanhamento de orçamento e detecção de anomalias.
- Pesquisa de texto completo:saiba como implementar a funcionalidade de pesquisa de texto completo no Spanner. Você vai aprender a indexar dados de texto e escrever consultas eficientes para realizar pesquisas baseadas em palavras-chave nos seus dados operacionais, permitindo a descoberta de dados eficaz, como encontrar clientes por endereço de e-mail no sistema bancário.
- Consultas federadas do BigQuery:saiba como aproveitar os recursos de consulta federada do Spanner para consultar diretamente dados que residem no BigQuery. Isso permite combinar os dados operacionais em tempo real do Spanner com os conjuntos de dados analíticos do BigQuery para insights e relatórios abrangentes sem duplicação de dados ou processos ETL complexos, impulsionando vários casos de uso no nosso aplicativo bancário, como campanhas de marketing segmentadas, combinando dados de clientes em tempo real com tendências históricas mais amplas do BigQuery.
O que você vai aprender
- Como configurar uma instância do Spanner.
- Como criar um banco de dados e tabelas.
- Como carregar dados nas tabelas do banco de dados do Spanner.
- Como chamar modelos da Vertex AI usando o Spanner.
- Como consultar o banco de dados do Spanner usando pesquisa aproximada e de texto completo.
- Como executar consultas federadas no Spanner do BigQuery.
- Como excluir sua instância do Spanner.
O que é necessário
2. Configuração e requisitos
Criar um projeto
Se você já tiver um projeto do Google Cloud com o faturamento ativado, clique no menu suspenso de seleção no canto superior esquerdo do console:
Com um projeto selecionado, pule para Ativar as APIs necessárias.
Se você ainda não tem uma Conta do Google (Gmail ou Google Apps), crie uma. Faça login no console do Google Cloud Platform (console.cloud.google.com) e crie um novo projeto.
Clique no botão "NEW PROJECT" na caixa de diálogo resultante para criar um novo projeto:
Se você ainda não tiver um projeto, uma caixa de diálogo como esta será exibida para criar seu primeiro:
A caixa de diálogo de criação de projeto subsequente permite que você insira os detalhes do novo projeto.
Lembre-se do ID do projeto, um nome exclusivo em todos os projetos do Google Cloud. Faremos referência a ele mais adiante neste codelab como PROJECT_ID
.
Em seguida, se ainda não tiver feito isso, ative o faturamento no console do desenvolvedor para usar os recursos do Google Cloud e ativar a API Spanner, a API Vertex AI, a API BigQuery e a API BigQuery Connection.
Os preços do Spanner estão documentados aqui. Outros custos associados a outros recursos serão documentados nas páginas de preços específicas.
Novos usuários do Google Cloud Platform estão qualificados para um teste sem custo financeiro de US$300.
Configuração do Google Cloud Shell
Neste codelab, vamos usar o Google Cloud Shell, um ambiente de linha de comando executado no Cloud.
O Cloud Shell é uma máquina virtual com base em Debian que contém todas as ferramentas de desenvolvimento necessárias. Ela oferece um diretório principal persistente de 5 GB e é executada no Google Cloud. Isso aprimora o desempenho e a autenticação da rede. Isso significa que tudo que você precisa para este codelab é um navegador.
Para ativar o Cloud Shell no Console do Cloud, basta clicar em Ativar o Cloud Shell . O provisionamento e a conexão ao ambiente levam apenas alguns instantes.
Depois de se conectar ao Cloud Shell, você já estará autenticado e o projeto estará configurado com seu PROJECT_ID
.
gcloud auth list
Saída esperada:
Credentialed Accounts ACTIVE: * ACCOUNT: <myaccount>@<mydomain>.com
gcloud config list project
Saída esperada:
[core] project = <PROJECT_ID>
Se, por algum motivo, o projeto não estiver definido, emita o seguinte comando:
gcloud config set project <PROJECT_ID>
Quer encontrar seu PROJECT_ID
? Confira qual ID você usou nas etapas de configuração ou procure-o no painel do Console do Cloud:
O Cloud Shell também define algumas variáveis de ambiente por padrão, o que pode ser útil ao executar comandos futuros.
echo $GOOGLE_CLOUD_PROJECT
Saída esperada:
<PROJECT_ID>
Ative as APIs necessárias
Ative as APIs Spanner, Vertex AI e BigQuery no projeto:
gcloud services enable spanner.googleapis.com
gcloud services enable aiplatform.googleapis.com
gcloud services enable bigquery.googleapis.com
gcloud services enable bigqueryconnection.googleapis.com
Resumo
Nesta etapa, você configurou seu projeto, caso ainda não tivesse um, ativou o Cloud Shell e as APIs necessárias.
A seguir
Em seguida, você vai configurar a instância do Spanner.
3. Configurar uma instância do Spanner
Criar a instância do Spanner
Nesta etapa, você vai configurar uma instância do Spanner para o codelab. Para fazer isso, abra o Cloud Shell e execute este comando:
export SPANNER_INSTANCE=cloudspanner-onlinebanking
gcloud spanner instances create $SPANNER_INSTANCE \
--config=regional-us-central1 \
--description="Spanner Online Banking" \
--nodes=1 \
--edition=ENTERPRISE \
--default-backup-schedule-type=NONE
Saída esperada:
Creating instance...done.
Resumo
Nesta etapa, você criou a instância do Spanner.
A seguir
Em seguida, você vai preparar o aplicativo inicial e criar o banco de dados e o esquema.
4. Criar um banco de dados e um esquema
Preparar a inscrição inicial
Nesta etapa, você vai criar o banco de dados e o esquema usando o código.
Primeiro, crie um aplicativo Java chamado onlinebanking
usando o Maven:
mvn -B archetype:generate \
-DarchetypeGroupId=org.apache.maven.archetypes \
-DgroupId=com.google.codelabs \
-DartifactId=onlinebanking \
-DjavaCompilerVersion=1.8 \
-DjunitVersion=4.13.2 \
-DarchetypeVersion=1.5
Confira e copie os arquivos de dados que vamos adicionar ao banco de dados (confira o repositório de código aqui):
git clone https://github.com/GoogleCloudPlatform/cloud-spanner-samples.git
cp -r ./cloud-spanner-samples/banking/data ./onlinebanking
Navegue até a pasta do aplicativo:
cd onlinebanking
Abra o arquivo pom.xml
do Maven. Adicione a seção de gerenciamento de dependências para usar a BOM do Maven e gerenciar a versão das bibliotecas do Google Cloud:
<dependencyManagement>
<dependencies>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>libraries-bom</artifactId>
<version>26.56.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
O editor e o arquivo vão ficar assim:
Verifique se a seção dependencies
inclui as bibliotecas que o aplicativo vai usar:
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-nop</artifactId>
<version>2.0.9</version>
</dependency>
<dependency>
<groupId>com.opencsv</groupId>
<artifactId>opencsv</artifactId>
<version>5.10</version>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-spanner</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-bigquery</artifactId>
</dependency>
<dependency>
<groupId>com.google.cloud</groupId>
<artifactId>google-cloud-bigqueryconnection</artifactId>
</dependency>
</dependencies>
Por fim, substitua os plug-ins de build para que o aplicativo seja empacotado em um JAR executável:
<build>
<plugins>
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>3.3.1</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/${project.artifactId}-resources</outputDirectory>
<resources>
<resource>
<directory>resources</directory>
<filtering>true</filtering>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.8.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/${project.artifactId}-resources/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>3.4.2</version>
<configuration>
<finalName>${project.artifactId}</finalName>
<outputDirectory>${project.build.directory}</outputDirectory>
<archive>
<index>false</index>
<manifest>
<mainClass>com.google.codelabs.App</mainClass>
<addClasspath>true</addClasspath>
<classpathPrefix>${project.artifactId}-resources/lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>3.2.5</version>
<executions>
<execution>
<goals>
<goal>integration-test</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.2.5</version>
<configuration>
<useSystemClassLoader>false</useSystemClassLoader>
</configuration>
</plugin>
</plugins>
</build>
Salve as alterações feitas no arquivo pom.xml
selecionando "Salvar" no menu "Arquivo" do editor do Cloud Shell ou pressionando Ctrl+S
.
Agora que as dependências estão prontas, você vai adicionar código ao app para criar um esquema, alguns índices (incluindo a pesquisa) e um modelo de IA conectado a um endpoint remoto. Você vai criar esses artefatos e adicionar mais métodos a essa classe ao longo deste codelab.
Abra App.java
em onlinebanking/src/main/java/com/google/codelabs
e substitua o conteúdo pelo seguinte código:
package com.google.codelabs;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.ExecutionException;
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
public class App {
// Create the Spanner database and schema
public static void create(DatabaseAdminClient dbAdminClient, DatabaseId db,
String location, String model) {
System.out.println("Creating Spanner database...");
List<String> statements = Arrays.asList(
"CREATE TABLE Customers (\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " FirstName STRING(256) NOT NULL,\n"
+ " LastName STRING(256) NOT NULL,\n"
+ " FullName STRING(512) AS (FirstName || ' ' || LastName) STORED,\n"
+ " Email STRING(512) NOT NULL,\n"
+ " EmailTokens TOKENLIST AS\n"
+ " (TOKENIZE_SUBSTRING(Email, ngram_size_min=>2, ngram_size_max=>3,\n"
+ " relative_search_types=>[\"all\"])) HIDDEN,\n"
+ " Address STRING(MAX)\n"
+ ") PRIMARY KEY (CustomerId)",
"CREATE INDEX CustomersByEmail\n"
+ "ON Customers(Email)",
"CREATE SEARCH INDEX CustomersFuzzyEmail\n"
+ "ON Customers(EmailTokens)",
"CREATE TABLE Accounts (\n"
+ " AccountId INT64 NOT NULL,\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " AccountType STRING(256) NOT NULL,\n"
+ " Balance NUMERIC NOT NULL,\n"
+ " OpenDate TIMESTAMP NOT NULL\n"
+ ") PRIMARY KEY (AccountId)",
"CREATE INDEX AccountsByCustomer\n"
+ "ON Accounts (CustomerId)",
"CREATE TABLE TransactionLedger (\n"
+ " TransactionId INT64 NOT NULL,\n"
+ " AccountId INT64 NOT NULL,\n"
+ " TransactionType STRING(256) NOT NULL,\n"
+ " Amount NUMERIC NOT NULL,\n"
+ " Timestamp TIMESTAMP NOT NULL"
+ " OPTIONS(allow_commit_timestamp=true),\n"
+ " Category STRING(256),\n"
+ " Description STRING(MAX),\n"
+ " CategoryTokens TOKENLIST AS (TOKENIZE_FULLTEXT(Category)) HIDDEN,\n"
+ " DescriptionTokens TOKENLIST AS (TOKENIZE_FULLTEXT(Description)) HIDDEN\n"
+ ") PRIMARY KEY (AccountId, TransactionId),\n"
+ "INTERLEAVE IN PARENT Accounts ON DELETE CASCADE",
"CREATE INDEX TransactionLedgerByAccountType\n"
+ "ON TransactionLedger(AccountId, TransactionType)",
"CREATE INDEX TransactionLedgerByCategory\n"
+ "ON TransactionLedger(AccountId, Category)",
"CREATE SEARCH INDEX TransactionLedgerTextSearch\n"
+ "ON TransactionLedger(CategoryTokens, DescriptionTokens)",
"CREATE MODEL TransactionCategoryModel\n"
+ "INPUT (prompt STRING(MAX))\n"
+ "OUTPUT (content STRING(MAX))\n"
+ "REMOTE OPTIONS (\n"
+ " endpoint = '//aiplatform.googleapis.com/projects/" + db.getInstanceId().getProject()
+ "/locations/" + location + "/publishers/google/models/" + model + "',\n"
+ " default_batch_size = 1\n"
+ ")");
OperationFuture<Database, CreateDatabaseMetadata> op = dbAdminClient.createDatabase(
db.getInstanceId().getInstance(),
db.getDatabase(),
statements);
try {
Database dbOperation = op.get();
System.out.println("Created Spanner database [" + dbOperation.getId() + "]");
} catch (ExecutionException e) {
throw (SpannerException) e.getCause();
} catch (InterruptedException e) {
throw SpannerExceptionFactory.propagateInterrupt(e);
}
}
static void printUsageAndExit() {
System.out.println("Online Online Banking Application 1.0.0");
System.out.println("Usage:");
System.out.println(" java -jar target/onlinebanking.jar <command> [command_option(s)]");
System.out.println("");
System.out.println("Examples:");
System.out.println(" java -jar target/onlinebanking.jar create");
System.out.println(" - Create a sample Spanner database and schema in your "
+ "project.\n");
System.exit(1);
}
public static void main(String[] args) {
if (args.length < 1) {
printUsageAndExit();
}
String instanceId = System.getProperty("SPANNER_INSTANCE", System.getenv("SPANNER_INSTANCE"));
String databaseId = System.getProperty("SPANNER_DATABASE", System.getenv("SPANNER_DATABASE"));
String location = System.getenv().getOrDefault("SPANNER_LOCATION", "us-central1");
String model = System.getenv().getOrDefault("SPANNER_MODEL", "gemini-2.0-flash-lite");
if (instanceId == null || databaseId == null) {
System.err.println("Missing one or more required environment variables: SPANNER_INSTANCE or "
+ "SPANNER_DATABASE");
System.exit(1);
}
BigQueryOptions bigqueryOptions = BigQueryOptions.newBuilder().build();
BigQuery bigquery = bigqueryOptions.getService();
SpannerOptions spannerOptions = SpannerOptions.newBuilder().build();
try (Spanner spanner = spannerOptions.getService()) {
String command = args[0];
DatabaseId db = DatabaseId.of(spannerOptions.getProjectId(), instanceId, databaseId);
DatabaseClient dbClient = spanner.getDatabaseClient(db);
DatabaseAdminClient dbAdminClient = spanner.getDatabaseAdminClient();
switch (command) {
case "create":
create(dbAdminClient, db, location, model);
break;
default:
printUsageAndExit();
}
}
}
}
Salve as alterações em App.java
.
Confira as diferentes entidades que o código está criando e crie o JAR do aplicativo:
mvn package
Saída esperada:
[INFO] Building jar: /home/your_user/onlinebanking/target/onlinebanking.jar [INFO] ------------------------------------------------------------------------ [INFO] BUILD SUCCESS
Execute o aplicativo para conferir as informações de uso:
java -jar target/onlinebanking.jar
Saída esperada:
Online Banking Application 1.0.0 Usage: java -jar target/onlinebanking.jar <command> [command_option(s)] Examples: java -jar target/onlinebanking.jar create - Create a sample Spanner database and schema in your project.
Criar o banco de dados e o esquema
Defina as variáveis de ambiente do aplicativo necessárias:
export SPANNER_INSTANCE=cloudspanner-onlinebanking
export SPANNER_DATABASE=onlinebanking
Crie o banco de dados e o esquema executando o comando create
:
java -jar target/onlinebanking.jar create
Saída esperada:
Creating Spanner database... Created Spanner database [<DATABASE_RESOURCE_NAME>]
Verificar o esquema no Spanner
No console do Spanner, navegue até a instância e o banco de dados que acabou de ser criado.
Você vai encontrar as três tabelas: Accounts
, Customers
e TransactionLedger
.
Essa ação cria o esquema do banco de dados, incluindo as tabelas Accounts
, Customers
e TransactionLedger
, além de índices secundários para recuperação de dados otimizada e uma referência de modelo da Vertex AI.
A tabela TransactionLedger
é intercalada nas contas para melhorar o desempenho da consulta de transações específicas da conta com uma melhor localidade de dados.
Os índices secundários (CustomersByEmail
, CustomersFuzzyEmail
, AccountsByCustomer
, TransactionLedgerByAccountType
, TransactionLedgerByCategory
, TransactionLedgerTextSearch
) foram implementados para otimizar padrões comuns de acesso a dados usados neste codelab, como a pesquisa de clientes por e-mail exato e aproximado, a recuperação de contas por cliente e a consulta e pesquisa eficientes de dados de transações.
O TransactionCategoryModel
usa a Vertex AI para permitir chamadas SQL diretas para um LLM, que é usado para categorização dinâmica de transações neste codelab.
Resumo
Nesta etapa, você criou o banco de dados e o esquema do Spanner.
A seguir
Em seguida, você vai carregar os dados de amostra do aplicativo.
5. Carregar dados
Agora, você vai adicionar a funcionalidade para carregar dados de exemplo de arquivos CSV no banco de dados.
Abra App.java
e comece substituindo as importações:
package com.google.codelabs;
import java.io.FileReader;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.Timestamp;
import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Key;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
import com.google.cloud.spanner.Struct;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
import com.opencsv.CSVReader;
Em seguida, adicione os métodos de inserção à classe App
:
// Insert customers from CSV
public static void insertCustomers(DatabaseClient dbClient) {
System.out.println("Inserting customers...");
dbClient
.readWriteTransaction()
.run(transaction -> {
int count = 0;
List<Statement> statements = new ArrayList<>();
try (CSVReader reader = new CSVReader(new FileReader("data/customers.csv"))) {
reader.skip(1);
String[] line;
while ((line = reader.readNext()) != null) {
Statement statement = Statement.newBuilder(
"INSERT INTO Customers (CustomerId, FirstName, LastName, Email, Address) "
+ "VALUES (@customerId, @firstName, @lastName, @email, @address)")
.bind("customerId").to(Long.parseLong(line[0]))
.bind("firstName").to(line[1])
.bind("lastName").to(line[2])
.bind("email").to(line[3])
.bind("address").to(line[4])
.build();
statements.add(statement);
count++;
}
transaction.batchUpdate(statements);
System.out.println("Inserted " + count + " customers");
return null;
}
});
}
// Insert accounts from CSV
public static void insertAccounts(DatabaseClient dbClient) {
System.out.println("Inserting accounts...");
dbClient
.readWriteTransaction()
.run(transaction -> {
int count = 0;
List<Statement> statements = new ArrayList<>();
try (CSVReader reader = new CSVReader(new FileReader("data/accounts.csv"))) {
reader.skip(1);
String[] line;
while ((line = reader.readNext()) != null) {
Statement statement = Statement.newBuilder(
"INSERT INTO Accounts (AccountId, CustomerId, AccountType, Balance, OpenDate) "
+ "VALUES (@accountId, @customerId, @accountType, @balance, @openDate)")
.bind("accountId").to(Long.parseLong(line[0]))
.bind("customerId").to(Long.parseLong(line[1]))
.bind("accountType").to(line[2])
.bind("balance").to(new BigDecimal(line[3]))
.bind("openDate").to(line[4])
.build();
statements.add(statement);
count++;
}
transaction.batchUpdate(statements);
System.out.println("Inserted " + count + " accounts");
return null;
}
});
}
// Insert transactions from CSV
public static void insertTransactions(DatabaseClient dbClient) {
System.out.println("Inserting transactions...");
dbClient
.readWriteTransaction()
.run(transaction -> {
int count = 0;
List<Statement> statements = new ArrayList<>();
try (CSVReader reader = new CSVReader(new FileReader("data/transactions.csv"))) {
reader.skip(1);
String[] line;
// Specify timestamps that are within last 30 days
Random random = new Random();
Instant startTime = Instant.now().minus(15, ChronoUnit.DAYS);
Instant currentTimestamp = startTime;
Map<Long, BigDecimal> balanceChanges = new HashMap<>();
while ((line = reader.readNext()) != null) {
long accountId = Long.parseLong(line[1]);
String transactionType = line[2];
BigDecimal amount = new BigDecimal(line[3]);
int randomMinutes = random.nextInt(60) + 1;
currentTimestamp = currentTimestamp.plus(Duration.ofMinutes(randomMinutes));
Timestamp timestamp = Timestamp.ofTimeSecondsAndNanos(
currentTimestamp.getEpochSecond(), currentTimestamp.getNano());
Statement statement = Statement.newBuilder(
"INSERT INTO TransactionLedger (TransactionId, AccountId, TransactionType, Amount,"
+ "Timestamp, Category, Description) "
+ "VALUES (@transactionId, @accountId, @transactionType, @amount, @timestamp,"
+ "@category, @description)")
.bind("transactionId").to(Long.parseLong(line[0]))
.bind("accountId").to(accountId)
.bind("transactionType").to(transactionType)
.bind("amount").to(amount)
.bind("timestamp").to(timestamp)
.bind("category").to(line[5])
.bind("description").to(line[6])
.build();
statements.add(statement);
// Track balance changes per account
BigDecimal balanceChange = balanceChanges.getOrDefault(accountId,
BigDecimal.ZERO);
if ("Credit".equalsIgnoreCase(transactionType)) {
balanceChanges.put(accountId, balanceChange.add(amount));
} else if ("Debit".equalsIgnoreCase(transactionType)) {
balanceChanges.put(accountId, balanceChange.subtract(amount));
} else {
System.err.println("Unsupported transaction type: " + transactionType);
continue;
}
count++;
}
// Apply final balance updates
for (Map.Entry<Long, BigDecimal> entry : balanceChanges.entrySet()) {
long accountId = entry.getKey();
BigDecimal balanceChange = entry.getValue();
Struct row = transaction.readRow(
"Accounts",
Key.of(accountId),
List.of("Balance"));
if (row != null) {
BigDecimal currentBalance = row.getBigDecimal("Balance");
BigDecimal updatedBalance = currentBalance.add(balanceChange);
Statement statement = Statement.newBuilder(
"UPDATE Accounts SET Balance = @balance WHERE AccountId = @accountId")
.bind("accountId").to(accountId)
.bind("balance").to(updatedBalance)
.build();
statements.add(statement);
}
}
transaction.batchUpdate(statements);
System.out.println("Inserted " + count + " transactions");
}
return null;
});
}
Adicione outra instrução de caso no método main
para inserção no switch (command)
:
case "insert":
String insertType = (args.length >= 2) ? args[1] : "";
if (insertType.equals("customers")) {
insertCustomers(dbClient);
} else if (insertType.equals("accounts")) {
insertAccounts(dbClient);
} else if (insertType.equals("transactions")) {
insertTransactions(dbClient);
} else {
insertCustomers(dbClient);
insertAccounts(dbClient);
insertTransactions(dbClient);
}
break;
Por fim, adicione como usar a inserção ao método printUsageAndExit
:
System.out.println(" java -jar target/onlinebanking.jar insert");
System.out.println(" - Insert sample Customers, Accounts, and Transactions into the "
+ "database.\n");
Salve as alterações que você fez em App.java
.
Recrie o aplicativo:
mvn package
Insira os dados de amostra executando o comando insert
:
java -jar target/onlinebanking.jar insert
Saída esperada:
Inserting customers... Inserted 100 customers Inserting accounts... Inserted 125 accounts Inserting transactions... Inserted 200 transactions
No console do Spanner, volte ao Spanner Studio para sua instância e seu banco de dados. Em seguida, selecione a tabela TransactionLedger
e clique em "Dados" na barra lateral para verificar se os dados foram carregados. Deve haver 200 linhas na tabela.
Resumo
Nesta etapa, você inseriu os dados de amostra no banco de dados.
A seguir
Em seguida, você vai aproveitar a integração da Vertex AI para categorizar transações bancárias automaticamente no Spanner SQL.
6. Categorizar dados com a Vertex AI
Nesta etapa, você vai aproveitar o poder da Vertex AI para categorizar automaticamente suas transações financeiras diretamente no Spanner SQL. Com a Vertex AI, você pode escolher um modelo pré-treinado ou treinar e implantar o seu. Confira os modelos disponíveis no Model Garden da Vertex AI.
Neste codelab, vamos usar um dos modelos Gemini, Gemini Flash Lite
. Essa versão do Gemini é econômica e ainda pode processar a maioria das cargas de trabalho diárias.
No momento, temos várias transações financeiras que gostaríamos de categorizar (groceries
, transportation
etc.) dependendo da descrição. Para fazer isso, registre um modelo no Spanner e use ML.PREDICT
para chamar o modelo de IA.
No nosso aplicativo bancário, podemos querer categorizar transações para ter insights mais aprofundados sobre o comportamento do cliente, personalizar serviços, detectar anomalias com mais eficiência ou permitir que o cliente acompanhe o orçamento mensal.
A primeira etapa já foi realizada quando criamos o banco de dados e o esquema, que criaram um modelo assim:
Em seguida, vamos adicionar um método ao aplicativo para chamar ML.PREDICT
.
Abra App.java
e adicione o método categorize
:
// Use Vertex AI to set the category of transactions
public static void categorize(DatabaseClient dbClient) {
System.out.println("Categorizing transactions...");
try {
// Create a prompt to instruct the LLM how to categorize the transactions
String categories = String.join(", ", Arrays.asList("Entertainment", "Gifts", "Groceries",
"Investment", "Medical", "Movies", "Online Shopping", "Other", "Purchases", "Refund",
"Restaurants", "Salary", "Transfer", "Transportation", "Utilities"));
String prompt = "Categorize the following financial activity into one of these "
+ "categories: " + categories + ". Return Other if the description cannot be mapped to "
+ "one of these categories. Only return the exact category string, no other text or "
+ "punctuation or reasoning. Description: ";
String sql = "UPDATE TransactionLedger SET Category = (\n"
+ " SELECT content FROM ML.PREDICT(MODEL `TransactionCategoryModel`, (\n"
+ " SELECT CONCAT('" + prompt + "', CASE WHEN TRIM(Description) = ''\n"
+ " THEN 'Other' ELSE Description END) AS prompt\n"
+ " ))\n"
+ ") WHERE TRUE";
// Use partitioned update to batch update a large number of rows
dbClient.executePartitionedUpdate(Statement.of(sql));
System.out.println("Completed categorizing transactions");
} catch (SpannerException e) {
throw e;
}
}
Adicione outra instrução de caso no método main
para categorizar:
case "categorize":
categorize(dbClient);
break;
Por fim, adicione como usar a categorização ao método printUsageAndExit
:
System.out.println(" java -jar target/onlinebanking.jar categorize");
System.out.println(" - Use AI to categorize transactions in the database.\n");
Salve as alterações que você fez em App.java
.
Recrie o aplicativo:
mvn package
Categorize as transações no banco de dados executando o comando categorize
:
java -jar target/onlinebanking.jar categorize
Saída esperada:
Categorizing transactions... Completed categorizing transactions
No Spanner Studio, execute a instrução Preview Data para a tabela TransactionLedger
. A coluna Category
agora vai ser preenchida para todas as linhas.
Agora que categorizamos as transações, podemos usar essas informações para consultas internas ou voltadas ao cliente. Na próxima etapa, vamos descobrir quanto um determinado cliente gasta em uma categoria durante o mês.
Resumo
Nesta etapa, você usou um modelo pré-treinado para realizar a categorização dos seus dados com tecnologia de IA.
A seguir
Em seguida, você vai usar a tokenização para realizar pesquisas imprecisas e de texto completo.
7. Consultar usando a pesquisa de texto completo
Adicionar o código da consulta
O Spanner oferece muitas consultas de pesquisa de texto completo. Nesta etapa, você vai realizar uma pesquisa de correspondência exata, depois uma pesquisa aproximada e uma de texto completo.
Abra App.java
e comece substituindo as importações:
package com.google.codelabs;
import java.io.FileReader;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.Timestamp;
import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Key;
import com.google.cloud.spanner.ReadOnlyTransaction;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
import com.google.cloud.spanner.Struct;
import com.google.cloud.spanner.TimestampBound;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
import com.opencsv.CSVReader;
Em seguida, adicione os métodos de consulta:
// Get current account balance(s) by customer
public static void getBalance(DatabaseClient dbClient, long customerId) {
String query = "SELECT AccountId, Balance\n"
+ "FROM Accounts\n"
+ "WHERE CustomerId = @customerId";
Statement statement = Statement.newBuilder(query)
.bind("customerId").to(customerId)
.build();
// Ignore ongoing transactions, use stale reads as seconds-old data is sufficient
TimestampBound stalenessBound = TimestampBound.ofMaxStaleness(5, TimeUnit.SECONDS);
try (ReadOnlyTransaction transaction = dbClient.singleUseReadOnlyTransaction(stalenessBound);
ResultSet resultSet = transaction.executeQuery(statement);) {
System.out.println("Account balances for customer " + customerId + ":");
while (resultSet.next()) {
System.out.println(" Account " + resultSet.getLong("AccountId") + ": "
+ resultSet.getBigDecimal("Balance"));
}
}
}
// Find customers by email
public static void findCustomers(DatabaseClient dbClient, String email) {
// Query using fuzzy search (ngrams) to allow for spelling mistakes
String query = "SELECT CustomerId, Email\n"
+ "FROM Customers\n"
+ "WHERE SEARCH_NGRAMS(EmailTokens, @email)\n"
+ "ORDER BY SCORE_NGRAMS(EmailTokens, @email) DESC\n"
+ "LIMIT 10";
Statement statement = Statement.newBuilder(query)
.bind("email").to(email)
.build();
try (ReadOnlyTransaction transaction = dbClient.singleUseReadOnlyTransaction();
ResultSet resultSet = transaction.executeQuery(statement)) {
System.out.println("Customer emails matching " + email + " (top 10 matches):");
while (resultSet.next()) {
System.out.println(" Customer " + resultSet.getLong("CustomerId") + ": "
+ resultSet.getString("Email"));
}
}
}
// Get total monthly spending for a customer by category
public static void getSpending(DatabaseClient dbClient, long customerId, String category) {
// Query category using full-text search
String query = "SELECT SUM(Amount) as TotalSpending\n"
+ "FROM TransactionLedger t\n"
+ "JOIN Accounts a\n"
+ " ON t.AccountId = a.AccountId\n"
+ "WHERE t.TransactionType = 'Debit'\n"
+ " AND a.CustomerId = @customerId\n"
+ " AND t.Timestamp >= TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -30 DAY)\n"
+ " AND (SEARCH(t.CategoryTokens, @category) OR SEARCH(t.DescriptionTokens, @category))";
Statement statement = Statement.newBuilder(query)
.bind("customerId").to(customerId)
.bind("category").to(category)
.build();
try (ReadOnlyTransaction transaction = dbClient.singleUseReadOnlyTransaction();
ResultSet resultSet = transaction.executeQuery(statement);) {
System.out.println("Total spending for customer " + customerId + " under category "
+ category + ":");
while (resultSet.next()) {
BigDecimal totalSpending = BigDecimal.ZERO;
if (!resultSet.isNull("TotalSpending")) {
totalSpending = resultSet.getBigDecimal("TotalSpending");
}
System.out.println(" " + totalSpending);
}
}
}
Adicione outra instrução case
no método main
para a consulta:
case "query":
String queryType = (args.length >= 2) ? args[1] : "";
if (queryType.equals("balance")) {
long customerId = (args.length >= 3) ? Long.parseLong(args[2]) : 1L;
getBalance(dbClient, customerId);
} else if (queryType.equals("email")) {
String email = (args.length >= 3) ? args[2] : "";
findCustomers(dbClient, email);
} else if (queryType.equals("spending")) {
long customerId = (args.length >= 3) ? Long.parseLong(args[2]) : 1L;
String category = (args.length >= 4) ? args[3] : "";
getSpending(dbClient, customerId, category);
} else {
printUsageAndExit();
}
break;
Por fim, adicione como usar os comandos de consulta ao método printUsageAndExit
:
System.out.println(" java -jar target/onlinebanking.jar query balance 1");
System.out.println(" - Query customer account balance(s) by customer id.\n");
System.out.println(" java -jar target/onlinebanking.jar query email madi");
System.out.println(" - Find customers by email using fuzzy search.\n");
System.out.println(" java -jar target/onlinebanking.jar query spending 1 groceries");
System.out.println(" - Query customer spending by customer id and category using "
+ "full-text search.\n");
Salve as alterações que você fez em App.java
.
Recrie o aplicativo:
mvn package
Realizar uma pesquisa de correspondência exata para saldos de contas de clientes
Uma consulta de correspondência exata procura linhas correspondentes que correspondam exatamente a um termo.
Para melhorar o desempenho, um índice já foi adicionado quando você criou o banco de dados e o esquema:
"CREATE INDEX AccountsByCustomer\n" + "ON Accounts (CustomerId)",
O método getBalance
usa implicitamente esse índice para encontrar clientes que correspondem ao customerId fornecido e também faz junções em contas pertencentes a esse cliente.
Confira como a consulta fica quando é executada diretamente no Spanner Studio:
Para listar os saldos da conta do cliente 1
, execute o comando:
java -jar target/onlinebanking.jar query balance 1
Saída esperada:
Account balances for customer 1: Account 1: 9875.25 Account 7: 9900 Account 110: 38200
Há 100 clientes, então você também pode consultar qualquer um dos outros saldos de conta de cliente especificando um ID de cliente diferente:
java -jar target/onlinebanking.jar query balance 5
java -jar target/onlinebanking.jar query balance 10
java -jar target/onlinebanking.jar query balance 99
Realizar uma pesquisa aproximada nos e-mails dos clientes
As pesquisas aproximadas permitem encontrar correspondências aproximadas para termos de pesquisa, incluindo variações ortográficas e erros de digitação.
Um índice de n-gramas já foi adicionado quando você criou o banco de dados e o esquema:
CREATE TABLE Customers ( ... EmailTokens TOKENLIST AS (TOKENIZE_SUBSTRING(Email, ngram_size_min=>2, ngram_size_max=>3, relative_search_types=>["all"])) HIDDEN, ) PRIMARY KEY(CustomerId); CREATE SEARCH INDEX CustomersFuzzyEmail ON Customers(EmailTokens);
O método findCustomers
usa SEARCH_NGRAMS
e SCORE_NGRAMS
para consultar esse índice e encontrar clientes por e-mail. Como a coluna de e-mail foi tokenizada em n-gramas, essa consulta pode conter erros de ortografia e ainda retornar uma resposta correta. Os resultados são ordenados com base na melhor correspondência.
Encontre endereços de e-mail de clientes correspondentes que contêm madi
executando o comando:
java -jar target/onlinebanking.jar query email madi
Saída esperada:
Customer emails matching madi (top 10 matches): Customer 39: madison.perez@example.com Customer 64: mason.gray@example.com Customer 91: mabel.alexander@example.com
Essa resposta mostra as correspondências mais próximas que incluem madi
ou uma string semelhante, em ordem de classificação.
Confira como a consulta fica se for executada diretamente no Spanner Studio:
A pesquisa imprecisa também pode ajudar com erros de ortografia, como erros de emily
:
java -jar target/onlinebanking.jar query email emily
java -jar target/onlinebanking.jar query email emliy
java -jar target/onlinebanking.jar query email emilee
Saída esperada:
Customer emails matching emliy (top 10 matches): Customer 31: emily.lopez@example.com
Em cada caso, o e-mail do cliente esperado é retornado como a correspondência principal.
Pesquisar transações com pesquisa de texto completo
O recurso de pesquisa de texto completo do Spanner é usado para recuperar registros com base em palavras-chave ou frases. Ele pode corrigir erros de ortografia ou pesquisar sinônimos.
Um índice de pesquisa de texto completo já foi adicionado quando você criou o banco de dados e o esquema:
CREATE TABLE TransactionLedger ( ... CategoryTokens TOKENLIST AS (TOKENIZE_FULLTEXT(Category)) HIDDEN, DescriptionTokens TOKENLIST AS (TOKENIZE_FULLTEXT(Description)) HIDDEN, ) PRIMARY KEY(AccountId, TransactionId), INTERLEAVE IN PARENT Accounts ON DELETE CASCADE; CREATE SEARCH INDEX TransactionLedgerTextSearch ON TransactionLedger(CategoryTokens, DescriptionTokens);
O método getSpending
usa a função de pesquisa de texto completo SEARCH
para corresponder a esse índice. Ele procura todos os gastos (débitos) nos últimos 30 dias para o ID do cliente.
Para conferir o gasto total do último mês do cliente 1
na categoria groceries
, execute o comando:
java -jar target/onlinebanking.jar query spending 1 groceries
Saída esperada:
Total spending for customer 1 under category groceries: 50
Você também pode encontrar os gastos em outras categorias (que foram categorizadas em uma etapa anterior) ou usar um ID de cliente diferente:
java -jar target/onlinebanking.jar query spending 1 transportation
java -jar target/onlinebanking.jar query spending 1 restaurants
java -jar target/onlinebanking.jar query spending 12 entertainment
Resumo
Nesta etapa, você realizou consultas de correspondência exata, além de pesquisas de texto completo e aproximadas.
A seguir
Em seguida, você vai integrar o Spanner ao Google BigQuery para realizar consultas federadas, permitindo combinar os dados do Spanner em tempo real com os dados do BigQuery.
8. Executar consultas federadas com o BigQuery
Crie o conjunto de dados do BigQuery
Nesta etapa, você vai reunir dados do BigQuery e do Spanner usando consultas federadas.
Para fazer isso, na linha de comando do Cloud Shell, primeiro crie um conjunto de dados MarketingCampaigns
:
bq mk --location=us-central1 MarketingCampaigns
Saída esperada:
Dataset '<PROJECT_ID>:MarketingCampaigns' successfully created.
E uma tabela CustomerSegments
no conjunto de dados:
bq mk --table MarketingCampaigns.CustomerSegments CampaignId:STRING,CampaignName:STRING,CustomerId:INT64
Saída esperada:
Table '<PROJECT_ID>:MarketingCampaigns.CustomerSegments' successfully created.
Em seguida, faça uma conexão do BigQuery com o Spanner:
bq mk --connection \
--connection_type=CLOUD_SPANNER \
--properties="{\"database\": \"projects/$GOOGLE_CLOUD_PROJECT/instances/cloudspanner-onlinebanking/databases/onlinebanking\", \"useParallelism\": true, \"useDataBoost\": true}" \
--location=us-central1 \
spanner-connection
Saída esperada:
Connection <PROJECT_NUMBER>.us-central1.spanner-connection successfully created
Por fim, adicione alguns clientes à tabela do BigQuery que podem ser agrupados com nossos dados do Spanner:
bq query --use_legacy_sql=false '
INSERT INTO MarketingCampaigns.CustomerSegments (CampaignId, CampaignName, CustomerId)
VALUES
("campaign1", "Spring Promotion", 1),
("campaign1", "Spring Promotion", 3),
("campaign1", "Spring Promotion", 5),
("campaign1", "Spring Promotion", 7),
("campaign1", "Spring Promotion", 9),
("campaign1", "Spring Promotion", 11)'
Saída esperada:
Waiting on bqjob_r76a7ce76c5ec948f_0000019644bda052_1 ... (0s) Current status: DONE Number of affected rows: 6
Para verificar se os dados estão disponíveis, consulte o BigQuery:
bq query --use_legacy_sql=false "SELECT * FROM MarketingCampaigns.CustomerSegments"
Saída esperada:
+------------+------------------+------------+ | CampaignId | CampaignName | CustomerId | +------------+------------------+------------+ | campaign1 | Spring Promotion | 1 | | campaign1 | Spring Promotion | 5 | | campaign1 | Spring Promotion | 7 | | campaign1 | Spring Promotion | 9 | | campaign1 | Spring Promotion | 11 | | campaign1 | Spring Promotion | 3 | +------------+------------------+------------+
Esses dados no BigQuery representam dados que foram adicionados em vários fluxos de trabalho do banco. Por exemplo, essa pode ser a lista de clientes que abriram contas recentemente ou se inscreveram em uma promoção de marketing. Para determinar a lista de clientes que queremos segmentar na nossa campanha de marketing, precisamos consultar esses dados no BigQuery e também os dados em tempo real no Spanner. Uma consulta federada permite fazer isso em uma única consulta.
Executar uma consulta federada com o BigQuery
Em seguida, vamos adicionar um método ao aplicativo para chamar EXTERNAL_QUERY
e realizar a consulta federada. Isso permite mesclar e analisar dados de clientes no BigQuery e no Spanner, como identificar quais clientes atendem aos critérios da nossa campanha de marketing com base nos gastos recentes.
Abra App.java
e comece substituindo as importações:
package com.google.codelabs;
import java.io.FileReader;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.Timestamp;
import com.google.cloud.bigquery.BigQuery;
import com.google.cloud.bigquery.BigQueryException;
import com.google.cloud.bigquery.BigQueryOptions;
import com.google.cloud.bigquery.connection.v1.ConnectionName;
import com.google.cloud.bigquery.JobException;
import com.google.cloud.bigquery.QueryJobConfiguration;
import com.google.cloud.bigquery.TableResult;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Key;
import com.google.cloud.spanner.ReadOnlyTransaction;
import com.google.cloud.spanner.ResultSet;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerException;
import com.google.cloud.spanner.SpannerExceptionFactory;
import com.google.cloud.spanner.SpannerOptions;
import com.google.cloud.spanner.Statement;
import com.google.cloud.spanner.Struct;
import com.google.cloud.spanner.TimestampBound;
import com.google.spanner.admin.database.v1.CreateDatabaseMetadata;
import com.opencsv.CSVReader;
Em seguida, adicione o método campaign
:
// Get customers for quarterly marketing campaign in BigQuery using Spanner data
public static void campaign(BigQuery bq, DatabaseId db, String location, String campaignId,
int threshold) {
// The BigQuery dataset, table, and Spanner connection must already exist for this to succeed
ConnectionName connection = ConnectionName.of(db.getInstanceId().getProject(), location,
"spanner-connection");
// Use a federated query to bring Spanner data into BigQuery
String bqQuery = "SELECT cs.CampaignName, c.CustomerId, c.FullName, t.TotalSpending\n"
+ "FROM MarketingCampaigns.CustomerSegments cs\n"
+ "JOIN EXTERNAL_QUERY('" + connection.toString() + "',\n"
+ " \"SELECT t.AccountId, SUM(t.Amount) AS TotalSpending"
+ " FROM TransactionLedger t"
+ " WHERE t.Timestamp >= TIMESTAMP_ADD(CURRENT_TIMESTAMP(), INTERVAL -90 DAY)"
+ " GROUP BY t.AccountId"
+ " HAVING SUM(t.Amount) > " + threshold + "\"\n"
+ ") t ON cs.CustomerId = t.AccountId\n"
+ "JOIN EXTERNAL_QUERY('" + connection.toString() + "',\n"
+ " \"SELECT CustomerId, FullName"
+ " FROM Customers\"\n"
+ ") c ON c.CustomerId = cs.CustomerId\n"
+ "WHERE cs.CampaignId = '" + campaignId + "'";
try {
QueryJobConfiguration queryConfig = QueryJobConfiguration.newBuilder(bqQuery).build();
TableResult results = bq.query(queryConfig);
System.out.println("Customers for campaign (" + campaignId + "):");
results.iterateAll().forEach(row -> {
System.out.println(" " + row.get("FullName").getStringValue()
+ " (" + row.get("CustomerId").getStringValue() + ")");
});
} catch (JobException e) {
throw (BigQueryException) e.getCause();
} catch (InterruptedException e) {
throw SpannerExceptionFactory.propagateInterrupt(e);
}
}
Adicione outra instrução de caso no método main
para a campanha:
case "campaign":
String campaignId = (args.length >= 2) ? args[1] : "";
int threshold = (args.length >= 3) ? Integer.parseInt(args[2]) : 5000;
campaign(bigquery, db, location, campaignId, threshold);
break;
Por fim, adicione como usar a campanha ao método printUsageAndExit
:
System.out.println(" java -jar target/onlinebanking.jar campaign campaign1 5000");
System.out.println(" - Use Federated Queries (BigQuery) to find customers that match a "
+ "marketing campaign by name based on a recent spending threshold.\n");
Salve as alterações que você fez em App.java
.
Recrie o aplicativo:
mvn package
Execute uma consulta federada para determinar os clientes que devem ser incluídos na campanha de marketing (campaign1
) se tiverem gasto pelo menos $5000
nos últimos três meses, executando o comando campaign
:
java -jar target/onlinebanking.jar campaign campaign1 5000
Saída esperada:
Customers for campaign (campaign1): Alice Smith (1) Eve Davis (5) Kelly Thomas (11)
Agora podemos segmentar esses clientes com ofertas ou recompensas exclusivas.
Ou podemos procurar um número maior de clientes que alcançaram um limite de gastos menor nos últimos três meses:
java -jar target/onlinebanking.jar campaign campaign1 2500
Saída esperada:
Customers for campaign (campaign1): Alice Smith (1) Charlie Williams (3) Eve Davis (5) Ivy Taylor (9) Kelly Thomas (11)
Resumo
Nesta etapa, você executou consultas federadas do BigQuery que trouxeram dados do Spanner em tempo real.
A seguir
Em seguida, você pode limpar os recursos criados para este codelab para evitar cobranças.
9. Limpeza (opcional)
Esta etapa é opcional. Se você quiser continuar testando sua instância do Spanner, não é necessário limpá-la no momento. No entanto, o projeto que você está usando vai continuar sendo cobrado pela instância. Se você não precisar mais dessa instância, exclua-a para evitar cobranças. Além da instância do Spanner, este codelab também criou um conjunto de dados e uma conexão do BigQuery, que precisam ser limpos quando não forem mais necessários.
Exclua a instância do Spanner:
gcloud spanner instances delete cloudspanner-onlinebanking
Confirme que você quer continuar (digite Y):
Delete instance [cloudspanner-onlinebanking]. Are you sure? Do you want to continue (Y/n)?
Exclua a conexão e o conjunto de dados do BigQuery:
bq rm --connection --location=us-central1 spanner-connection
bq rm -r MarketingCampaigns
Confirme a exclusão do conjunto de dados do BigQuery (digite Y):
rm: remove dataset '<PROJECT_ID>:MarketingCampaigns'? (y/N)
10. Parabéns
🚀 Você criou uma nova instância do Cloud Spanner, criou um banco de dados vazio, carregou dados de amostra, realizou operações e consultas avançadas e excluiu a instância do Cloud Spanner (opcional).
O que aprendemos
- Como configurar uma instância do Spanner.
- Como criar um banco de dados e tabelas.
- Como carregar dados nas tabelas do banco de dados do Spanner.
- Como chamar modelos da Vertex AI usando o Spanner.
- Como consultar o banco de dados do Spanner usando pesquisa aproximada e de texto completo.
- Como executar consultas federadas no Spanner do BigQuery.
- Como excluir sua instância do Spanner.
A seguir
- Saiba mais sobre os recursos avançados do Spanner, incluindo:
- Consulte as bibliotecas de cliente do Spanner disponíveis.