Spanner की मदद से ऑनलाइन बैंकिंग ऐप्लिकेशन बनाना

1. खास जानकारी

Spanner, पूरी तरह से मैनेज की जाने वाली, हॉरिज़ॉन्टल तौर पर स्केल की जा सकने वाली, और दुनिया भर में उपलब्ध डेटाबेस सेवा है. यह रिलेशनल और नॉन-रिलेशनल, दोनों तरह के ऑपरेशनल वर्कलोड के लिए बेहतरीन है. Spanner की मुख्य सुविधाओं के अलावा, इसमें बेहतर सुविधाएं भी हैं. इनकी मदद से, बेहतर और डेटा-ड्रिवन ऐप्लिकेशन बनाए जा सकते हैं.

इस कोडलैब में, Spanner के बुनियादी सिद्धांतों के बारे में जानकारी दी गई है. साथ ही, इसमें डेटा प्रोसेसिंग और विश्लेषण की क्षमताओं को बेहतर बनाने के लिए, ऑनलाइन बैंकिंग ऐप्लिकेशन का इस्तेमाल करके, Spanner के बेहतर इंटिग्रेशन का फ़ायदा पाने के बारे में बताया गया है.

हम तीन मुख्य ऐडवांस सुविधाओं पर फ़ोकस करेंगे:

  • Vertex AI इंटिग्रेशन: Spanner को Google Cloud के एआई प्लैटफ़ॉर्म, Vertex AI के साथ आसानी से इंटिग्रेट करने का तरीका जानें. इस लेख में, सीधे Spanner SQL क्वेरी से Vertex AI मॉडल को शुरू करने का तरीका बताया गया है. इससे, डेटाबेस में बेहतर बदलाव और अनुमान लगाने की सुविधा चालू होती है. साथ ही, हमारे बैंकिंग ऐप्लिकेशन को बजट ट्रैकिंग और गड़बड़ी का पता लगाने जैसे इस्तेमाल के उदाहरणों के लिए, लेन-देन को अपने-आप कैटगरी में बांटने की सुविधा मिलती है.
  • पूरे टेक्स्ट की खोज: Spanner में पूरे टेक्स्ट की खोज की सुविधा को लागू करने का तरीका जानें. आपको अपने ऑपरेशनल डेटा में कीवर्ड के आधार पर खोज करने के लिए, टेक्स्ट डेटा को इंडेक्स करने और असरदार क्वेरी लिखने का तरीका पता चलेगा. इससे, डेटा की बेहतर तरीके से खोज की जा सकेगी. जैसे, हमारे बैंकिंग सिस्टम में ईमेल पते से ग्राहकों को आसानी से ढूंढना.
  • BigQuery की फ़ेडरेटेड क्वेरी: BigQuery में मौजूद डेटा पर सीधे क्वेरी करने के लिए, Spanner की फ़ेडरेटेड क्वेरी की सुविधाओं का फ़ायदा पाने का तरीका जानें. इसकी मदद से, Spanner के रीयल-टाइम ऑपरेशनल डेटा को BigQuery के विश्लेषण वाले डेटासेट के साथ जोड़ा जा सकता है. इससे, डेटा डुप्लीकेट होने या ETL की जटिल प्रोसेस के बिना, पूरी जानकारी और रिपोर्टिंग मिलती है. साथ ही, हमारे बैंकिंग ऐप्लिकेशन में टारगेट किए गए मार्केटिंग कैंपेन जैसे अलग-अलग इस्तेमाल के उदाहरणों को बेहतर बनाया जा सकता है. इसके लिए, ग्राहक के रीयल-टाइम डेटा को BigQuery के पुराने रुझानों के साथ जोड़ा जाता है.

आपको क्या सीखने को मिलेगा

  • Spanner इंस्टेंस सेट अप करने का तरीका.
  • डेटाबेस और टेबल बनाने का तरीका.
  • Spanner डेटाबेस टेबल में डेटा लोड करने का तरीका.
  • Spanner से Vertex AI मॉडल को कॉल करने का तरीका.
  • फ़ज़ी सर्च और फ़ुल-टेक्स्ट सर्च का इस्तेमाल करके, अपने Spanner डेटाबेस में क्वेरी करने का तरीका.
  • BigQuery से Spanner के लिए फ़ेडरेटेड क्वेरी करने का तरीका.
  • Spanner इंस्टेंस को मिटाने का तरीका.

आपको किन चीज़ों की ज़रूरत होगी

  • Google Cloud का ऐसा प्रोजेक्ट जो किसी बिलिंग खाते से जुड़ा हो.
  • Chrome या Firefox जैसा कोई वेब ब्राउज़र.

2. सेटअप और ज़रूरी शर्तें

प्रोजेक्ट बनाना

अगर आपके पास पहले से ही कोई ऐसा Google Cloud प्रोजेक्ट है जिसमें बिलिंग की सुविधा चालू है, तो कंसोल के ऊपर बाईं ओर मौजूद, प्रोजेक्ट चुनने के लिए उपलब्ध पुल-डाउन मेन्यू पर क्लिक करें:

मौजूदा प्रोजेक्ट

चुने गए प्रोजेक्ट के लिए, ज़रूरी एपीआई चालू करें पर जाएं.

अगर आपके पास पहले से कोई Google खाता (Gmail या Google Apps) नहीं है, तो आपको एक खाता बनाना होगा. Google Cloud Platform Console (console.cloud.google.com) में साइन इन करें और नया प्रोजेक्ट बनाएं.

नया प्रोजेक्ट बनाने के लिए, डायलॉग बॉक्स में "नया प्रोजेक्ट" बटन पर क्लिक करें:

नया प्रोजेक्ट

अगर आपके पास पहले से कोई प्रोजेक्ट नहीं है, तो आपको अपना पहला प्रोजेक्ट बनाने के लिए, ऐसा डायलॉग दिखेगा:

प्रोजेक्ट डायलॉग

प्रोजेक्ट बनाने के बाद दिखने वाले डायलॉग बॉक्स में, अपने नए प्रोजेक्ट की जानकारी डाली जा सकती है.

प्रोजेक्ट आईडी को याद रखें. यह Google Cloud के सभी प्रोजेक्ट में एक यूनीक नाम होता है. इस कोडलैब में बाद में इसे PROJECT_ID कहा जाएगा.

प्रोजेक्ट विवरण

इसके बाद, अगर आपने अब तक ऐसा नहीं किया है, तो Google Cloud के संसाधनों का इस्तेमाल करने और Spanner API, Vertex AI API, BigQuery API, और BigQuery Connection API को चालू करने के लिए, आपको Developers Console में बिलिंग की सुविधा चालू करनी होगी.

प्रोजेक्ट की बिलिंग

Spanner की कीमत की जानकारी यहां दी गई है. अन्य रिसॉर्स से जुड़ी अन्य लागतों की जानकारी, उनके खास कीमत वाले पेजों पर दी जाएगी.

Google Cloud Platform के नए उपयोगकर्ताओं को 300 डॉलर का क्रेडिट मुफ़्त में मिलता है.

Google Cloud Shell का सेटअप

इस कोडलैब में, हम Google Cloud Shell का इस्तेमाल करेंगे. यह Cloud में चलने वाला कमांड लाइन एनवायरमेंट है.

Debian पर आधारित इस वर्चुअल मशीन में, डेवलपमेंट के लिए ज़रूरी सभी टूल लोड होते हैं. यह 5 जीबी की होम डायरेक्ट्री उपलब्ध कराती है और Google Cloud में चलती है. इससे नेटवर्क की परफ़ॉर्मेंस और पुष्टि करने की प्रोसेस बेहतर होती है. इसका मतलब है कि इस कोडलैब के लिए, आपको सिर्फ़ एक ब्राउज़र की ज़रूरत होगी.

Cloud Console से Cloud Shell को चालू करने के लिए, बस Cloud Shell चालू करें Cloud Shell का आइकॉन पर क्लिक करें. एनवायरमेंट को प्रोवाइड करने और उससे कनेक्ट होने में कुछ ही मिनट लगेंगे.

Cloud Shell

Cloud Shell से कनेक्ट होने के बाद, आपको दिखेगा कि आपने पहले ही पुष्टि कर ली है और प्रोजेक्ट पहले से ही आपके PROJECT_ID पर सेट है.

gcloud auth list

अनुमानित आउटपुट:

Credentialed Accounts

ACTIVE: *
ACCOUNT: <myaccount>@<mydomain>.com
gcloud config list project

अनुमानित आउटपुट:

[core]
project = <PROJECT_ID>

अगर किसी वजह से प्रोजेक्ट सेट नहीं है, तो यह कमांड दें:

gcloud config set project <PROJECT_ID>

क्या आपको अपना PROJECT_ID ढूंढना है? देखें कि सेटअप के दौरान आपने किस आईडी का इस्तेमाल किया था या Cloud Console डैशबोर्ड में जाकर उसे देखें:

प्रोजेक्ट आईडी

Cloud Shell, कुछ एनवायरमेंट वैरिएबल भी डिफ़ॉल्ट रूप से सेट करता है. ये आने वाले समय में कमांड चलाने के दौरान काम के हो सकते हैं.

echo $GOOGLE_CLOUD_PROJECT

अनुमानित आउटपुट:

<PROJECT_ID>

ज़रूरी एपीआई चालू करना

अपने प्रोजेक्ट के लिए Spanner, Vertex AI, और BigQuery API चालू करें:

gcloud services enable spanner.googleapis.com
gcloud services enable aiplatform.googleapis.com
gcloud services enable bigquery.googleapis.com
gcloud services enable bigqueryconnection.googleapis.com

खास जानकारी

इस चरण में, आपने अपना प्रोजेक्ट सेट अप किया है. अगर आपके पास पहले से कोई प्रोजेक्ट नहीं था, तो आपने Cloud Shell चालू किया है और ज़रूरी एपीआई चालू किए हैं.

अगला लेख

इसके बाद, आपको Spanner इंस्टेंस सेट अप करना होगा.

3. Spanner इंस्टेंस सेट अप करना

Spanner इंस्टेंस बनाना

इस चरण में, आपको कोडलैब के लिए Spanner इंस्टेंस सेट अप करना होगा. ऐसा करने के लिए, Cloud Shell खोलें और यह कमांड चलाएं:

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

अनुमानित आउटपुट:

Creating instance...done.

खास जानकारी

इस चरण में, आपने Spanner इंस्टेंस बनाया है.

अगला लेख

इसके बाद, आपको शुरुआती ऐप्लिकेशन तैयार करना होगा और डेटाबेस और स्कीमा बनाना होगा.

4. डेटाबेस और स्कीमा बनाना

शुरुआती आवेदन तैयार करना

इस चरण में, आपको कोड की मदद से डेटाबेस और स्कीमा बनाना होगा.

सबसे पहले, Maven का इस्तेमाल करके onlinebanking नाम का एक Java ऐप्लिकेशन बनाएं:

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

डेटाबेस में जोड़ी जाने वाली डेटा फ़ाइलों को चेकआउट करें और कॉपी करें. कोड रिपॉज़िटरी के लिए यहां देखें:

git clone https://github.com/GoogleCloudPlatform/cloud-spanner-samples.git
cp -r ./cloud-spanner-samples/banking/data ./onlinebanking

ऐप्लिकेशन फ़ोल्डर पर जाएं:

cd onlinebanking

Maven pom.xml फ़ाइल खोलें. Google Cloud लाइब्रेरी के वर्शन को मैनेज करने के लिए, Maven BOM का इस्तेमाल करने के लिए डिपेंडेंसी मैनेजमेंट सेक्शन जोड़ें:

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

एडिटर और फ़ाइल कुछ इस तरह दिखेगी: Cloud Shell

पक्का करें कि dependencies सेक्शन में वे लाइब्रेरी शामिल हों जिनका इस्तेमाल ऐप्लिकेशन करेगा:

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

आखिर में, बिल्ड प्लग इन बदलें, ताकि ऐप्लिकेशन को चलाए जा सकने वाले JAR में पैकेज किया जा सके:

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

pom.xml फ़ाइल में किए गए बदलावों को सेव करने के लिए, Cloud Shell Editor के "फ़ाइल" मेन्यू में जाकर "सेव करें" को चुनें या Ctrl+S दबाएं.

अब डिपेंडेंसी तैयार हैं. अब आपको ऐप्लिकेशन में कोड जोड़ना होगा, ताकि स्कीमा, कुछ इंडेक्स (खोज के साथ) और रिमोट एंडपॉइंट से कनेक्ट किया गया एआई मॉडल बनाया जा सके. इस कोडलैब में, आपको इन आर्टफ़ैक्ट के आधार पर काम करना होगा और इस क्लास में और तरीके जोड़ने होंगे.

onlinebanking/src/main/java/com/google/codelabs में जाकर App.java खोलें और कॉन्टेंट को इस कोड से बदलें:

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

बदलावों को App.java में सेव करें.

उन अलग-अलग इकाइयों को देखें जिन्हें आपका कोड बना रहा है और ऐप्लिकेशन JAR बनाएं:

mvn package

अनुमानित आउटपुट:

[INFO] Building jar: /home/your_user/onlinebanking/target/onlinebanking.jar
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS

इस्तेमाल से जुड़ी जानकारी देखने के लिए, ऐप्लिकेशन चलाएं:

java -jar target/onlinebanking.jar

अनुमानित आउटपुट:

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.

डेटाबेस और स्कीमा बनाना

ऐप्लिकेशन के एनवायरमेंट के लिए ज़रूरी वैरिएबल सेट करें:

export SPANNER_INSTANCE=cloudspanner-onlinebanking
export SPANNER_DATABASE=onlinebanking

create कमांड चलाकर, डेटाबेस और स्कीमा बनाएं:

java -jar target/onlinebanking.jar create

अनुमानित आउटपुट:

Creating Spanner database...
Created Spanner database [<DATABASE_RESOURCE_NAME>]

Spanner में स्कीमा देखना

Spanner कंसोल में, अपने इंस्टेंस और हाल ही में बनाए गए डेटाबेस पर जाएं.

आपको तीनों टेबल - Accounts, Customers, और TransactionLedger दिखनी चाहिए.

स्कीमा देखना

यह कार्रवाई, डेटाबेस स्कीमा बनाती है. इसमें Accounts, Customers, और TransactionLedger टेबल के साथ-साथ, डेटा को ऑप्टिमाइज़ करके वापस पाने के लिए सेकंडरी इंडेक्स और Vertex AI मॉडल का रेफ़रंस शामिल होता है.

इकाई के बीच संबंध दिखाने वाला डायग्राम

TransactionLedger टेबल को खातों में इंटरलीव किया जाता है, ताकि डेटा लोकलिटी को बेहतर करके, खाते से जुड़े लेन-देन के लिए क्वेरी की परफ़ॉर्मेंस को बेहतर बनाया जा सके.

इस कोडलैब में इस्तेमाल किए गए डेटा ऐक्सेस के सामान्य पैटर्न को ऑप्टिमाइज़ करने के लिए, सेकंडरी इंडेक्स (CustomersByEmail, CustomersFuzzyEmail, AccountsByCustomer, TransactionLedgerByAccountType, TransactionLedgerByCategory, TransactionLedgerTextSearch) लागू किए गए थे. जैसे, सटीक और फ़ज़ी ईमेल के हिसाब से ग्राहक लुकअप, ग्राहक के हिसाब से खाते वापस लाना, और लेन-देन के डेटा को बेहतर तरीके से क्वेरी करना और खोजना.

TransactionCategoryModel, एलएलएम को सीधे SQL कॉल करने के लिए Vertex AI का इस्तेमाल करता है. इस कोडलैब में, इसका इस्तेमाल ट्रांज़ैक्शन की डाइनैमिक कैटगरी तय करने के लिए किया जाता है.

खास जानकारी

इस चरण में, आपने Spanner डेटाबेस और स्कीमा बना लिया है.

अगला लेख

इसके बाद, आपको ऐप्लिकेशन का सैंपल डेटा लोड करना होगा.

5. डेटा लोड करें

अब, आपको CSV फ़ाइलों से सैंपल डेटा को डेटाबेस में लोड करने की सुविधा जोड़नी होगी.

App.java खोलें और इंपोर्ट किए गए डेटा को बदलने की प्रोसेस शुरू करें:

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;

इसके बाद, क्लास 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;
        });
  }

switch (command) में शामिल करने के लिए, main तरीके में एक और केस स्टेटमेंट जोड़ें:

        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;

आखिर में, printUsageAndExit तरीके में इंसर्ट का इस्तेमाल करने का तरीका जोड़ें:

    System.out.println("  java -jar target/onlinebanking.jar insert");
    System.out.println("      - Insert sample Customers, Accounts, and Transactions into the "
        + "database.\n");

App.java में किए गए बदलावों को सेव करें.

ऐप्लिकेशन को फिर से बनाएं:

mvn package

insert कमांड चलाकर, सैंपल डेटा डालें:

java -jar target/onlinebanking.jar insert

अनुमानित आउटपुट:

Inserting customers...
Inserted 100 customers
Inserting accounts...
Inserted 125 accounts
Inserting transactions...
Inserted 200 transactions

Spanner Console में, अपने इंस्टेंस और डेटाबेस के लिए Spanner Studio पर वापस जाएं. इसके बाद, TransactionLedger टेबल चुनें और डेटा लोड होने की पुष्टि करने के लिए, साइडबार में "डेटा" पर क्लिक करें. टेबल में 200 लाइनें होनी चाहिए.

डेटा देखें

खास जानकारी

इस चरण में, आपने डेटाबेस में सैंपल डेटा डाला.

अगला लेख

इसके बाद, Vertex AI इंटिग्रेशन का फ़ायदा उठाकर, सीधे Spanner SQL में बैंकिंग लेन-देन को अपने-आप कैटगरी में बांटा जा सकता है.

6. Vertex AI की मदद से डेटा को कैटगरी में बांटना

इस चरण में, Vertex AI की मदद से, सीधे Spanner SQL में अपने वित्तीय लेन-देन की कैटगरी अपने-आप तय की जा सकती है. Vertex AI की मदद से, पहले से ट्रेन किया गया कोई मौजूदा मॉडल चुना जा सकता है या अपना मॉडल ट्रेन करके उसे डिप्लॉय किया जा सकता है. Vertex AI मॉडल गार्डन में उपलब्ध मॉडल देखें.

इस कोडलैब के लिए, हम Gemini के किसी मॉडल, Gemini Flash Lite का इस्तेमाल करेंगे. Gemini का यह वर्शन, कम लागत में काम करता है. इसके बावजूद, यह रोज़ाना के ज़्यादातर वर्कलोड को मैनेज कर सकता है.

फ़िलहाल, हमारे पास कई वित्तीय लेन-देन हैं. हमें इनके ब्यौरे के आधार पर, इनकी कैटगरी (groceries, transportation वगैरह) तय करनी है. ऐसा करने के लिए, Spanner में मॉडल रजिस्टर करें. इसके बाद, एआई मॉडल को कॉल करने के लिए ML.PREDICT का इस्तेमाल करें.

अपने बैंकिंग ऐप्लिकेशन में, हम लेन-देन की कैटगरी बना सकते हैं, ताकि ग्राहक के व्यवहार के बारे में ज़्यादा जानकारी मिल सके. इससे हम सेवाओं को उनके हिसाब से बना सकते हैं, गड़बड़ियों का ज़्यादा असरदार तरीके से पता लगा सकते हैं या ग्राहक को हर महीने अपने बजट को ट्रैक करने की सुविधा दे सकते हैं.

डेटाबेस और स्कीमा बनाते समय, पहला चरण पहले ही पूरा हो चुका था. इससे ऐसा मॉडल बनता है:

create model statement

इसके बाद, हम ऐप्लिकेशन में ML.PREDICT को कॉल करने का एक तरीका जोड़ेंगे.

App.java खोलें और 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;
    }
  }

कैटगरी तय करने के लिए, main तरीके में एक और केस स्टेटमेंट जोड़ें:

        case "categorize":
          categorize(dbClient);
          break;

आखिर में, printUsageAndExit तरीके में कैटगरी का इस्तेमाल करने का तरीका जोड़ें:

    System.out.println("  java -jar target/onlinebanking.jar categorize");
    System.out.println("      - Use AI to categorize transactions in the database.\n");

App.java में किए गए बदलावों को सेव करें.

ऐप्लिकेशन को फिर से बनाएं:

mvn package

categorize कमांड चलाकर, डेटाबेस में मौजूद लेन-देन को अलग-अलग कैटगरी में बांटें:

java -jar target/onlinebanking.jar categorize

अनुमानित आउटपुट:

Categorizing transactions...
Completed categorizing transactions

Spanner Studio में, TransactionLedger टेबल के लिए डेटा की झलक स्टेटमेंट चलाएं. अब Category कॉलम में सभी पंक्तियों के लिए जानकारी दिखनी चाहिए.

कैटगरी के हिसाब से डेटा देखना

अब हमने लेन-देन की कैटगरी तय कर ली है. इस जानकारी का इस्तेमाल, संगठन के अंदर या ग्राहकों से जुड़ी क्वेरी के लिए किया जा सकता है. अगले चरण में, हम यह पता लगाएंगे कि कोई ग्राहक महीने भर में किसी कैटगरी में कितना खर्च कर रहा है.

खास जानकारी

इस चरण में, आपने एआई की मदद से अपने डेटा को अलग-अलग कैटगरी में बांटने के लिए, पहले से ट्रेन किए गए मॉडल का इस्तेमाल किया.

अगला लेख

इसके बाद, फ़ज़ी और फ़ुल-टेक्स्ट खोज करने के लिए, टोकनाइज़ेशन का इस्तेमाल किया जाएगा.

7. पूरे टेक्स्ट की खोज का इस्तेमाल करके क्वेरी करना

क्वेरी कोड जोड़ना

Spanner, पूरे टेक्स्ट की खोज क्वेरी की कई सुविधाएं देता है. इस चरण में, आपको एग्ज़ैक्ट मैच वाली खोज करनी होगी. इसके बाद, फ़ज़ी खोज और पूरे टेक्स्ट वाली खोज करनी होगी.

App.java खोलें और इंपोर्ट किए गए डेटा को बदलने की प्रोसेस शुरू करें:

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;

इसके बाद, क्वेरी के तरीके जोड़ें:

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

क्वेरी के लिए main तरीके में एक और case स्टेटमेंट जोड़ें:

        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;

आखिर में, 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");

App.java में किए गए बदलावों को सेव करें.

ऐप्लिकेशन को फिर से बनाएं:

mvn package

ग्राहक के खाते के बैलेंस के लिए एग्ज़ैक्ट मैच वाली खोज करना

एग्ज़ैक्ट मैच वाली क्वेरी, किसी शब्द से पूरी तरह मैच करने वाली पंक्तियों को खोजती है.

परफ़ॉर्मेंस को बेहतर बनाने के लिए, डेटाबेस और स्कीमा बनाते समय एक इंडेक्स पहले से ही जोड़ दिया गया था:

  "CREATE INDEX AccountsByCustomer\n"
          + "ON Accounts (CustomerId)",

getBalance तरीका, दिए गए customerId से मैच करने वाले ग्राहकों को ढूंढने के लिए, इस इंडेक्स का इस्तेमाल करता है. साथ ही, उस ग्राहक के खातों से भी जॉइन करता है.

सीधे Spanner Studio में लागू करने पर, क्वेरी इस तरह दिखती है: बैलेंस की जानकारी मैन्युअल तरीके से पाने के लिए

ग्राहक 1 के खाते के बैलेंस की सूची देखने के लिए, यह कमांड चलाएं:

java -jar target/onlinebanking.jar query balance 1

अनुमानित आउटपुट:

Account balances for customer 1:
  Account 1: 9875.25
  Account 7: 9900
  Account 110: 38200

यहां 100 ग्राहक हैं. इसलिए, किसी दूसरे ग्राहक आईडी का इस्तेमाल करके, किसी भी ग्राहक के खाते के बैलेंस के बारे में क्वेरी की जा सकती है:

java -jar target/onlinebanking.jar query balance 5
java -jar target/onlinebanking.jar query balance 10
java -jar target/onlinebanking.jar query balance 99

ग्राहकों के ईमेल में फ़ज़ी सर्च करना

फ़ज़ी सर्च की मदद से, खोज के लिए इस्तेमाल हुए शब्दों से मिलते-जुलते शब्दों को खोजा जा सकता है. इनमें स्पेलिंग के वैरिएशन और टाइपिंग की गलतियां शामिल हैं.

डेटाबेस और स्कीमा बनाते समय, n-gram इंडेक्स पहले से ही जोड़ दिया गया था:

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

findCustomers तरीका, ईमेल से ग्राहकों को ढूंढने के लिए, इस इंडेक्स के ख़िलाफ़ क्वेरी करने के लिए SEARCH_NGRAMS और SCORE_NGRAMS का इस्तेमाल करता है. ईमेल कॉलम को n-gram टोकन में बदला गया है. इसलिए, इस क्वेरी में स्पेलिंग की गलतियां हो सकती हैं. इसके बावजूद, सही जवाब मिल सकता है. नतीजों को सबसे ज़्यादा मिलते-जुलते शब्द के हिसाब से क्रम में लगाया जाता है.

ग्राहक के ऐसे ईमेल पते ढूंढें जिनमें madi शामिल हो. इसके लिए, यह कमांड चलाएं:

java -jar target/onlinebanking.jar query email madi

अनुमानित आउटपुट:

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

इस जवाब में, madi या मिलती-जुलती स्ट्रिंग वाले सबसे मिलते-जुलते मैच, रैंक के हिसाब से दिखाए जाते हैं.

सीधे Spanner Studio में लागू करने पर, क्वेरी इस तरह दिखती है: मैन्युअल तरीके से madi खोजना

फ़ज़ी सर्च की मदद से, वर्तनी की गलतियां भी ठीक की जा सकती हैं. जैसे, 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

अनुमानित आउटपुट:

Customer emails matching emliy (top 10 matches):
  Customer 31: emily.lopez@example.com

हर मामले में, ग्राहक का अनुमानित ईमेल सबसे ज़्यादा हिट के तौर पर दिखता है.

Spanner की फ़ुल-टेक्स्ट सर्च की सुविधा का इस्तेमाल, कीवर्ड या वाक्यांशों के आधार पर रिकॉर्ड वापस पाने के लिए किया जाता है. यह स्पेलिंग की गलतियां ठीक कर सकता है या मिलते-जुलते शब्दों को खोज सकता है.

डेटाबेस और स्कीमा बनाते समय, फ़ुल-टेक्स्ट सर्च इंडेक्स पहले से ही जोड़ दिया गया था:

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

getSpending तरीका, उस इंडेक्स से मैच करने के लिए SEARCH फ़ुल-टेक्स्ट सर्च फ़ंक्शन का इस्तेमाल करता है. यह दिए गए ग्राहक आईडी के लिए, पिछले 30 दिनों में किए गए सभी खर्च (डेबिट) को ढूंढता है.

groceries कैटगरी में मौजूद ग्राहक 1 के लिए, पिछले महीने का कुल खर्च जानने के लिए यह कमांड चलाएं:

java -jar target/onlinebanking.jar query spending 1 groceries

अनुमानित आउटपुट:

Total spending for customer 1 under category groceries:
  50

आपके पास अन्य कैटगरी (जिन्हें हमने पिछले चरण में कैटगरी में बांटा था) में भी खर्च देखने का विकल्प है. इसके अलावा, किसी दूसरे ग्राहक आईडी का इस्तेमाल भी किया जा सकता है:

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

खास जानकारी

इस चरण में, आपने एग्ज़ैक्ट मैच वाली क्वेरी के साथ-साथ फ़ज़ी और पूरे टेक्स्ट वाली खोजें की हैं.

अगला लेख

इसके बाद, आपको फ़ेडरेटेड क्वेरी करने के लिए, Spanner को Google BigQuery के साथ इंटिग्रेट करना होगा. इससे, आपको Spanner के रीयल-टाइम डेटा को BigQuery के डेटा के साथ जोड़ने में मदद मिलेगी.

8. BigQuery की मदद से फ़ेडरेटेड क्वेरी चलाना

BigQuery डेटासेट बनाना

इस चरण में, आपको फ़ेडरेटेड क्वेरी का इस्तेमाल करके, BigQuery और Spanner डेटा को एक साथ लाने की सुविधा मिलेगी.

ऐसा करने के लिए, Cloud Shell कमांड लाइन में सबसे पहले MarketingCampaigns डेटासेट बनाएं:

bq mk --location=us-central1 MarketingCampaigns

अनुमानित आउटपुट:

Dataset '<PROJECT_ID>:MarketingCampaigns' successfully created.

और डेटासेट में CustomerSegments टेबल:

bq mk --table MarketingCampaigns.CustomerSegments CampaignId:STRING,CampaignName:STRING,CustomerId:INT64

अनुमानित आउटपुट:

Table '<PROJECT_ID>:MarketingCampaigns.CustomerSegments' successfully created.

इसके बाद, BigQuery से 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

अनुमानित आउटपुट:

Connection <PROJECT_NUMBER>.us-central1.spanner-connection successfully created

आखिर में, BigQuery टेबल में कुछ ऐसे ग्राहक जोड़ें जिन्हें हमारे 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)'

अनुमानित आउटपुट:

Waiting on bqjob_r76a7ce76c5ec948f_0000019644bda052_1 ... (0s) Current status: DONE
Number of affected rows: 6

BigQuery से क्वेरी करके, यह पुष्टि की जा सकती है कि डेटा उपलब्ध है या नहीं:

bq query --use_legacy_sql=false "SELECT * FROM MarketingCampaigns.CustomerSegments"

अनुमानित आउटपुट:

+------------+------------------+------------+
| 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 |
+------------+------------------+------------+

BigQuery में मौजूद यह डेटा, बैंक के अलग-अलग वर्कफ़्लो से जोड़े गए डेटा को दिखाता है. उदाहरण के लिए, यह उन ग्राहकों की सूची हो सकती है जिन्होंने हाल ही में खाते खोले हैं या मार्केटिंग प्रमोशन के लिए साइन अप किया है. हमें अपने मार्केटिंग कैंपेन में किन ग्राहकों को टारगेट करना है, यह तय करने के लिए हमें BigQuery में मौजूद इस डेटा और Spanner में मौजूद रीयल-टाइम डेटा, दोनों पर क्वेरी करनी होगी. फ़ेडरेटेड क्वेरी की मदद से, हम एक ही क्वेरी में ऐसा कर सकते हैं.

BigQuery की मदद से फ़ेडरेट की गई क्वेरी चलाना

इसके बाद, हम ऐप्लिकेशन में एक तरीका जोड़ेंगे, ताकि फ़ेडरेटेड क्वेरी करने के लिए EXTERNAL_QUERY को कॉल किया जा सके. इससे, BigQuery और Spanner में मौजूद ग्राहक डेटा को जोड़ने और उसका विश्लेषण करने में मदद मिलेगी. जैसे, यह पता लगाना कि हाल ही में किए गए खर्च के आधार पर, कौनसे ग्राहक हमारे मार्केटिंग कैंपेन की ज़रूरी शर्तें पूरी करते हैं.

App.java खोलें और इंपोर्ट किए गए डेटा को बदलने की प्रोसेस शुरू करें:

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;

इसके बाद, 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);
    }
  }

कैंपेन के लिए main तरीके में एक और केस स्टेटमेंट जोड़ें:

        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;

आखिर में, 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");

App.java में किए गए बदलावों को सेव करें.

ऐप्लिकेशन को फिर से बनाएं:

mvn package

campaign कमांड चलाकर, पिछले तीन महीनों में कम से कम $5000 खर्च करने वाले ग्राहकों को मार्केटिंग कैंपेन (campaign1) में शामिल करने के लिए, फ़ेडरेटेड क्वेरी चलाएं:

java -jar target/onlinebanking.jar campaign campaign1 5000

अनुमानित आउटपुट:

Customers for campaign (campaign1):
  Alice Smith (1)
  Eve Davis (5)
  Kelly Thomas (11)

अब हम इन ग्राहकों को खास ऑफ़र या इनामों के साथ टारगेट कर सकते हैं.

इसके अलावा, हम उन ग्राहकों की संख्या भी देख सकते हैं जिन्होंने पिछले तीन महीनों में खर्च करने का थ्रेशोल्ड पूरा किया है:

java -jar target/onlinebanking.jar campaign campaign1 2500

अनुमानित आउटपुट:

Customers for campaign (campaign1):
  Alice Smith (1)
  Charlie Williams (3)
  Eve Davis (5)
  Ivy Taylor (9)
  Kelly Thomas (11)

खास जानकारी

इस चरण में, आपने BigQuery से फ़ेडरेट की गई क्वेरी को सफलतापूर्वक लागू किया, जिससे Spanner का रीयल-टाइम डेटा मिला.

अगला लेख

इसके बाद, शुल्क से बचने के लिए, इस कोडलैब के लिए बनाए गए संसाधनों को हटाया जा सकता है.

9. क्लीनअप (ज़रूरी नहीं)

यह करना ज़रूरी नहीं है. अगर आपको अपने Spanner इंस्टेंस के साथ प्रयोग जारी रखना है, तो आपको इस समय उसे खाली करने की ज़रूरत नहीं है. हालांकि, जिस प्रोजेक्ट का इस्तेमाल किया जा रहा है उससे इंस्टेंस के लिए शुल्क लिया जाता रहेगा. अगर आपको इस इंस्टेंस की अब ज़रूरत नहीं है, तो इन शुल्कों से बचने के लिए, इसे अभी मिटा दें. इस कोडलैब में, Spanner इंस्टेंस के अलावा एक BigQuery डेटासेट और कनेक्शन भी बनाया गया है. जब इनकी ज़रूरत न हो, तब इन्हें मिटा देना चाहिए.

Spanner इंस्टेंस मिटाएं:

gcloud spanner instances delete cloudspanner-onlinebanking

पुष्टि करें कि आपको जारी रखना है (Y टाइप करें):

Delete instance [cloudspanner-onlinebanking]. Are you sure?

Do you want to continue (Y/n)?

BigQuery कनेक्शन और डेटासेट मिटाएं:

bq rm --connection --location=us-central1 spanner-connection
bq rm -r MarketingCampaigns

BigQuery डेटासेट मिटाने की पुष्टि करें (Y टाइप करें):

rm: remove dataset '<PROJECT_ID>:MarketingCampaigns'? (y/N)

10. बधाई हो

🚀 आपने नया Cloud Spanner इंस्टेंस बनाया है, खाली डेटाबेस बनाया है, सैंपल डेटा लोड किया है, बेहतर ऑपरेशन और क्वेरी की हैं, और (ज़रूरी नहीं) Cloud Spanner इंस्टेंस को मिटाया है.

हमने क्या-क्या कवर किया है

  • Spanner इंस्टेंस सेट अप करने का तरीका.
  • डेटाबेस और टेबल बनाने का तरीका.
  • Spanner डेटाबेस टेबल में डेटा लोड करने का तरीका.
  • Spanner से Vertex AI मॉडल को कॉल करने का तरीका.
  • फ़ज़ी सर्च और फ़ुल-टेक्स्ट सर्च का इस्तेमाल करके, अपने Spanner डेटाबेस में क्वेरी करने का तरीका.
  • BigQuery से Spanner के लिए फ़ेडरेटेड क्वेरी करने का तरीका.
  • Spanner इंस्टेंस को मिटाने का तरीका.

आगे क्या करना है?