Udostępnij za pośrednictwem


Szybki start: wyszukiwanie wektorów przy użyciu Java w Azure Cosmos DB

Użyj wyszukiwania wektorów w Azure Cosmos DB z biblioteką klienta Java. Wydajne przechowywanie danych wektorów i wykonywanie zapytań w aplikacjach.

W tym przewodniku szybkiego startu użyto przykładowego hotelowego zestawu danych zawartego w pliku JSON z wektorami z modelu text-embedding-3-small. Zestaw danych zawiera nazwy hoteli, lokalizacje, opisy i osadzanie wektorów.

Znajdź przykładowy kod z aprowizowaniem zasobów w GitHub.

Wymagania wstępne

Tworzenie pliku danych z wektorami

  1. Utwórz nowy katalog danych dla pliku danych hoteli:

    mkdir data
    
  2. Pobierz plik danych raw z wektorami do katalogu data:

    curl -o data/HotelsData_toCosmosDB_Vector.json https://raw.githubusercontent.com/Azure-Samples/cosmos-db-vector-samples/refs/heads/main/data/HotelsData_toCosmosDB_Vector.json
    

Tworzenie projektu Java

  1. Utwórz nowy katalog równorzędny dla projektu na tym samym poziomie co katalog danych i otwórz go w Visual Studio Code:

    mkdir vector-search-quickstart
    cd vector-search-quickstart
    code .
    
  2. pom.xml Utwórz plik w katalogu głównym projektu przy użyciu konfiguracji narzędzia Maven:

    <project xmlns="http://maven.apache.org/POM/4.0.0"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
        <modelVersion>4.0.0</modelVersion>
    
        <groupId>com.example.cosmos.samples</groupId>
        <artifactId>nosql-vector-search-sample</artifactId>
        <version>1.0.0</version>
        <name>Azure Cosmos DB NoSQL Vector Search - Java</name>
    
        <properties>
            <maven.compiler.release>21</maven.compiler.release>
            <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        </properties>
    
        <dependencies>
            <!-- Azure Cosmos DB SDK (NoSQL API) -->
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-cosmos</artifactId>
                <version>4.69.0</version>
            </dependency>
    
            <!-- Azure Identity (DefaultAzureCredential) -->
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-identity</artifactId>
                <version>1.18.1</version>
            </dependency>
    
            <!-- Azure OpenAI (embeddings) -->
            <dependency>
                <groupId>com.azure</groupId>
                <artifactId>azure-ai-openai</artifactId>
                <version>1.0.0-beta.16</version>
            </dependency>
    
            <!-- Jackson (JSON serialization) -->
            <dependency>
                <groupId>tools.jackson.core</groupId>
                <artifactId>jackson-databind</artifactId>
                <version>3.0.3</version>
            </dependency>
    
            <!-- Suppress noisy SDK logging -->
            <dependency>
                <groupId>org.slf4j</groupId>
                <artifactId>slf4j-nop</artifactId>
                <version>2.0.17</version>
                <scope>runtime</scope>
            </dependency>
        </dependencies>
    
        <build>
            <plugins>
                <plugin>
                    <groupId>org.codehaus.mojo</groupId>
                    <artifactId>exec-maven-plugin</artifactId>
                    <version>3.5.0</version>
                    <configuration>
                        <mainClass>com.example.cosmos.vectorsearch.VectorSearch</mainClass>
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </project>
    

    Kluczowe zależności:

    • azure-identity — biblioteka uwierzytelniania Azure dla połączeń bez hasła (tożsamości zarządzanej)
    • azure-cosmos — biblioteka klienta Azure Cosmos DB dla operacji bazy danych
    • azure-ai-openai — SDK platformy Azure OpenAI do generowania wektorów osadzania
    • slf4j-nop — pomija głośne rejestrowanie zestawu SDK w czasie wykonywania
  3. Utwórz strukturę katalogu źródłowego:

    mkdir -p src/main/java/com/example/cosmos/vectorsearch
    
  4. .env Utwórz plik w katalogu głównym projektu dla zmiennych środowiskowych:

    # Azure OpenAI Embedding Settings
    AZURE_OPENAI_EMBEDDING_MODEL=text-embedding-3-small
    AZURE_OPENAI_EMBEDDING_API_VERSION=2024-08-01-preview
    AZURE_OPENAI_EMBEDDING_ENDPOINT=
    
    # Cosmos DB configuration
    AZURE_COSMOSDB_ENDPOINT=
    
    # Data file
    DATA_FILE_WITH_VECTORS=../data/HotelsData_toCosmosDB_Vector.json
    FIELD_TO_EMBED=Description
    EMBEDDED_FIELD=DescriptionVector
    EMBEDDING_DIMENSIONS=1536
    
    # Vector search algorithm: diskann or quantizedflat
    VECTOR_ALGORITHM=diskann
    

    Zastąp wartości znaczników zastępczych w pliku .env własnymi informacjami:

    • AZURE_OPENAI_EMBEDDING_ENDPOINT: Adres URL punktu końcowego zasobu Azure OpenAI
    • AZURE_COSMOSDB_ENDPOINT: Adres URL punktu końcowego Azure Cosmos DB

    Uwaga / Notatka

    Przykład Java używa System.getenv() do odczytywania zmiennych środowiskowych. Należy wyeksportować te zmienne w sesji powłoki lub użyć azd env get-values, aby je ustawić. Plik .env służy jako szablon odwołania — nie jest ładowany automatycznie przez aplikację.

Omówienie schematu dokumentu

Przed utworzeniem aplikacji dowiedz się, jak wektory są przechowywane w dokumentach Azure Cosmos DB. Każdy dokument hotelowy zawiera:

  • Pola standardowe: HotelId, HotelName, Description, Category, itp.
  • Pole wektorowe: DescriptionVector — tablica 1536 liczb zmiennoprzecinkowych reprezentujących semantyczne znaczenie opisu hotelu

Oto uproszczony przykład struktury dokumentów hotelowych:

{
  "HotelId": "1",
  "HotelName": "Stay-Kay City Hotel",
  "Description": "This classic hotel is fully-refurbished...",
  "Rating": 3.6,
  "DescriptionVector": [
    -0.04886505,
    -0.02030743,
    0.01763356,
    ...
    // 1536 dimensions total
  ]
}

Najważniejsze kwestie dotyczące przechowywania osadzania:

  • Tablice wektorowe są przechowywane jako standardowe tablice JSON w dokumentach
  • Zasady wektorów definiują ścieżkę (), typ danych (/DescriptionVectorfloat32), wymiary (1536) i funkcję odległości (cosinus)
  • Zasady indeksowania tworzą indeks wektorowy w polu wektora w celu wydajnego wyszukiwania podobieństwa
  • Pole wektorowe powinno zostać wykluczone ze standardowego indeksowania w celu zoptymalizowania wydajności wstawiania

Te zasady są definiowane w szablonach Bicep dla metryk odległości dla tego przykładowego projektu. Aby uzyskać więcej informacji na temat polityk wektorowych i indeksowania, zobacz Wyszukiwanie wektorowe w Azure Cosmos DB.

Utwórz dwa pliki źródłowe Java w katalogu src/main/java/com/example/cosmos/vectorsearch:

touch src/main/java/com/example/cosmos/vectorsearch/VectorSearch.java
touch src/main/java/com/example/cosmos/vectorsearch/Utils.java

Wklej następujący kod do VectorSearch.java pliku.

package com.example.cosmos.vectorsearch;

import com.azure.ai.openai.OpenAIClient;
import com.azure.ai.openai.models.EmbeddingItem;
import com.azure.ai.openai.models.EmbeddingsOptions;
import com.azure.cosmos.CosmosClient;
import com.azure.cosmos.CosmosContainer;
import com.azure.cosmos.models.CosmosQueryRequestOptions;
import com.azure.cosmos.models.SqlParameter;
import com.azure.cosmos.models.SqlQuerySpec;

import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;

/**
 * Azure Cosmos DB NoSQL vector search sample — Java port of nosql-vector-search-typescript.
 *
 * Demonstrates:
 * - Passwordless authentication with DefaultAzureCredential
 * - Bulk insert of hotel data with pre-computed embeddings
 * - Vector similarity search using VectorDistance() SQL function
 * - DiskANN and QuantizedFlat algorithm selection via environment variable
 */
public final class VectorSearch {

    private static final String SAMPLE_QUERY =
            "quintessential lodging near running trails, eateries, retail";

    private static final Set<String> VALID_ALGORITHMS = Set.of("diskann", "quantizedflat");

    private static final Map<String, String> ALGORITHM_CONTAINERS = Map.of(
            "diskann", "hotels_diskann",
            "quantizedflat", "hotels_quantizedflat"
    );

    private static final Map<String, String> ALGORITHM_DISPLAY = Map.of(
            "diskann", "DiskANN",
            "quantizedflat", "QuantizedFlat"
    );

    public static void main(String[] args) {
        try {
            new VectorSearch().run();
        } catch (Exception e) {
            System.err.println("App failed: " + e.getMessage());
            e.printStackTrace();
            System.exit(1);
        }
        System.exit(0);
    }

    private void run() throws Exception {
        // ── Configuration ───────────────────────────────────────────────
        var algorithm = Utils.envOrDefault("VECTOR_ALGORITHM", "diskann").trim().toLowerCase();
        var dbName = Utils.envOrDefault("AZURE_COSMOSDB_DATABASENAME", "Hotels");
        var dataFile = Utils.requireEnv("DATA_FILE_WITH_VECTORS");
        var embeddedField = Utils.requireEnv("EMBEDDED_FIELD");
        var deployment = Utils.requireEnv("AZURE_OPENAI_EMBEDDING_MODEL");
        var distanceFunction = Utils.envOrDefault("VECTOR_DISTANCE_FUNCTION", "cosine");

        if (!VALID_ALGORITHMS.contains(algorithm)) {
            throw new IllegalArgumentException(
                    "Invalid algorithm '" + algorithm + "'. Must be one of: " +
                    String.join(", ", VALID_ALGORITHMS));
        }

        var containerName = ALGORITHM_CONTAINERS.get(algorithm);
        var algorithmDisplay = ALGORITHM_DISPLAY.get(algorithm);

        // ── Clients ─────────────────────────────────────────────────────
        OpenAIClient aiClient = Utils.createOpenAIClient();
        CosmosClient dbClient = Utils.createCosmosClient();

        try {
            var database = dbClient.getDatabase(dbName);
            System.out.println("Connected to database: " + dbName);

            CosmosContainer container = database.getContainer(containerName);
            System.out.println("Connected to container: " + containerName);
            System.out.println("\n[Algorithm] Vector Search Algorithm: " + algorithmDisplay);
            System.out.println("[Distance]  Distance Function: " + distanceFunction);

            // Verify container exists
            container.read();

            // ── Load & Insert Data ──────────────────────────────────────
            var dataPath = Path.of(dataFile);
            var data = Utils.readJsonFile(dataPath);
            Utils.insertData(container, data);

            // ── Generate Query Embedding ────────────────────────────────
            var embeddingOptions = new EmbeddingsOptions(List.of(SAMPLE_QUERY));
            var embeddingResult = aiClient.getEmbeddings(deployment, embeddingOptions);

            List<Float> embedding = embeddingResult.getData().get(0).getEmbedding();

            // Convert Float list to List<Double> for Cosmos DB parameter binding
            var embeddingDoubles = new ArrayList<Double>(embedding.size());
            for (var f : embedding) {
                embeddingDoubles.add(f.doubleValue());
            }

            // ── Build & Execute Vector Search Query ─────────────────────
            var safeField = Utils.validateFieldName(embeddedField);
            var queryText = "SELECT TOP 5 c.HotelName, c.Description, c.Rating, " +
                    "VectorDistance(c." + safeField + ", @embedding) AS SimilarityScore " +
                    "FROM c " +
                    "ORDER BY VectorDistance(c." + safeField + ", @embedding)";

            System.out.println("\n--- Executing Vector Search Query ---");
            System.out.println("Query: " + queryText);
            System.out.println("Parameters: @embedding (vector with " + embeddingDoubles.size() + " dimensions)");
            System.out.println("--------------------------------------\n");

            var sqlQuery = new SqlQuerySpec(
                    queryText,
                    List.of(new SqlParameter("@embedding", embeddingDoubles))
            );

            var queryOptions = new CosmosQueryRequestOptions();

            @SuppressWarnings("unchecked")
            var resultPages = container.queryItems(sqlQuery, queryOptions, Map.class);

            var results = new ArrayList<Map<String, Object>>();
            var requestCharge = 0.0;

            for (var page : resultPages.iterableByPage()) {
                requestCharge += page.getRequestCharge();
                for (var item : page.getResults()) {
                    @SuppressWarnings("unchecked")
                    var typedItem = (Map<String, Object>) item;
                    results.add(typedItem);
                }
            }

            Utils.printSearchResults(results, requestCharge);

        } finally {
            dbClient.close();
        }
    }
}

Ten kod:

  • Konfiguruje algorytm wektora DiskANN lub quantizedFlat z zmiennej środowiskowej VECTOR_ALGORITHM .
  • Nawiązuje połączenie z Azure OpenAI i Azure Cosmos DB poprzez uwierzytelnianie bezhasłowe.
  • Ładuje wstępnie wektoryzowane dane hotelowe z pliku JSON.
  • Wstawia dane do odpowiedniego kontenera.
  • Generuje osadzanie dla zapytania w języku naturalnym (quintessential lodging near running trails, eateries, retail).
  • Wykonuje zapytanie SQL, VectorDistance aby pobrać 5 najbardziej semantycznie podobnych hoteli sklasyfikowanych według wyniku podobieństwa.
  • Obsługuje błędy brakujących klientów, wybór nieprawidłowego algorytmu i nieistniejące kontenery/bazy danych.

Omówienie kodu: Generowanie osadzania za pomocą Azure OpenAI

Kod tworzy osadzanie dla tekstu zapytania:

EmbeddingsOptions options = new EmbeddingsOptions(
    List.of(queryText) // Array of description strings to embed
);
Embeddings embeddings = openAIClient.getEmbeddings(model, options);
List<Float> queryVector = embeddings.getData().get(0).getEmbedding();

To wywołanie Azure OpenAI SDK konwertuje tekst, taki jak "kwintesencjonalne zakwaterowanie w pobliżu tras biegowych", na wektor o wymiarze 1536, który oddaje jego znaczenie semantyczne. Aby uzyskać więcej informacji na temat generowania wektorów osadzających, zobacz dokumentację wektorów osadzających Azure OpenAI.

Opis kodu: Przechowywanie wektorów w Azure Cosmos DB

Wszystkie dokumenty z tablicami wektorowymi są wstawiane na dużą skalę przy użyciu executeBulkOperations metody w pliku Utils.insertData(). Każdy dokument jest mapowany na zbiorczą operację tworzenia przy użyciu PartitionKeyBuilder dla wartości klucza partycji każdego dokumentu. Narzędzie śledzi wstawione, pominięte i nieudane liczby wraz z całkowitym użyciem jednostek RU.

Spowoduje to wstawienie dokumentów hotelowych, w tym wstępnie wygenerowanych DescriptionVector tablic do kontenera. Możesz bezpiecznie przekazać wszystkie dane dokumentu, a biblioteka klienta obsługuje przetwarzanie wsadowe oraz ponowne próby.

Kod wykonuje wyszukiwanie wektorów przy użyciu VectorDistance funkcji :

String queryText = String.format(
    "SELECT TOP 5 c.HotelName, c.Description, c.Rating, " +
    "VectorDistance(c.%s, @embedding) AS SimilarityScore " +
    "FROM c ORDER BY VectorDistance(c.%s, @embedding)",
    embeddedField, embeddedField
);

SqlQuerySpec querySpec = new SqlQuerySpec(queryText,
    new SqlParameter("@embedding", queryVector));

CosmosPagedIterable<ObjectNode> results = container.queryItems(
    querySpec, new CosmosQueryRequestOptions(), ObjectNode.class);

Ten kod tworzy sparametryzowane zapytanie SQL, które używa funkcji VectorDistance do porównywania wektora osadzania zapytania (@embedding) względem pola wektora składowanego każdego dokumentu (DescriptionVector), zwracając 5 najlepszych hoteli z ich nazwą i wynikiem podobieństwa, uporządkowanym z najbardziej podobnych do najmniej podobnych. Osadzenie zapytania jest przekazywane jako parametr, aby uniknąć injekcji i pochodzi z wcześniejszego wywołania osadzania Azure OpenAI.

Co zwraca to zapytanie:

  • 5 najbardziej podobnych hoteli w oparciu o odległość wektora
  • Właściwości hoteli: HotelName, Description, Rating
  • SimilarityScore: wartość liczbowa wskazująca, jak podobny jest każdy hotel do zapytania
  • Wyniki uporządkowane z najbardziej podobnych do najmniej podobnych

Aby uzyskać więcej informacji na VectorDistance temat funkcji, zobacz dokumentację vectorDistance.

Tworzenie funkcji narzędziowych

Wklej następujący kod do Utils.javapliku :

package com.example.cosmos.vectorsearch;

import com.azure.ai.openai.OpenAIClientBuilder;
import com.azure.ai.openai.OpenAIClient;
import com.azure.cosmos.CosmosClient;
import com.azure.cosmos.CosmosClientBuilder;
import com.azure.cosmos.CosmosContainer;
import com.azure.cosmos.models.CosmosBulkOperations;
import com.azure.cosmos.models.CosmosItemOperation;
import com.azure.cosmos.models.PartitionKey;
import com.azure.cosmos.models.PartitionKeyBuilder;
import com.azure.identity.DefaultAzureCredentialBuilder;

import tools.jackson.databind.json.JsonMapper;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * Shared utilities for Azure Cosmos DB NoSQL vector search sample.
 * Provides authentication, bulk insert, field validation, and result formatting.
 */
public final class Utils {

    private static final JsonMapper JSON_MAPPER = JsonMapper.builder().build();

    private Utils() {
        // utility class
    }

    // ── Authentication ──────────────────────────────────────────────────

    /**
     * Create an Azure OpenAI client using DefaultAzureCredential (passwordless).
     */
    public static OpenAIClient createOpenAIClient() {
        var endpoint = requireEnv("AZURE_OPENAI_EMBEDDING_ENDPOINT");
        var credential = new DefaultAzureCredentialBuilder().build();
        return new OpenAIClientBuilder()
                .endpoint(endpoint)
                .credential(credential)
                .buildClient();
    }

    /**
     * Create a Cosmos DB client using DefaultAzureCredential (passwordless).
     */
    public static CosmosClient createCosmosClient() {
        var endpoint = requireEnv("AZURE_COSMOSDB_ENDPOINT");
        var credential = new DefaultAzureCredentialBuilder().build();
        return new CosmosClientBuilder()
                .endpoint(endpoint)
                .credential(credential)
                .buildClient();
    }

    // ── Data Loading ────────────────────────────────────────────────────

    /**
     * Read a JSON array file and return its contents as a list of maps.
     */
    @SuppressWarnings("unchecked")
    public static List<Map<String, Object>> readJsonFile(Path filePath) throws IOException {
        System.out.println("Reading JSON file from " + filePath);
        var bytes = Files.readAllBytes(filePath);
        return JSON_MAPPER.readValue(bytes, List.class);
    }

    // ── Bulk Insert ─────────────────────────────────────────────────────

    /**
     * Insert documents into a Cosmos DB container using bulk operations.
     * Skips insert if the container already contains data.
     *
     * @return summary with counts and RU charge
     */
    public static BulkInsertResult insertData(CosmosContainer container,
                                               List<Map<String, Object>> data) {
        // Check existing document count
        var existingCount = getDocumentCount(container);
        if (existingCount > 0) {
            System.out.println("Container already has " + existingCount + " documents. Skipping insert.");
            return new BulkInsertResult(0, 0, 0, (int) existingCount, 0.0);
        }

        System.out.println("Inserting " + data.size() + " items using bulk operations...");

        // Build bulk create operations
        var operations = new ArrayList<CosmosItemOperation>();
        for (var item : data) {
            // Cosmos DB requires an "id" field — map HotelId to id
            var doc = new java.util.HashMap<>(item);
            var hotelId = String.valueOf(doc.get("HotelId"));
            doc.put("id", hotelId);
            operations.add(CosmosBulkOperations.getCreateItemOperation(doc,
                new PartitionKeyBuilder().add(hotelId).build()));
        }

        var inserted = 0;
        var failed = 0;
        var skipped = 0;
        var totalRUs = 0.0;

        var startTime = System.currentTimeMillis();
        System.out.println("Starting bulk insert (" + operations.size() + " items)...");

        var responses = container.executeBulkOperations(operations);
        for (var response : responses) {
            var statusCode = response.getResponse().getStatusCode();
            totalRUs += response.getResponse().getRequestCharge();

            if (statusCode >= 200 && statusCode < 300) {
                inserted++;
            } else if (statusCode == 409) {
                skipped++;
            } else {
                failed++;
            }
        }

        var durationSec = (System.currentTimeMillis() - startTime) / 1000.0;
        System.out.printf("Bulk insert completed in %.2fs%n", durationSec);
        System.out.printf("%nInsert Request Charge: %.2f RUs%n%n", totalRUs);

        return new BulkInsertResult(data.size(), inserted, failed, skipped, totalRUs);
    }

    private static long getDocumentCount(CosmosContainer container) {
        var result = container.queryItems(
                "SELECT VALUE COUNT(1) FROM c",
                new com.azure.cosmos.models.CosmosQueryRequestOptions(),
                Long.class
        );
        for (var count : result) {
            return count;
        }
        return 0;
    }

    // ── Field Name Validation ───────────────────────────────────────────

    /**
     * Validates a field name to prevent NoSQL injection when building queries
     * with string interpolation.
     *
     * @param fieldName the field name to validate
     * @return the validated field name
     * @throws IllegalArgumentException if the field name contains unsafe characters
     */
    public static String validateFieldName(String fieldName) {
        if (!fieldName.matches("^[A-Za-z_][A-Za-z0-9_]*$")) {
            throw new IllegalArgumentException(
                    "Invalid field name: \"" + fieldName + "\". " +
                    "Field names must start with a letter or underscore " +
                    "and contain only letters, numbers, and underscores.");
        }
        return fieldName;
    }

    // ── Output Formatting ───────────────────────────────────────────────

    /**
     * Print search results in a consistent tabular format.
     */
    public static void printSearchResults(List<Map<String, Object>> results, double requestCharge) {
        System.out.println("\n--- Search Results ---");

        if (results == null || results.isEmpty()) {
            System.out.println("No results found.");
            return;
        }

        for (var i = 0; i < results.size(); i++) {
            var r = results.get(i);
            var name = r.get("HotelName");
            var score = r.get("SimilarityScore");
            System.out.printf("%d. %s, Score: %.4f%n", i + 1, name, ((Number) score).doubleValue());
        }

        System.out.printf("%nVector Search Request Charge: %.2f RUs%n%n", requestCharge);
    }

    // ── Environment Helpers ─────────────────────────────────────────────

    public static String requireEnv(String key) {
        var value = System.getenv(key);
        if (value == null || value.isBlank()) {
            throw new IllegalStateException("Required environment variable not set: " + key);
        }
        return value;
    }

    public static String envOrDefault(String key, String defaultValue) {
        var value = System.getenv(key);
        return (value != null && !value.isBlank()) ? value : defaultValue;
    }

    // ── Result Record ───────────────────────────────────────────────────

    public record BulkInsertResult(int total, int inserted, int failed, int skipped, double requestCharge) {}
}

Ta klasa narzędzi udostępnia następujące kluczowe funkcje:

  • createOpenAIClient / createCosmosClient: Tworzenie klientów dla Azure OpenAI i Azure Cosmos DB przy użyciu uwierzytelniania bez hasła za pośrednictwem opcji DefaultAzureCredential. Włącz kontrolę dostępu opartą na rolach dla obu zasobów i zaloguj się do Azure CLI
  • insertData: Wstawia dane w partiach do kontenera Azure Cosmos DB przy użyciu operacji zbiorczych i śledzi liczby wstawionych, pominiętych i nieudanych operacji wraz z całkowitym użyciem jednostek RU.
  • printSearchResults: Wyświetla wyniki wyszukiwania wektorowego, w tym wynik i nazwę hotelu
  • validateFieldName: Sprawdza, czy nazwa pola istnieje w danych, aby zapobiec iniekcji

Uwierzytelnianie przy użyciu Azure CLI

Zaloguj się do Azure CLI przed uruchomieniem aplikacji, aby aplikacja mogła bezpiecznie uzyskiwać dostęp do Azure zasobów.

az login

Kod używa lokalnego uwierzytelniania dewelopera do uzyskiwania dostępu do Azure Cosmos DB i Azure OpenAI za pomocą createOpenAIClient i createCosmosClient z Utils.java. Te funkcje bazują na DefaultAzureCredential z azure-identity który prowadzi uporządkowany łańcuch dostawców poświadczeń i rozpoznaje Azure CLI poświadczenia na potrzeby programowania lokalnego. Dowiedz się więcej o tym, jak uwierzytelniać aplikacje Java do usług Azure przy użyciu biblioteki Azure Identity.

Kompilowanie i uruchamianie aplikacji

Skompiluj i uruchom aplikację za pomocą narzędzia Maven:

Linux/macOS:

VECTOR_ALGORITHM=diskann mvn compile exec:java

Windows:

set VECTOR_ALGORITHM=diskann && mvn compile exec:java

Rejestrowanie i dane wyjściowe aplikacji pokazują:

  • Stan wstawiania danych
  • Tworzenie indeksu wektorowego
  • Wyniki wyszukiwania z nazwami hoteli i wynikami podobieństwa
Connected to database: Hotels
Connected to container: hotels_diskann

📊 Vector Search Algorithm: DiskANN
📏 Distance Function: cosine
Reading JSON file from ../data/HotelsData_toCosmosDB_Vector.json
Inserting 50 items using bulk operations...
Starting bulk insert (50 items)...
Bulk insert completed in 3.41s

Insert Request Charge: 6805.25 RUs


--- Executing Vector Search Query ---
Query: SELECT TOP 5 c.HotelName, c.Description, c.Rating, VectorDistance(c.DescriptionVector, @embedding) AS SimilarityScore FROM c ORDER BY VectorDistance(c.DescriptionVector, @embedding)
Parameters: @embedding (vector with 1536 dimensions)
--------------------------------------


--- Search Results ---
1. Royal Cottage Resort, Score: 0.4991
2. Country Comfort Inn, Score: 0.4786
3. Nordick's Valley Motel, Score: 0.4635
4. Economy Universe Motel, Score: 0.4461
5. Roach Motel, Score: 0.4388

Vector Search Request Charge: 5.33 RUs

Metryki odległości

Azure Cosmos DB obsługuje trzy funkcje odległości dla podobieństwa wektorów:

Funkcja odległości Zakres wyników Interpretacja Najlepsze dla
Cosinus (ustawienie domyślne) Od 0.0 do 1.0 Wyższe wyniki (bliżej 1,0) wskazują na większe podobieństwo Ogólne podobieństwo tekstu, osadzenia Azure OpenAI (używane w tym szybkim starcie)
Euklidesan (L2) Od 0,0 do ∞ Dolna = bardziej podobna Dane przestrzenne, gdy wielkość ma znaczenie
Kropka produktu -∞ do +∞ Wyższe = bardziej podobne Gdy wielkości wektorów są znormalizowane

Funkcja distance jest ustawiana w zasadach osadzania wektorów podczas tworzenia kontenera. Jest to dostępne w infrastrukturze w przykładowym repozytorium. Jest on definiowany jako część definicji kontenera.

{
    name: 'hotels_diskann'
    partitionKeyPaths: [
        '/HotelId'
    ]
    indexingPolicy: {
        indexingMode: 'consistent'
        automatic: true
        includedPaths: [
        {
            path: '/*'
        }
        ]
        excludedPaths: [
        {
            path: '/_etag/?'
        }
        {
            path: '/DescriptionVector/*'
        }
        ]
        vectorIndexes: [
        {
            path: '/DescriptionVector'
            type: 'diskANN'
        }
        ]
    }
    vectorEmbeddingPolicy: {
        vectorEmbeddings: [
        {
            path: '/DescriptionVector'
            dataType: 'float32'
            dimensions: 1536
            distanceFunction: 'cosine'
        }
        ]
    }
}

Ten kod Bicep definiuje konfigurację kontenera Azure Cosmos DB do przechowywania dokumentów hotelowych z funkcjami wyszukiwania wektorowego.

Majątek Opis
partitionKeyPaths Partycjonuje dokumenty z użyciem HotelId dla rozproszonego przechowywania.
indexingPolicy Konfiguruje automatyczne indeksowanie wszystkich właściwości dokumentu (/*) oprócz pola systemowego _etag i tablicy DescriptionVector w celu zoptymalizowania wydajności zapisu. Pola wektorowe nie wymagają indeksowania standardowego, ponieważ zamiast tego używają wyspecjalizowanej vectorIndexes konfiguracji.
vectorIndexes Tworzy indeks DiskANN lub quantizedFlat na /DescriptionVector ścieżce w celu efektywnego wyszukiwania podobieństwa.
vectorEmbeddingPolicy Definiuje cechy pola wektorowego: float32 typ danych o wymiarach 1536 (pasujących text-embedding-3-small do danych wyjściowych modelu) i cosinus jako funkcja odległości do mierzenia podobieństwa między wektorami podczas zapytań.

Interpretowanie wyników podobieństwa

W przykładowych wynikach przy użyciu podobieństwa cosinus:

  • 0.4991 (Royal Cottage Resort) - Najwyższa podobieństwo, najlepsze dopasowanie do "zakwaterowania w pobliżu tras biegowych, restauracji, handlu detalicznego"
  • 0.4388 (Roach Motel) - Niższe podobieństwo, nadal istotne, ale mniej zgodne
  • Wyniki bliżej 1,0 wskazują na silniejsze podobieństwo semantyczne
  • Wyniki zbliżone do 0 wskazują na niewielkie podobieństwo

Ważna

  • Wartości wyników bezwzględnych zależą od modelu osadzania i danych
  • Skup się na względnym rankingu , a nie na progach bezwzględnych
  • Embeddingi Azure OpenAI najlepiej współpracują z podobieństwem cosinusowym.

Aby uzyskać szczegółowe informacje na temat funkcji odległości, zobacz Co to są funkcje odległości?

Wyświetlanie danych i zarządzanie nimi w Visual Studio Code

  1. Wybierz rozszerzenie Cosmos DB w Visual Studio Code, aby nawiązać połączenie z kontem Azure Cosmos DB.

  2. Wyświetl dane i indeksy w bazie danych Hotels.

    Zrzut ekranu przedstawiający rozszerzenie Azure Cosmos DB w Visual Studio Code z elementami bazy danych Hotels i edytorem dokumentów JSON.

Uprzątnij zasoby

Jeśli nie potrzebujesz już interfejsu API dla konta NoSQL, możesz usunąć odpowiednią grupę zasobów.

  1. Przejdź do grupy zasobów utworzonej wcześniej w portalu Azure.

    Wskazówka

    W tym przewodniku Szybki start zalecamy nazwę msdocs-cosmos-quickstart-rg.

  2. Wybierz pozycję Usuń grupę zasobów.

    Zrzut ekranu przedstawiający opcję Usuń grupę zasobów na pasku nawigacyjnym dla grupy zasobów.

  3. W oknie dialogowym Czy na pewno chcesz usunąć , wprowadź nazwę grupy zasobów, a następnie wybierz pozycję Usuń.

    Zrzut ekranu przedstawiający stronę potwierdzenia usuwania dla grupy zasobów.