Menu Docs
Página inicial do Docs
/
Atlas
/

Quantização vetorial

O Atlas Vector Search suporta a quantização automática de suas incorporações vetoriais de ponto flutuante (tanto de 32bits quanto de 64bit). Ele também oferece suporte à ingestão e indexação de seus vetores escalares e binários pré-quantizados de certos modelos de incorporação.

Quantização é o processo de reduzir vetores de fidelidade total em menos bits. Ela reduz a quantidade de memória principal necessária para armazenar cada vetor em um índice do Atlas Vector Search indexando os vetores de representação reduzida. Isso permite o armazenamento de mais vetores ou vetores com dimensões superiores. Portanto, a quantização reduz o consumo de recursos e melhora a velocidade. Recomendamos a quantização para aplicativos com um grande número de vetores, como acima de 100,000.

A quantização escalar envolve primeiro identificar os valores mínimo e máximo para cada dimensão dos vetores indexados para estabelecer uma faixa de valores para uma dimensão. Em seguida, o intervalo é dividido em intervalos ou compartimentos de tamanhos iguais. Finalmente, cada valor de flutuação é mapeado para um compartimento para converter os valores de flutuação contínuos em inteiros discretos. No Atlas Vector Search, esta quantização reduz o custo de RAM do vetor de incorporação para cerca de um quarto ()1/3.75 do custo pré-quantização.

A quantização binária envolve assumir um ponto médio de 0 para cada dimensão, o que normalmente é apropriado para incorporações normalizadas para comprimento 1, como o text-embedding-3-large da OpenAI. Em seguida, cada valor no vetor é comparado ao ponto médio e recebe um valor binário de 1 se for maior que o ponto médio e um valor binário de 0 se for menor ou igual ao ponto médio. No Atlas Vector Search, esta quantização reduz o custo de RAM da incorporação do vetor para um vigésimo quarto (1/24) do custo pré-quantização. O motivo pelo qual não 1/32 é é porque a estrutura de dados que contém o gráfico Hierarchical Navigable Small Worlds em si, separada dos valores vetoriais, não é compactada.

Quando você executa uma query, o Atlas Vector Search converte o valor de ponto flutuante no vetor de query em um vetor binário usando o mesmo ponto médio para uma comparação eficiente entre o vetor de query e os vetores binários indexados. Em seguida, ele reavalia os candidatos identificados na comparação binária usando os valores de ponto flutuante originais associados a esses resultados do índice binário para refinar ainda mais os resultados. Os vetores de fidelidade total são armazenados em sua própria estrutura de dados no disco e são referenciados apenas durante o rescoring quando você configura a quantização binária ou realiza uma pesquisa exata em vetores quantizados binários ou escalares.

Dica

A tabela a seguir apresenta os requisitos para a quantização automática e ingestão de vetores quantizados.

Observação

O Atlas armazena todos os valores de ponto flutuante internamente como o tipo de dados double; portanto, as incorporações de 32bits e 64bits são compatíveis com a quantização automática sem conversão.

Requerimento
Para int1 ingestão
Para int8 ingestão
Para Quantização escalar automática
Para Quantização Binária Automática

Exige configurações de definição de índice

No

No

Sim

Sim

Requer formatoBSON binData

Sim

Sim

No

No

Armazenamento no mongod

binData(int1)

binData(int8)

binData(float32)
array(double)
binData(float32)
array(double)

Método de similaridade suportado

euclidean

cosine
euclidean
dotProduct
cosine
euclidean
dotProduct
cosine
euclidean
dotProduct

Número de dimensões suportadas

Múltiplo de 8

1 a 8192

1 a 8192

1 a 8192

Oferece suporte às pesquisas ANN e ENN

Sim

Sim

Sim

Sim

Você pode configurar o Atlas Vector Search para quantizar automaticamente incorporações vetoriais de ponto flutuante na sua coleção para tipos de representação reduzidos, como int8 (escalar) e binary nos seus índices vetoriais.

Para configurar ou alterar o tipo de quantização, especifique um valor de campo quantization de scalar ou binary em sua definição de índice. Isso aciona uma reconstrução de índice semelhante a qualquer outra alteração de definição de índice. O tipo de quantização especificado se aplica a todos os vetores indexados e vetores de consulta no momento da consulta. Você não precisa alterar sua query, pois seus vetores de query são quantizados automaticamente.

Para a maioria dos modelos de incorporação, recomendamos a quantização binária com repontuação. Se você quiser usar modelos de dimensão inferior que não sejam QAT, use a quantização escalar porque ela tem menos perda de representação e, portanto, incorre em menos perda de capacidade de representação.

O Atlas Vector Search oferece capacidades nativas para quantização escalar e quantização binária com reavaliação. A quantização automática aumenta a escalabilidade e a economia de custos para seus aplicativos, reduzindo os recursos computacionais para o processamento eficiente de seus vetores. A quantização automática reduz a RAM para mongot em 3,75x para escalar e em 24x para binário; os valores vetoriais diminuem em 4x e 32x respectivamente, mas o grafo de Mundos Pequenos Navegáveis Hierárquicos em si não encolhe. Isso melhora o desempenho, mesmo nos volumes e escalas mais altos.

Recomendamos a quantização automática se você tiver um grande número de vetores de fidelidade total, normalmente mais de 100,000 vetores. Após a quantização, você indexa vetores de representação reduzida sem comprometer a precisão ao recuperar vetores.

Para habilitar a quantização automática:

1

Em um índice novo ou existente do Atlas Vector Search , especifique um dos seguintes tipos de quantização no fields.quantization campo para sua definição de índice:

  • scalar: para produzir vetores de bytes a partir de vetores de entrada de ponto flutuante.

  • binary: para gerar vetores de bits a partir de vetores de entrada em ponto flutuante.

Se você especificar quantização automática em dados que não sejam um array de valores de ponto flutuante, o Atlas Vector Search ignora silenciosamente esse vetor em vez de indexá-lo, e esses vetores serão ignorados. Como o Atlas armazena valores de ponto flutuante (tanto de 32 bits quanto de 64 bits) como o tipo double internamente, embeddings de modelos que geram qualquer uma dessas precisões funcionarão com a quantização automática.

2

O índice deve levar cerca de um minuto para ser criado. Enquanto ele é compilado, o índice está em um estado de sincronização inicial. Quando a construção estiver concluída, você poderá começar a fazer query nos dados em sua coleção.

O tipo de quantização especificado aplica-se a todos os vetores indexados e vetores de consulta no momento da consulta.

Quando você visualiza seu índice quantizado na UI do Atlas, o tamanho do índice pode parecer maior do que um índice sem quantização. Isso ocorre porque a métrica Size representa o total de dados armazenados, que inclui o gráfico Hierarchical Navigable Small Worlds (na memória), os vetores quantizados (na memória) e os vetores de fidelidade total (no disco). Para estimar a quantidade de memória usada pelo índice no momento da query, consulte a métrica Required Memory.

O Atlas Vector Search também oferece suporte à ingestão e indexação de vetores quantizados escalares e binários de certos modelos de incorporação. Caso você ainda não possua vetores quantizados, é possível converter suas incorporações em vetores BSON BinData com subtipo float32, int1 ou int8.

Recomendamos ingerir vetores BSON binData quantizados para os seguintes casos de uso:

  • Você precisa indexar a saída do vetor quantizado dos modelos de incorporação.

  • Você tem um grande número de vetores flutuantes e deseja reduzir o armazenamento e o volume do WiredTiger (como uso de disco e memória) no mongod.

BinData é um tipo de dado BSON que armazena dados binários. Ele comprime suas incorporações vetoriais e requer cerca de três vezes menos espaço em disco no seu cluster em comparação a incorporações que usam um array float32 padrão. Para aprender mais, consulte Compactação Vetorial.

Esse subtipo também permite indexar seus vetores com tipos alternativos, como vetores int1 ou int8, reduzindo a memória necessária para construir o índice Atlas Vector Search para sua coleção. Ele reduz a RAM para mongot em 3,75x para escalar e em 24x para binário; os valores do vetor diminuem em 4x e 32x, respectivamente, mas o gráfico Hierarchical Navigable Small Worlds em si não diminui.

Se você ainda não tiver vetores binData, poderá converter suas inserções para esse formato usando qualquer driver compatível antes de gravar seus dados em uma coleção. O procedimento a seguir orienta você nas etapas para converter suas incorporações nos vetores BinData com subtipos float32, int8 e int1.

BSON Vetores BinData com subtipos float32, int1 e int8 são suportados pelos seguintes drivers:


➤ Use o menu suspenso Selecione sua linguagem para definir o idioma do procedimento nesta página.


Para quantizar seus vetores BSON binData, você deve ter o seguinte:

  • Um cluster do Atlas executando o MongoDB versão 6.0.11, 7.0.2, ou posterior.

    Certifique-se de que seu endereço IP esteja incluído na lista de acessodo seu projeto Atlas.

  • Acesso a um modelo de incorporação que suporta saída de vetor de bytes.

    As saídas dos modelos de incorporação a seguir podem ser usadas para gerar vetores BSON binData com um driver MongoDB compatível.

    Provedor de modelo de incorporação
    Modelo de incorporação

    voyage-3-large

    embed-english-v3.0

    nomic-embed-text-v1.5

    jina-embeddings-v2-base-en

    mxbai-embed-large-v1

    A quantização escalar preserva a recuperação para esses modelos porque esses modelos são todos treinamentos para reconhecer a quantização. Portanto, a degradação da recuperação para incorporações quantizadas escalares produzidas por esses modelos é mínima, mesmo em dimensões mais inferiores,384 como.

  • Um terminal e editor de código para executar seu projeto Go.

  • Go instalado.

  • Java Development Kit (JDK) versão 8 ou posterior.

  • Um ambiente para configurar e executar um aplicação Java . Recomendamos que você use um ambiente de desenvolvimento integrado (IDE) como IntelliJ IDEA ou Eclipse IDE para configurar Maven ou Gradle para construir e executar seu projeto.

  • Um editor de terminal e código para executar seu projeto Node.js.

  • npm e Node.js instalado.

  • Um ambiente para executar notebooks Python interativos, como o VS Code ou Colab.

Os exemplos neste procedimento usam dados novos ou dados existentes e incorporações gerados usando o modelo da Voyage voyage-3-large AI. O exemplo para novos dados utiliza strings de texto de exemplo, que você pode substituir por seus próprios dados. O exemplo de dados existentes usa um subconjunto de documentos sem nenhuma incorporação da listingsAndReviews coleção no sample_airbnb banco de dados , que você pode substituir por seu próprio banco de dados e coleção (com ou sem incorporações).

Selecione a guia com base no desejo de quantizar vetores binData para novos dados ou para dados que você já possui em seu cluster Atlas.

1

Em uma janela de terminal, execute os seguintes comandos para criar um novo diretório chamado ingest-binary-vectors e inicializar seu projeto:

mkdir ingest-binary-vectors-project
cd ingest-binary-vectors-project
go mod init ingest-binary-vectors-project
2

Execute o comando a seguir para instalar o driver Go do MongoDB. Esta operação pode levar alguns minutos para ser concluída.

go get go.mongodb.org/mongo-driver/v2/mongo

Você deve instalar 2.1 o driver Go v ou posterior. Se necessário, você também pode instalar bibliotecas do fornecedor do modelo de incorporação. Para exemplos neste tutorial, usaremos a API REST da Voyage AI para gerar incorporações. Portanto, você não precisa instalar nenhuma biblioteca adicional.

3
  1. Para acessar o provedor de modelo de incorporação para gerar e converter incorporações, configure a variável de ambiente para a chave de API do provedor de modelo de incorporação, se necessário.

    Para utilizar incorporações da Voyage AI, configure a variável de ambiente do VOYAGE_API_KEY.

    export VOYAGE_API_KEY="<VOYAGE-API-KEY>"
  2. Para acessar o cluster Atlas, defina a variável de ambiente MONGODB_URI.

    export MONGODB_URI="<CONNECTION-STRING>"

    Sua string de conexão deve estar no seguinte formato:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
4

Você pode usar um fornecedor de modelo de incorporação para gerar incorporações do float32, int8 e int1 para seus dados e, em seguida, usar o driver MongoDB Go para converter sua incorporação de vetor nativo em vetores BSON. O código de exemplo a seguir usa a API embed do Cohere para gerar vetores de precisão total.

  1. Crie um novo arquivo chamado GenerateAndConvertEmbeddings.go em seu projeto Go.

    touch GenerateAndConvertEmbeddings.go
  2. Copie e cole o seguinte código no arquivo GenerateAndConvertEmbeddings.go.

    Este código faz o seguinte:

    • Gera as incorporações vetoriais float32, int8 e ubinary usando a API embed do Cohere.

    • Converte as incorporações em vetores BSON binData usando o driver MongoDB Go.

    • Cria um arquivo chamado embeddings.json e salva os dados com as incorporações no arquivo.

    GenerateAndConvertEmbeddings.go
    1package main
    2
    3import (
    4 "bytes"
    5 "context"
    6 "encoding/json"
    7 "fmt"
    8 "io/ioutil"
    9 "log"
    10 "net/http"
    11 "os"
    12
    13 "go.mongodb.org/mongo-driver/v2/bson"
    14)
    15
    16// Sample data for embedding
    17var data = []string{
    18 "The Great Wall of China is visible from space.",
    19 "The Eiffel Tower was completed in Paris in 1889.",
    20 "Mount Everest is the highest peak on Earth at 8,848m.",
    21 "Shakespeare wrote 37 plays and 154 sonnets during his lifetime.",
    22 "The Mona Lisa was painted by Leonardo da Vinci.",
    23}
    24
    25func main() {
    26 apiKey := os.Getenv("VOYAGE_API_KEY")
    27 if apiKey == "" {
    28 log.Fatal("Ensure VOYAGE_API_KEY is set.")
    29 }
    30
    31 model := "voyage-3-large"
    32
    33 // Generate embeddings for float, int8, and ubinary
    34 floatEmbeddings, err := fetchEmbeddingsFromVoyage(data, apiKey, model, "float")
    35 if err != nil {
    36 log.Fatalf("Error fetching float embeddings: %v", err)
    37 }
    38
    39 int8Embeddings, err := fetchEmbeddingsFromVoyage(data, apiKey, model, "int8")
    40 if err != nil {
    41 log.Fatalf("Error fetching int8 embeddings: %v", err)
    42 }
    43
    44 ubinaryEmbeddings, err := fetchEmbeddingsFromVoyage(data, apiKey, model, "ubinary")
    45 if err != nil {
    46 log.Fatalf("Error fetching ubinary embeddings: %v", err)
    47 }
    48
    49 // Convert to BSON and store in JSON file
    50 documents := convertEmbeddingsToBSON(data, floatEmbeddings, int8Embeddings, ubinaryEmbeddings)
    51
    52 err = writeJSONToFile("embeddings.json", documents)
    53 if err != nil {
    54 log.Fatalf("Error writing embeddings to file: %v", err)
    55 }
    56
    57 fmt.Println("Embeddings successfully stored in embeddings.json")
    58}
    59
    60// Fetch embeddings using Voyage AI REST API
    61func fetchEmbeddingsFromVoyage(texts []string, apiKey string, model string, outputDType string) ([]map[string]interface{}, error) {
    62 url := "https://api.voyageai.com/v1/embeddings"
    63
    64 // Prepare request body
    65 requestBody := map[string]interface{}{
    66 "input": texts,
    67 "model": model,
    68 "output_dtype": outputDType,
    69 "output_dimension": 1024,
    70 "input_type": "document",
    71 }
    72
    73 requestBytes, err := json.Marshal(requestBody)
    74 if err != nil {
    75 return nil, fmt.Errorf("failed to marshal request body: %w", err)
    76 }
    77
    78 req, err := http.NewRequestWithContext(context.TODO(), "POST", url, bytes.NewBuffer(requestBytes))
    79 if err != nil {
    80 return nil, fmt.Errorf("failed to create HTTP request: %w", err)
    81 }
    82
    83 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
    84 req.Header.Set("Content-Type", "application/json")
    85
    86 client := &http.Client{}
    87 resp, err := client.Do(req)
    88 if err != nil {
    89 return nil, fmt.Errorf("failed to make API request: %w", err)
    90 }
    91 defer resp.Body.Close()
    92
    93 if resp.StatusCode != http.StatusOK {
    94 body, _ := ioutil.ReadAll(resp.Body)
    95 return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body))
    96 }
    97
    98 var response struct {
    99 Data []map[string]interface{} `json:"data"`
    100 }
    101 if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
    102 return nil, fmt.Errorf("failed to parse API response: %w", err)
    103 }
    104
    105 return response.Data, nil
    106}
    107
    108// Convert embeddings to BSON binary vectors
    109func convertEmbeddingsToBSON(sentences []string, floatEmbeddings []map[string]interface{}, int8Embeddings []map[string]interface{}, ubinaryEmbeddings []map[string]interface{}) []bson.M {
    110 var documents []bson.M
    111
    112 for i, sentence := range sentences {
    113 floatEmbedding := convertInterfaceToFloat32(floatEmbeddings[i]["embedding"].([]interface{}))
    114 int8Embedding := convertInterfaceToInt8(int8Embeddings[i]["embedding"].([]interface{}))
    115 ubinaryEmbedding := convertInterfaceToBytes(ubinaryEmbeddings[i]["embedding"].([]interface{}))
    116
    117 floatVector := bson.NewVector(floatEmbedding)
    118 int8Vector := bson.NewVector(int8Embedding)
    119 ubinaryVector, err := bson.NewPackedBitVector(ubinaryEmbedding, 0)
    120 if err != nil {
    121 log.Fatalf("Error creating PackedBitVector: %v", err)
    122 }
    123
    124 document := bson.M{
    125 "text": sentence,
    126 "embeddings_float32": floatVector.Binary(),
    127 "embeddings_int8": int8Vector.Binary(),
    128 "embeddings_int1": ubinaryVector.Binary(),
    129 }
    130 documents = append(documents, document)
    131 }
    132
    133 return documents
    134}
    135
    136// Write JSON file from in-memory BSON documents
    137func writeJSONToFile(filename string, documents []bson.M) error {
    138 file, err := os.Create(filename)
    139 if err != nil {
    140 return fmt.Errorf("failed to create file: %w", err)
    141 }
    142 defer file.Close()
    143
    144 var jsonData []json.RawMessage
    145 for _, document := range documents {
    146 jsonBytes, err := bson.MarshalExtJSON(document, false, false)
    147 if err != nil {
    148 return fmt.Errorf("error marshaling BSON to JSON: %w", err)
    149 }
    150 jsonData = append(jsonData, jsonBytes)
    151 }
    152
    153 marshaledData, err := json.MarshalIndent(jsonData, "", " ")
    154 if err != nil {
    155 return fmt.Errorf("failed to marshal JSON: %w", err)
    156 }
    157
    158 _, err = file.Write(marshaledData)
    159 if err != nil {
    160 return fmt.Errorf("failed to write JSON to file: %w", err)
    161 }
    162
    163 return nil
    164}
    165
    166// Convert a slice of interfaces to a slice of float32
    167func convertInterfaceToFloat32(data []interface{}) []float32 {
    168 f32s := make([]float32, len(data))
    169 for i, v := range data {
    170 f32s[i] = float32(v.(float64))
    171 }
    172 return f32s
    173}
    174
    175// Convert a slice of interfaces to a slice of int8
    176func convertInterfaceToInt8(data []interface{}) []int8 {
    177 ints8 := make([]int8, len(data))
    178 for i, v := range data {
    179 switch val := v.(type) {
    180 case int:
    181 ints8[i] = int8(val)
    182 case float64:
    183 ints8[i] = int8(val)
    184 default:
    185 log.Fatalf("Unexpected type %T in int8 embedding at index %d", v, i)
    186 }
    187 }
    188 return ints8
    189}
    190
    191// Convert a slice of interfaces to a slice of bytes
    192func convertInterfaceToBytes(data []interface{}) []byte {
    193 bytes := make([]byte, len(data))
    194 for i, v := range data {
    195 switch val := v.(type) {
    196 case int:
    197 bytes[i] = byte(val)
    198 case float64:
    199 bytes[i] = byte(val)
    200 default:
    201 log.Fatalf("Unexpected type %T in ubinary embedding at index %d", v, i)
    202 }
    203 }
    204 return bytes
    205}
  3. Substitua o seguinte valor de espaço reservado no código e salve o arquivo.

    VOYAGE_API_KEY

    Sua chave de API da IA do Voyage somente se você não tiver definido a variável de ambiente.

  4. Execute o programa usando o seguinte comando.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    go run GenerateAndConvertEmbeddings.go
    Embeddings successfully stored in embeddings.json
  5. Verifique as incorporações no arquivo embeddings.json.

Para aprender mais sobre como gerar incorporações e convertê-las em vetores binData, veja Como criar incorporações vetoriais.

5

Você deve carregar seus dados e incorporações em uma coleção no cluster do Atlas e criar um índice Atlas Vector Search nos dados para executar queries $vectorSearch em relação aos dados.

  1. Crie um novo arquivo chamado UploadDataAndCreateIndex.go em seu projeto Go.

    touch UploadDataAndCreateIndex.go
  2. Copie e cole o seguinte código no arquivo UploadDataAndCreateIndex.go.

    Este código faz o seguinte:

    • Carrega as incorporações float32, int8 e int1 no arquivo embeddings.json para o seu cluster do Atlas.

    • Cria um índice do Atlas Vector Search nos campos embeddings.float32, embeddings.int8 e embeddings.int1.

    UploadDataAndCreateIndex.go
    1package main
    2
    3import (
    4 "context"
    5 "fmt"
    6 "io/ioutil"
    7 "log"
    8 "time"
    9 "os"
    10
    11 "go.mongodb.org/mongo-driver/v2/bson"
    12 "go.mongodb.org/mongo-driver/v2/mongo"
    13 "go.mongodb.org/mongo-driver/v2/mongo/options"
    14)
    15
    16var (
    17 mongodbURI = os.Getenv("MONGODB_URI")
    18 dbName = "<DATABASE-NAME>"
    19 collectionName = "<COLLECTION-NAME>"
    20 indexName = "<INDEX-NAME>"
    21 numberOfDimensions = 1024
    22 embeddingFields = []string{"embeddings_float32", "embeddings_int8", "embeddings_int1"}
    23 embeddingSimilarity = []string{"dotProduct", "dotProduct", "euclidean"}
    24)
    25
    26func main() {
    27 clientOpts := options.Client().ApplyURI(mongodbURI)
    28 client, err := mongo.Connect(clientOpts)
    29 if err != nil {
    30 log.Fatalf("Failed to connect to MongoDB: %v", err)
    31 }
    32
    33 defer func() {
    34 if err := client.Disconnect(context.TODO()); err != nil {
    35 log.Fatalf("Failed to disconnect MongoDB client: %v", err)
    36 }
    37 }()
    38
    39 storeEmbeddings(client)
    40 setupVectorSearchIndex(client)
    41}
    42
    43// Reads JSON data, stores it in MongoDB
    44func storeEmbeddings(client *mongo.Client) {
    45 database := client.Database(dbName)
    46 collection := database.Collection(collectionName)
    47
    48 data, err := ioutil.ReadFile("embeddings.json")
    49 if err != nil {
    50 log.Fatalf("Failed to read file: %v", err)
    51 }
    52
    53 var documents []bson.M
    54 if err := bson.UnmarshalExtJSON(data, false, &documents); err != nil {
    55 log.Fatalf("Failed to unmarshal JSON data: %v", err)
    56 }
    57
    58 if _, err := collection.InsertMany(context.TODO(), documents); err != nil {
    59 log.Fatalf("Failed to insert documents: %v", err)
    60 }
    61
    62 fmt.Println("Inserted documents into MongoDB")
    63}
    64
    65// Sets up vector search index in MongoDB
    66func setupVectorSearchIndex(client *mongo.Client) {
    67 database := client.Database(dbName)
    68 collection := database.Collection(collectionName)
    69
    70 ctx := context.TODO()
    71
    72 type vectorDefinitionField struct {
    73 Type string `bson:"type"`
    74 Path string `bson:"path"`
    75 NumDimensions int `bson:"numDimensions"`
    76 Similarity string `bson:"similarity"`
    77 }
    78
    79 type vectorDefinition struct {
    80 Fields []vectorDefinitionField `bson:"fields"`
    81 }
    82
    83 fields := make([]vectorDefinitionField, len(embeddingFields))
    84 for i, field := range embeddingFields {
    85 fields[i] = vectorDefinitionField{
    86 Type: "vector",
    87 Path: field,
    88 NumDimensions: numberOfDimensions,
    89 Similarity: embeddingSimilarity[i],
    90 }
    91 }
    92 fmt.Println(fields)
    93
    94 opts := options.SearchIndexes().SetName(indexName).SetType("vectorSearch")
    95
    96 indexModel := mongo.SearchIndexModel{
    97 Definition: vectorDefinition{
    98 Fields: fields,
    99 },
    100 Options: opts,
    101 }
    102
    103 // Create the index
    104 log.Println("Creating the index.")
    105 searchIndexName, err := collection.SearchIndexes().CreateOne(ctx, indexModel)
    106 if err != nil {
    107 log.Fatalf("Failed to create the search index: %v", err)
    108 }
    109
    110 // Polling to confirm successful index creation
    111 log.Println("Polling to confirm successful index creation.")
    112 log.Println("NOTE: This may take up to a minute.")
    113 searchIndexes := collection.SearchIndexes()
    114 var doc bson.Raw
    115
    116 for doc == nil {
    117 cursor, err := searchIndexes.List(ctx, options.SearchIndexes().SetName(searchIndexName))
    118 if err != nil {
    119 log.Fatalf("failed to list search indexes: %v", err)
    120 }
    121
    122 if !cursor.Next(ctx) {
    123 break
    124 }
    125
    126 name := cursor.Current.Lookup("name").StringValue()
    127 queryable := cursor.Current.Lookup("queryable").Boolean()
    128 if name == searchIndexName && queryable {
    129 doc = cursor.Current
    130 } else {
    131 time.Sleep(5 * time.Second)
    132 }
    133 }
    134
    135 log.Println("Name of Index Created: " + searchIndexName)
    136}
  3. Substitua o seguinte por valores válidos no código e salve o arquivo.

    MONGODB_URI

    Sua string de conexão do cluster do Atlas se você não definiu a variável de ambiente.

    <DATABASE-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

    <COLLECTION-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

  4. Execute o programa usando o seguinte comando.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    go run UploadDataAndCreateIndex.go
    Inserted documents into MongoDB
    Creating the index.
    Polling to confirm successful index creation.
    NOTE: This may take up to a minute.
    Name of Index Created: <INDEX-NAME>
  5. Conecte-se no cluster do Atlas e verifique o seguinte:

    • Dados no namespace.

    • Índice do Atlas Vector Search para a coleção.

6

Para testar suas incorporações, você pode executar uma query em sua coleção. Utilize um fornecedor de modelo de incorporação para gerar incorporações float32, int8 e int1 para seu texto de query. O código de exemplo a seguir usa a embed API do Cohere para gerar vetores de precisão total. Depois de gerar as incorporações, use o driver Go do MongoDB para converter sua incorporação de vetor nativo em vetores binários BSON e execute a $vectorSearch query na coleção.

  1. Crie um novo arquivo chamado CreateEmbeddingsAndRunQuery.go em seu projeto Go.

    touch CreateEmbeddingsAndRunQuery.go
  2. Copie e cole o seguinte código no arquivo CreateEmbeddingsAndRunQuery.go.

    Este código faz o seguinte:

    • Gera as incorporações vetoriais float32, int8 e ubinary usando a API embed do Cohere.

    • Converte as incorporações em vetores BSON binData usando o driver MongoDB Go.

    • Executa a query em relação à sua coleção e retorna os resultados.

    CreateEmbeddingsAndRunQuery.go
    1package main
    2
    3import (
    4 "bytes"
    5 "context"
    6 "encoding/json"
    7 "fmt"
    8 "io"
    9 "log"
    10 "net/http"
    11 "os"
    12
    13 "go.mongodb.org/mongo-driver/v2/bson"
    14 "go.mongodb.org/mongo-driver/v2/mongo"
    15 "go.mongodb.org/mongo-driver/v2/mongo/options"
    16)
    17
    18const (
    19 dbName = "<DATABASE-NAME>"
    20 collectionName = "<COLLECTION-NAME>"
    21 vectorIndexName = "<INDEX-NAME>"
    22 dataFieldName = "<TEXT-FIELD-NAME>"
    23 queryText = "<QUERY-TEXT>"
    24 model = "voyage-3-large"
    25 outputDimension = 1024
    26 candidates = <NUMBER-OF-CANDIDATES-TO-CONSIDER>
    27 numDocs = <NUMBER-OF-DOCUMENTS-TO-RETURN>
    28)
    29
    30func main() {
    31 apiKey := os.Getenv("VOYAGE_API_KEY")
    32 mongodbURI := os.Getenv("MONGODB_URI")
    33
    34 if apiKey == "" {
    35 log.Fatal("API key not found. Set VOYAGE_API_KEY in your environment.")
    36 }
    37 if mongodbURI == "" {
    38 log.Fatal("MongoDB URI not found. Set MONGODB_URI in your environment.")
    39 }
    40
    41 embeddingsData, err := generateAndConvertEmbeddings(apiKey, queryText)
    42 if err != nil {
    43 log.Fatalf("Error generating embeddings: %v", err)
    44 }
    45
    46 err = runVectorSearchQuery(mongodbURI, embeddingsData)
    47 if err != nil {
    48 log.Fatalf("Error running vector search query: %v", err)
    49 }
    50}
    51
    52// Generate embeddings using Voyage AI's embedding API from the query text
    53func generateAndConvertEmbeddings(apiKey, text string) (map[string]bson.Binary, error) {
    54 embeddingFormats := []string{"float", "int8", "ubinary"}
    55 embeddingsData := make(map[string]bson.Binary)
    56
    57 for _, outputDType := range embeddingFormats {
    58 response := fetchEmbeddingsFromVoyageAPI(apiKey, text, outputDType)
    59 embedding := createBSONVectorEmbeddings(outputDType, response)
    60 embeddingsData[outputDType] = embedding
    61 }
    62
    63 return embeddingsData, nil
    64}
    65
    66// Fetch embeddings using Voyage AI Embedding REST API
    67func fetchEmbeddingsFromVoyageAPI(apiKey, text, outputDType string) map[string]interface{} {
    68 url := "https://api.voyageai.com/v1/embeddings"
    69
    70 requestBody := map[string]interface{}{
    71 "input": []string{text},
    72 "model": model,
    73 "output_dtype": outputDType,
    74 "output_dimension": outputDimension,
    75 "input_type": "query",
    76 }
    77
    78 requestBytes, err := json.Marshal(requestBody)
    79 if err != nil {
    80 log.Fatalf("Failed to marshal request body: %v", err)
    81 }
    82
    83 req, err := http.NewRequestWithContext(context.TODO(), "POST", url, bytes.NewBuffer(requestBytes))
    84 if err != nil {
    85 log.Fatalf("Failed to create HTTP request: %v", err)
    86 }
    87
    88 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
    89 req.Header.Set("Content-Type", "application/json")
    90
    91 client := &http.Client{}
    92 resp, err := client.Do(req)
    93 if err != nil {
    94 log.Fatalf("Failed to make API request: %v", err)
    95 }
    96 defer resp.Body.Close()
    97
    98 if resp.StatusCode != http.StatusOK {
    99 body, _ := io.ReadAll(resp.Body)
    100 log.Fatalf("Unexpected status code %d: %s", resp.StatusCode, string(body))
    101 }
    102
    103 var response struct {
    104 Data []map[string]interface{} `json:"data"`
    105 }
    106 if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
    107 log.Fatalf("Failed to parse API response: %v", err)
    108 }
    109
    110 if len(response.Data) == 0 {
    111 log.Fatalf("No embeddings found in API response")
    112 }
    113
    114 return response.Data[0]
    115}
    116
    117// Convert embeddings to BSON vectors using MongoDB Go Driver
    118func createBSONVectorEmbeddings(dataType string, rawEmbedding map[string]interface{}) bson.Binary {
    119 embeddingArray := rawEmbedding["embedding"].([]interface{})
    120
    121 switch dataType {
    122 case "float":
    123 floatData := convertInterfaceToFloat32(embeddingArray)
    124 floatVector := bson.NewVector(floatData)
    125 return floatVector.Binary()
    126 case "int8":
    127 int8Data := convertInterfaceToInt8(embeddingArray)
    128 int8Vector := bson.NewVector(int8Data)
    129 return int8Vector.Binary()
    130 case "ubinary":
    131 int1Data := convertInterfaceToBytes(embeddingArray)
    132 ubinaryVector, err := bson.NewPackedBitVector(int1Data, 0)
    133 if err != nil {
    134 log.Fatalf("Error creating PackedBitVector: %v", err)
    135 }
    136 return ubinaryVector.Binary()
    137 default:
    138 log.Fatalf("Unknown data type: %s", dataType)
    139 return bson.Binary{}
    140 }
    141}
    142
    143// Run $vectorSearch query using the embeddings
    144func runVectorSearchQuery(mongodbURI string, embeddingsData map[string]bson.Binary) error {
    145 ctx := context.Background()
    146 clientOptions := options.Client().ApplyURI(mongodbURI)
    147 client, err := mongo.Connect(clientOptions)
    148 if err != nil {
    149 return fmt.Errorf("failed to connect to MongoDB: %w", err)
    150 }
    151 defer func() { _ = client.Disconnect(ctx) }()
    152
    153 db := client.Database(dbName)
    154 collection := db.Collection(collectionName)
    155
    156 pathMap := map[string]string{
    157 "float": "embeddings_float32",
    158 "int8": "embeddings_int8",
    159 "ubinary": "embeddings_int1",
    160 }
    161
    162 for pathKey, queryVector := range embeddingsData {
    163 path, ok := pathMap[pathKey]
    164 if !ok {
    165 return fmt.Errorf("invalid path key: %s", pathKey)
    166 }
    167
    168 pipeline := mongo.Pipeline{
    169 {
    170 {"$vectorSearch", bson.D{
    171 {"queryVector", queryVector},
    172 {"index", vectorIndexName},
    173 {"path", path},
    174 {"numCandidates", candidates},
    175 {"limit", numDocs},
    176 }},
    177 },
    178 {
    179 {"$project", bson.D{
    180 {"_id", 1},
    181 {dataFieldName, 1},
    182 {"score", bson.D{
    183 {"$meta", "vectorSearchScore"},
    184 }},
    185 }},
    186 },
    187 }
    188
    189 cursor, err := collection.Aggregate(context.Background(), pipeline)
    190 if err != nil {
    191 return fmt.Errorf("failed to run vector search aggregation query: %w", err)
    192 }
    193 defer cursor.Close(ctx)
    194
    195 var results []bson.M
    196 if err = cursor.All(context.Background(), &results); err != nil {
    197 return fmt.Errorf("failed to parse aggregation query results: %w", err)
    198 }
    199
    200 fmt.Printf("Results from %v embeddings:\n", path)
    201 for _, result := range results {
    202 fmt.Println(result)
    203 }
    204 }
    205
    206 return nil
    207}
    208
    209// Converts []interface{} to []float32 safely
    210func convertInterfaceToFloat32(data []interface{}) []float32 {
    211 f32s := make([]float32, len(data))
    212 for i, v := range data {
    213 switch val := v.(type) {
    214 case float64:
    215 f32s[i] = float32(val)
    216 case int:
    217 f32s[i] = float32(val)
    218 default:
    219 log.Fatalf("Unexpected type %T in float32 conversion at index %d", v, i)
    220 }
    221 }
    222 return f32s
    223}
    224
    225// Converts []interface{} to []int8 safely
    226func convertInterfaceToInt8(data []interface{}) []int8 {
    227 ints8 := make([]int8, len(data))
    228 for i, v := range data {
    229 switch val := v.(type) {
    230 case float64:
    231 ints8[i] = int8(val)
    232 case int:
    233 ints8[i] = int8(val)
    234 default:
    235 log.Fatalf("Unexpected type %T in int8 conversion at index %d", v, i)
    236 }
    237 }
    238 return ints8
    239}
    240
    241// Converts []interface{} to []byte (uint8) safely
    242func convertInterfaceToBytes(data []interface{}) []byte {
    243 bytesOut := make([]byte, len(data))
    244 for i, v := range data {
    245 switch val := v.(type) {
    246 case float64:
    247 bytesOut[i] = byte(val)
    248 case int:
    249 bytesOut[i] = byte(val)
    250 default:
    251 log.Fatalf("Unexpected type %T in byte conversion at index %d", v, i)
    252 }
    253 }
    254 return bytesOut
    255}
  3. Substitua os seguintes valores de espaço reservado no código e salve o arquivo.

    MONGODB_URI

    Sua string de conexão do cluster do Atlas se você não definiu a variável de ambiente.

    VOYAGE_API_KEY

    Sua chave de API da IA do Voyage somente se você não tiver definido a variável de ambiente.

    <DATABASE-NAME>

    Nome do banco de dados no seu cluster do Atlas.

    <COLLECTION-NAME>

    Nome da coleção em que você fez a ingestão dos dados.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

    <TEXT-FIELD-NAME>

    Nome do campo que contém o texto a partir do qual você gerou as incorporações. Para este exemplo, use text.

    <QUERY-TEXT>

    Texto para a query. Para este exemplo, use science fact.

    <NUMBER-OF-CANDIDATES-TO-CONSIDER>

    Número de vizinhos mais próximos a serem considerados durante a pesquisa. Para este exemplo, use 5.

    <NUMBER-OF-DOCUMENTS-TO-RETURN>

    Número de documentos a retornar nos resultados. Para este exemplo, use 2.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    go run CreateEmbeddingsAndRunQuery.go
    Results from embeddings_float32 embeddings:
    {"_id":{"$oid":"68630fc85cb353712a1c521d"},"text":"The Great Wall of China is visible from space.","score":{"$numberDouble":"0.7723928093910217"}}
    {"_id":{"$oid":"68630fc85cb353712a1c521f"},"text":"Mount Everest is the highest peak on Earth at 8,848m.","score":{"$numberDouble":"0.7363046407699585"}}
    Results from embeddings_int8 embeddings:
    {"_id":{"$oid":"68630fc85cb353712a1c521d"},"text":"The Great Wall of China is visible from space.","score":{"$numberDouble":"0.5051995515823364"}}
    {"_id":{"$oid":"68630fc85cb353712a1c521f"},"text":"Mount Everest is the highest peak on Earth at 8,848m.","score":{"$numberDouble":"0.5044659972190857"}}
    Results from embeddings_int1 embeddings:
    {"_id":{"$oid":"68630fc85cb353712a1c521d"},"text":"The Great Wall of China is visible from space.","score":{"$numberDouble":"0.6845703125"}}
    {"_id":{"$oid":"68630fc85cb353712a1c521f"},"text":"Mount Everest is the highest peak on Earth at 8,848m.","score":{"$numberDouble":"0.6650390625"}}
1

Em uma janela de terminal, execute os seguintes comandos para criar um novo diretório chamado ingest-binary-vectors e inicializar seu projeto:

mkdir ingest-binary-vectors-project
cd ingest-binary-vectors-project
go mod init ingest-binary-vectors-project
2

Execute o comando a seguir para instalar o driver Go do MongoDB. Esta operação pode levar alguns minutos para ser concluída.

go get go.mongodb.org/mongo-driver/v2/mongo

Você deve instalar 2.1 o driver Go v ou posterior. Se necessário, você também pode instalar bibliotecas do fornecedor do modelo de incorporação. Para exemplos neste tutorial, usaremos a API REST da Voyage AI para gerar incorporações. Portanto, você não precisa instalar nenhuma biblioteca adicional.

3
  1. Para acessar o provedor de modelo de incorporação para gerar e converter incorporações, configure a variável de ambiente para a chave de API do provedor de modelo de incorporação, se necessário.

    Para utilizar incorporações da Voyage AI, configure a variável de ambiente do VOYAGE_API_KEY.

    export VOYAGE_API_KEY="<VOYAGE-API-KEY>"
  2. Para acessar o cluster Atlas, defina a variável de ambiente MONGODB_URI.

    export MONGODB_URI="<CONNECTION-STRING>"

    Sua string de conexão deve estar no seguinte formato:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
4

Você pode usar um fornecedor de modelo de incorporação para gerar incorporações float do, int8 e int1 para seus dados e, em seguida, usar o driver MongoDB Go para converter sua incorporação de vetor nativo em vetores BSON. O código de exemplo a seguir usa o voyage-3-large modelo de incorporação da Voyage AI para gerar vetores de precisão total a partir dos dados no sample_airbnb.listingsAndReviews namespace .

  1. Crie um novo arquivo chamado GenerateAndConvertEmbeddings.go em seu projeto Go.

    touch GenerateAndConvertEmbeddings.go
  2. Copie e cole o seguinte código no arquivo GenerateAndConvertEmbeddings.go.

    Este código faz o seguinte:

    • Obtém o campo summary dos documentos 50 no namespace sample_airbnb.listingsAndReviews.

    • Gera as float32 int8 ubinary incorporações de vetor, e usando a API do Voyage AI .

    • Converte as incorporações em vetores BSON binData usando o driver MongoDB Go.

    • Cria um arquivo chamado embeddings.json e salva os dados com as incorporações no arquivo.

    GenerateAndConvertEmbeddings.go
    1package main
    2
    3import (
    4 "bytes"
    5 "context"
    6 "encoding/json"
    7 "fmt"
    8 "io/ioutil"
    9 "log"
    10 "net/http"
    11 "os"
    12
    13 "go.mongodb.org/mongo-driver/v2/bson"
    14 "go.mongodb.org/mongo-driver/v2/mongo"
    15 "go.mongodb.org/mongo-driver/v2/mongo/options"
    16)
    17
    18const (
    19 batchSize = 96
    20 dbName = "sample_airbnb"
    21 collName = "listingsAndReviews"
    22 model = "voyage-3-large"
    23 outputDimension = 1024
    24)
    25
    26func main() {
    27 apiKey := os.Getenv("VOYAGE_API_KEY")
    28 mongodbURI := os.Getenv("MONGODB_URI")
    29
    30 if apiKey == "" || mongodbURI == "" {
    31 log.Fatal("Ensure VOYAGE_API_KEY and MONGODB_URI are set.")
    32 }
    33
    34 summaries, err := fetchSummariesFromMongoDB(mongodbURI)
    35 if err != nil {
    36 log.Fatalf("Error fetching summaries: %v", err)
    37 }
    38
    39 for start := 0; start < len(summaries); start += batchSize {
    40 end := start + batchSize
    41 if end > len(summaries) {
    42 end = len(summaries)
    43 }
    44
    45 floatEmbeddings, err := fetchEmbeddingsFromVoyage(apiKey, summaries[start:end], "float")
    46 if err != nil {
    47 log.Fatalf("Error fetching float embeddings: %v", err)
    48 }
    49
    50 int8Embeddings, err := fetchEmbeddingsFromVoyage(apiKey, summaries[start:end], "int8")
    51 if err != nil {
    52 log.Fatalf("Error fetching int8 embeddings: %v", err)
    53 }
    54
    55 ubinaryEmbeddings, err := fetchEmbeddingsFromVoyage(apiKey, summaries[start:end], "ubinary")
    56 if err != nil {
    57 log.Fatalf("Error fetching ubinary embeddings: %v", err)
    58 }
    59
    60 documents := convertEmbeddingsToBSON(summaries[start:end], floatEmbeddings, int8Embeddings, ubinaryEmbeddings)
    61
    62 err = writeJSONToFile("embeddings.json", documents)
    63 if err != nil {
    64 log.Fatalf("Error writing embeddings to JSON: %v", err)
    65 }
    66 }
    67
    68 fmt.Println("Embeddings successfully saved to embeddings.json")
    69}
    70
    71// Fetch documents with the summary field from the collection
    72func fetchSummariesFromMongoDB(uri string) ([]string, error) {
    73 ctx := context.TODO()
    74 clientOpts := options.Client().ApplyURI(uri)
    75
    76 client, err := mongo.Connect(clientOpts)
    77 if err != nil {
    78 return nil, fmt.Errorf("failed to connect to MongoDB: %w", err)
    79 }
    80 defer func() {
    81 if err := client.Disconnect(ctx); err != nil {
    82 log.Fatalf("Failed to disconnect MongoDB client: %v", err)
    83 }
    84 }()
    85
    86 collection := client.Database(dbName).Collection(collName)
    87 filter := bson.M{"summary": bson.M{"$nin": []interface{}{nil, ""}}}
    88
    89 cursor, err := collection.Find(ctx, filter, options.Find().SetLimit(50))
    90 if err != nil {
    91 return nil, fmt.Errorf("error finding documents: %w", err)
    92 }
    93 defer cursor.Close(ctx)
    94
    95 var summaries []string
    96 for cursor.Next(ctx) {
    97 var result struct {
    98 Summary string `bson:"summary"`
    99 }
    100 if err := cursor.Decode(&result); err != nil {
    101 return nil, fmt.Errorf("error decoding document: %w", err)
    102 }
    103 if result.Summary != "" {
    104 summaries = append(summaries, result.Summary)
    105 }
    106 }
    107
    108 if err := cursor.Err(); err != nil {
    109 return nil, fmt.Errorf("cursor error: %w", err)
    110 }
    111
    112 return summaries, nil
    113}
    114
    115// Fetch embeddings using Voyage AI REST API
    116func fetchEmbeddingsFromVoyage(apiKey string, texts []string, outputDType string) ([]map[string]interface{}, error) {
    117 url := "https://api.voyageai.com/v1/embeddings"
    118
    119 requestBody := map[string]interface{}{
    120 "input": texts,
    121 "model": model,
    122 "output_dtype": outputDType,
    123 "output_dimension": outputDimension,
    124 "input_type": "document",
    125 }
    126
    127 requestBytes, err := json.Marshal(requestBody)
    128 if err != nil {
    129 return nil, fmt.Errorf("failed to marshal request body: %w", err)
    130 }
    131
    132 req, err := http.NewRequestWithContext(context.TODO(), "POST", url, bytes.NewBuffer(requestBytes))
    133 if err != nil {
    134 return nil, fmt.Errorf("failed to create HTTP request: %w", err)
    135 }
    136
    137 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
    138 req.Header.Set("Content-Type", "application/json")
    139
    140 client := &http.Client{}
    141 resp, err := client.Do(req)
    142 if err != nil {
    143 return nil, fmt.Errorf("failed to make API request: %w", err)
    144 }
    145 defer resp.Body.Close()
    146
    147 if resp.StatusCode != http.StatusOK {
    148 body, _ := ioutil.ReadAll(resp.Body)
    149 return nil, fmt.Errorf("unexpected status code %d: %s", resp.StatusCode, string(body))
    150 }
    151
    152 var response struct {
    153 Data []map[string]interface{} `json:"data"`
    154 }
    155 if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
    156 return nil, fmt.Errorf("failed to parse API response: %w", err)
    157 }
    158
    159 return response.Data, nil
    160}
    161
    162// Convert embeddings to BSON binary vectors
    163func convertEmbeddingsToBSON(summaries []string, floatEmbeddings []map[string]interface{}, int8Embeddings []map[string]interface{}, ubinaryEmbeddings []map[string]interface{}) []bson.M {
    164 var documents []bson.M
    165
    166 for i, summary := range summaries {
    167 floatEmbedding := convertInterfaceToFloat32(floatEmbeddings[i]["embedding"].([]interface{}))
    168 int8Embedding := convertInterfaceToInt8(int8Embeddings[i]["embedding"].([]interface{}))
    169 ubinaryEmbedding := convertInterfaceToBytes(ubinaryEmbeddings[i]["embedding"].([]interface{}))
    170
    171 floatVector := bson.NewVector(floatEmbedding)
    172 int8Vector := bson.NewVector(int8Embedding)
    173 ubinaryVector, err := bson.NewPackedBitVector(ubinaryEmbedding, 0)
    174 if err != nil {
    175 log.Fatalf("Error creating PackedBitVector: %v", err)
    176 }
    177
    178 document := bson.M{
    179 "text": summary,
    180 "embeddings_float32": floatVector.Binary(),
    181 "embeddings_int8": int8Vector.Binary(),
    182 "embeddings_int1": ubinaryVector.Binary(),
    183 }
    184
    185 documents = append(documents, document)
    186 }
    187
    188 return documents
    189}
    190
    191// Write JSON file from in-memory BSON documents
    192func writeJSONToFile(filename string, docs []bson.M) error {
    193 file, err := os.Create(filename)
    194 if err != nil {
    195 return fmt.Errorf("failed to create file: %w", err)
    196 }
    197 defer file.Close()
    198
    199 var jsonDocuments []json.RawMessage
    200 for _, document := range docs {
    201 jsonBytes, err := bson.MarshalExtJSON(document, false, false)
    202 if err != nil {
    203 log.Fatalf("Error: %v", err)
    204 }
    205 jsonDocuments = append(jsonDocuments, jsonBytes)
    206 }
    207
    208 jsonData, err := json.MarshalIndent(jsonDocuments, "", " ")
    209 if err != nil {
    210 return fmt.Errorf("failed to marshal JSON: %w", err)
    211 }
    212
    213 _, err = file.Write(jsonData)
    214 if err != nil {
    215 return fmt.Errorf("failed to write JSON to file: %w", err)
    216 }
    217
    218 return nil
    219}
    220
    221// Converts slice of interface{} to []float32
    222func convertInterfaceToFloat32(data []interface{}) []float32 {
    223 f32s := make([]float32, len(data))
    224 for i, v := range data {
    225 f32s[i] = float32(v.(float64))
    226 }
    227 return f32s
    228}
    229
    230// Converts slice of interface{} to []int8 safely
    231func convertInterfaceToInt8(data []interface{}) []int8 {
    232 ints8 := make([]int8, len(data))
    233 for i, v := range data {
    234 switch val := v.(type) {
    235 case float64:
    236 ints8[i] = int8(val)
    237 case int:
    238 ints8[i] = int8(val)
    239 default:
    240 log.Fatalf("Unexpected type %T in int8 embedding at index %d", v, i)
    241 }
    242 }
    243 return ints8
    244}
    245
    246// Converts slice of interface{} to []byte safely
    247func convertInterfaceToBytes(data []interface{}) []byte {
    248 bytes := make([]byte, len(data))
    249 for i, v := range data {
    250 switch val := v.(type) {
    251 case float64:
    252 bytes[i] = byte(val)
    253 case int:
    254 bytes[i] = byte(val)
    255 default:
    256 log.Fatalf("Unexpected type %T in ubinary embedding at index %d", v, i)
    257 }
    258 }
    259 return bytes
    260}
  3. Substitua os seguintes valores de placeholder no código se você não definiu as variáveis de ambiente e salve o arquivo.

    MONGODB_URI

    Sua string de conexão do cluster do Atlas se você não definiu a variável de ambiente.

    VOYAGE_API_KEY

    Sua chave de API do Voyage AI se você não tiver definido a variável de ambiente.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    go run GenerateAndConvertEmbeddings.go
    Embeddings successfully saved to embeddings.json
  5. Verifique as incorporações no arquivo embeddings.json.

Para aprender mais sobre como gerar incorporações e convertê-las em vetores binData, veja Como criar incorporações vetoriais.

5

Você deve carregar seus dados e incorporações em uma coleção no cluster do Atlas e criar um índice Atlas Vector Search nos dados para executar queries $vectorSearch em relação aos dados.

  1. Crie um novo arquivo chamado UploadDataAndCreateIndex.go em seu projeto Go.

    touch UploadDataAndCreateIndex.go
  2. Copie e cole o seguinte código no arquivo UploadDataAndCreateIndex.go.

    Este código faz o seguinte:

    • Carrega as incorporações float32, int8 e int1 no arquivo embeddings.json para o seu cluster do Atlas.

    • Cria um índice do Atlas Vector Search nos campos embeddings.float32, embeddings.int8 e embeddings.int1.

    UploadDataAndCreateIndex.go
    1package main
    2
    3import (
    4 "context"
    5 "fmt"
    6 "io/ioutil"
    7 "log"
    8 "time"
    9 "os"
    10
    11 "go.mongodb.org/mongo-driver/v2/bson"
    12 "go.mongodb.org/mongo-driver/v2/mongo"
    13 "go.mongodb.org/mongo-driver/v2/mongo/options"
    14)
    15
    16var (
    17 mongodbURI = os.Getenv("MONGODB_URI")
    18 dbName = "sample_airbnb"
    19 collectionName = "listingsAndReviews"
    20 indexName = "<INDEX-NAME>"
    21 numberOfDimensions = 1024
    22 embeddingFields = []string{"embeddings_float32", "embeddings_int8", "embeddings_int1"}
    23 embeddingSimilarity = []string{"dotProduct", "dotProduct", "euclidean"}
    24)
    25
    26func main() {
    27 if mongodbURI == "" {
    28 log.Fatal("MONGODB_URI environment variable not set")
    29 }
    30
    31 clientOptions := options.Client().ApplyURI(mongodbURI)
    32 client, err := mongo.Connect(clientOptions)
    33 if err != nil {
    34 log.Fatalf("Error connecting to MongoDB: %v", err)
    35 }
    36 defer func() {
    37 if err = client.Disconnect(context.TODO()); err != nil {
    38 log.Fatal(err)
    39 }
    40 }()
    41
    42 if err := uploadEmbeddingsData(client); err != nil {
    43 log.Fatalf("Error uploading embeddings data: %v", err)
    44 }
    45
    46 setupVectorSearchIndex(client)
    47}
    48
    49func uploadEmbeddingsData(client *mongo.Client) error {
    50 collection := client.Database(dbName).Collection(collectionName)
    51
    52 // Load embeddings.json file
    53 fileContent, err := ioutil.ReadFile("embeddings.json")
    54 if err != nil {
    55 return fmt.Errorf("error reading file: %w", err)
    56 }
    57
    58 // Convert JSON file content to BSON compatible format using UnmarshalExtJSON
    59 var documents []bson.M
    60 if err := bson.UnmarshalExtJSON(fileContent, false, &documents); err != nil {
    61 return fmt.Errorf("failed to unmarshal JSON data: %w", err)
    62 }
    63
    64 // Update documents in MongoDB
    65 for _, doc := range documents {
    66 summary, exists := doc["text"].(string)
    67 if !exists {
    68 return fmt.Errorf("missing 'text' field in document")
    69 }
    70
    71 // Using bson.Binary ensures binary data is correctly interpreted
    72 if float32Bin, ok := doc["embeddings_float32"].(bson.Binary); ok {
    73 doc["embeddings_float32"] = float32Bin
    74 }
    75 if int8Bin, ok := doc["embeddings_int8"].(bson.Binary); ok {
    76 doc["embeddings_int8"] = int8Bin
    77 }
    78 if int1Bin, ok := doc["embeddings_int1"].(bson.Binary); ok {
    79 doc["embeddings_int1"] = int1Bin
    80 }
    81
    82 filter := bson.M{"summary": summary}
    83 update := bson.M{
    84 "$set": doc,
    85 }
    86
    87 // Set the upsert option
    88 opts := options.UpdateMany().SetUpsert(true)
    89
    90 _, err = collection.UpdateMany(context.TODO(), filter, update, opts)
    91 if err != nil {
    92 return fmt.Errorf("failed to update documents: %w", err)
    93 }
    94 }
    95
    96 return nil
    97}
    98
    99// Sets up vector search index in MongoDB
    100func setupVectorSearchIndex(client *mongo.Client) {
    101 database := client.Database(dbName)
    102 collection := database.Collection(collectionName)
    103
    104 ctx := context.TODO()
    105
    106 type vectorDefinitionField struct {
    107 Type string `bson:"type"`
    108 Path string `bson:"path"`
    109 NumDimensions int `bson:"numDimensions"`
    110 Similarity string `bson:"similarity"`
    111 }
    112
    113 type vectorDefinition struct {
    114 Fields []vectorDefinitionField `bson:"fields"`
    115 }
    116
    117 fields := make([]vectorDefinitionField, len(embeddingFields))
    118 for i, field := range embeddingFields {
    119 fields[i] = vectorDefinitionField{
    120 Type: "vector",
    121 Path: field,
    122 NumDimensions: numberOfDimensions,
    123 Similarity: embeddingSimilarity[i],
    124 }
    125 }
    126
    127 opts := options.SearchIndexes().SetName(indexName).SetType("vectorSearch")
    128
    129 indexModel := mongo.SearchIndexModel{
    130 Definition: vectorDefinition{
    131 Fields: fields,
    132 },
    133 Options: opts,
    134 }
    135
    136 // Create the index
    137 log.Println("Creating the index.")
    138 searchIndexName, err := collection.SearchIndexes().CreateOne(ctx, indexModel)
    139 if err != nil {
    140 log.Fatalf("Failed to create the search index: %v", err)
    141 }
    142
    143 // Polling to confirm successful index creation
    144 log.Println("Polling to confirm successful index creation.")
    145 log.Println("NOTE: This may take up to a minute.")
    146 searchIndexes := collection.SearchIndexes()
    147 var doc bson.Raw
    148
    149 for doc == nil {
    150 cursor, err := searchIndexes.List(ctx, options.SearchIndexes().SetName(searchIndexName))
    151 if err != nil {
    152 log.Fatalf("failed to list search indexes: %v", err)
    153 }
    154
    155 if !cursor.Next(ctx) {
    156 break
    157 }
    158
    159 name := cursor.Current.Lookup("name").StringValue()
    160 queryable := cursor.Current.Lookup("queryable").Boolean()
    161 if name == searchIndexName && queryable {
    162 doc = cursor.Current
    163 } else {
    164 time.Sleep(5 * time.Second)
    165 }
    166 }
    167
    168 log.Println("Name of Index Created: " + searchIndexName)
    169}
  3. Substitua os seguintes valores de espaço reservado no código e salve o arquivo.

    MONGODB_URI

    Sua string de conexão do cluster do Atlas se você não definiu a variável de ambiente.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    go run UploadDataAndCreateIndex.go
    Creating the index.
    Polling to confirm successful index creation.
    NOTE: This may take up to a minute.
    Name of Index Created: <INDEX-NAME>
  5. Conecte-se no cluster do Atlas e verifique o seguinte:

    • Dados no namespace.

    • Índice do Atlas Vector Search para a coleção.

6

Para testar suas incorporações, você pode executar uma query em sua coleção. Utilize um fornecedor de modelo de incorporação para gerar float int8incorporações, e int1 para seu texto de query. O código de amostra a seguir usa a API da Voyage AI para gerar vetores de precisão total. Depois de gerar as incorporações, use o driver Go do MongoDB para converter sua incorporação de vetor nativo em vetores BSON e execute $vectorSearch a query na coleção.

  1. Crie um novo arquivo chamado CreateEmbeddingsAndRunQuery.go em seu projeto Go.

    touch CreateEmbeddingsAndRunQuery.go
  2. Copie e cole o seguinte código no arquivo CreateEmbeddingsAndRunQuery.go.

    Este código faz o seguinte:

    • Gera as float32 int8 ubinary incorporações de vetor, e usando a API do Voyage AI .

    • Converte as incorporações em vetores BSON binData usando o driver MongoDB Go.

    • Executa a query em relação à sua coleção e retorna os resultados.

    CreateEmbeddingsAndRunQuery.go
    1package main
    2
    3import (
    4 "bytes"
    5 "context"
    6 "encoding/json"
    7 "fmt"
    8 "io"
    9 "log"
    10 "net/http"
    11 "os"
    12
    13 "go.mongodb.org/mongo-driver/v2/bson"
    14 "go.mongodb.org/mongo-driver/v2/mongo"
    15 "go.mongodb.org/mongo-driver/v2/mongo/options"
    16)
    17
    18const (
    19 dbName = "<DATABASE-NAME>"
    20 collectionName = "<COLLECTION-NAME>"
    21 vectorIndexName = "<INDEX-NAME>"
    22 dataFieldName = "<TEXT-FIELD-NAME>"
    23 queryText = "<QUERY-TEXT>"
    24 model = "voyage-3-large"
    25 outputDimension = 1024
    26 candidates = <NUMBER-OF-CANDIDATES-TO-CONSIDER>
    27 numDocs = <NUMBER-OF-DOCUMENTS-TO-RETURN>
    28)
    29
    30func main() {
    31 apiKey := os.Getenv("VOYAGE_API_KEY")
    32 mongodbURI := os.Getenv("MONGODB_URI")
    33
    34 if apiKey == "" {
    35 log.Fatal("API key not found. Set VOYAGE_API_KEY in your environment.")
    36 }
    37 if mongodbURI == "" {
    38 log.Fatal("MongoDB URI not found. Set MONGODB_URI in your environment.")
    39 }
    40
    41 embeddingsData, err := generateAndConvertEmbeddings(apiKey, queryText)
    42 if err != nil {
    43 log.Fatalf("Error generating embeddings: %v", err)
    44 }
    45
    46 err = runVectorSearchQuery(mongodbURI, embeddingsData)
    47 if err != nil {
    48 log.Fatalf("Error running vector search query: %v", err)
    49 }
    50}
    51
    52// Generate embeddings using Voyage AI's embedding API from the query text
    53func generateAndConvertEmbeddings(apiKey, text string) (map[string]bson.Binary, error) {
    54 embeddingFormats := []string{"float", "int8", "ubinary"}
    55 embeddingsData := make(map[string]bson.Binary)
    56
    57 for _, outputDType := range embeddingFormats {
    58 response := fetchEmbeddingsFromVoyageAPI(apiKey, text, outputDType)
    59 embedding := createBSONVectorEmbeddings(outputDType, response)
    60 embeddingsData[outputDType] = embedding
    61 }
    62
    63 return embeddingsData, nil
    64}
    65
    66// Fetch embeddings using Voyage AI Embedding REST API
    67func fetchEmbeddingsFromVoyageAPI(apiKey, text, outputDType string) map[string]interface{} {
    68 url := "https://api.voyageai.com/v1/embeddings"
    69
    70 requestBody := map[string]interface{}{
    71 "input": []string{text},
    72 "model": model,
    73 "output_dtype": outputDType,
    74 "output_dimension": outputDimension,
    75 "input_type": "query",
    76 }
    77
    78 requestBytes, err := json.Marshal(requestBody)
    79 if err != nil {
    80 log.Fatalf("Failed to marshal request body: %v", err)
    81 }
    82
    83 req, err := http.NewRequestWithContext(context.TODO(), "POST", url, bytes.NewBuffer(requestBytes))
    84 if err != nil {
    85 log.Fatalf("Failed to create HTTP request: %v", err)
    86 }
    87
    88 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", apiKey))
    89 req.Header.Set("Content-Type", "application/json")
    90
    91 client := &http.Client{}
    92 resp, err := client.Do(req)
    93 if err != nil {
    94 log.Fatalf("Failed to make API request: %v", err)
    95 }
    96 defer resp.Body.Close()
    97
    98 if resp.StatusCode != http.StatusOK {
    99 body, _ := io.ReadAll(resp.Body)
    100 log.Fatalf("Unexpected status code %d: %s", resp.StatusCode, string(body))
    101 }
    102
    103 var response struct {
    104 Data []map[string]interface{} `json:"data"`
    105 }
    106 if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
    107 log.Fatalf("Failed to parse API response: %v", err)
    108 }
    109
    110 if len(response.Data) == 0 {
    111 log.Fatalf("No embeddings found in API response")
    112 }
    113
    114 return response.Data[0]
    115}
    116
    117// Convert embeddings to BSON vectors using MongoDB Go Driver
    118func createBSONVectorEmbeddings(dataType string, rawEmbedding map[string]interface{}) bson.Binary {
    119 embeddingArray := rawEmbedding["embedding"].([]interface{})
    120
    121 switch dataType {
    122 case "float":
    123 floatData := convertInterfaceToFloat32(embeddingArray)
    124 floatVector := bson.NewVector(floatData)
    125 return floatVector.Binary()
    126 case "int8":
    127 int8Data := convertInterfaceToInt8(embeddingArray)
    128 int8Vector := bson.NewVector(int8Data)
    129 return int8Vector.Binary()
    130 case "ubinary":
    131 int1Data := convertInterfaceToBytes(embeddingArray)
    132 ubinaryVector, err := bson.NewPackedBitVector(int1Data, 0)
    133 if err != nil {
    134 log.Fatalf("Error creating PackedBitVector: %v", err)
    135 }
    136 return ubinaryVector.Binary()
    137 default:
    138 log.Fatalf("Unknown data type: %s", dataType)
    139 return bson.Binary{}
    140 }
    141}
    142
    143// Run $vectorSearch query using the embeddings
    144func runVectorSearchQuery(mongodbURI string, embeddingsData map[string]bson.Binary) error {
    145 ctx := context.Background()
    146 clientOptions := options.Client().ApplyURI(mongodbURI)
    147 client, err := mongo.Connect(clientOptions)
    148 if err != nil {
    149 return fmt.Errorf("failed to connect to MongoDB: %w", err)
    150 }
    151 defer func() { _ = client.Disconnect(ctx) }()
    152
    153 db := client.Database(dbName)
    154 collection := db.Collection(collectionName)
    155
    156 pathMap := map[string]string{
    157 "float": "embeddings_float32",
    158 "int8": "embeddings_int8",
    159 "ubinary": "embeddings_int1",
    160 }
    161
    162 for pathKey, queryVector := range embeddingsData {
    163 path, ok := pathMap[pathKey]
    164 if !ok {
    165 return fmt.Errorf("invalid path key: %s", pathKey)
    166 }
    167
    168 pipeline := mongo.Pipeline{
    169 {
    170 {"$vectorSearch", bson.D{
    171 {"queryVector", queryVector},
    172 {"index", vectorIndexName},
    173 {"path", path},
    174 {"numCandidates", candidates},
    175 {"limit", numDocs},
    176 }},
    177 },
    178 {
    179 {"$project", bson.D{
    180 {"_id", 1},
    181 {dataFieldName, 1},
    182 {"score", bson.D{
    183 {"$meta", "vectorSearchScore"},
    184 }},
    185 }},
    186 },
    187 }
    188
    189 cursor, err := collection.Aggregate(context.Background(), pipeline)
    190 if err != nil {
    191 return fmt.Errorf("failed to run vector search aggregation query: %w", err)
    192 }
    193 defer cursor.Close(ctx)
    194
    195 var results []bson.M
    196 if err = cursor.All(context.Background(), &results); err != nil {
    197 return fmt.Errorf("failed to parse aggregation query results: %w", err)
    198 }
    199
    200 fmt.Printf("Results from %v embeddings:\n", path)
    201 for _, result := range results {
    202 fmt.Println(result)
    203 }
    204 }
    205
    206 return nil
    207}
    208
    209// Converts []interface{} to []float32 safely
    210func convertInterfaceToFloat32(data []interface{}) []float32 {
    211 f32s := make([]float32, len(data))
    212 for i, v := range data {
    213 switch val := v.(type) {
    214 case float64:
    215 f32s[i] = float32(val)
    216 case int:
    217 f32s[i] = float32(val)
    218 default:
    219 log.Fatalf("Unexpected type %T in float32 conversion at index %d", v, i)
    220 }
    221 }
    222 return f32s
    223}
    224
    225// Converts []interface{} to []int8 safely
    226func convertInterfaceToInt8(data []interface{}) []int8 {
    227 ints8 := make([]int8, len(data))
    228 for i, v := range data {
    229 switch val := v.(type) {
    230 case float64:
    231 ints8[i] = int8(val)
    232 case int:
    233 ints8[i] = int8(val)
    234 default:
    235 log.Fatalf("Unexpected type %T in int8 conversion at index %d", v, i)
    236 }
    237 }
    238 return ints8
    239}
    240
    241// Converts []interface{} to []byte (uint8) safely
    242func convertInterfaceToBytes(data []interface{}) []byte {
    243 bytesOut := make([]byte, len(data))
    244 for i, v := range data {
    245 switch val := v.(type) {
    246 case float64:
    247 bytesOut[i] = byte(val)
    248 case int:
    249 bytesOut[i] = byte(val)
    250 default:
    251 log.Fatalf("Unexpected type %T in byte conversion at index %d", v, i)
    252 }
    253 }
    254 return bytesOut
    255}
  3. Substitua os seguintes valores de espaço reservado no código e salve o arquivo.

    MONGODB_URI

    Sua string de conexão do cluster do Atlas se você não definiu a variável de ambiente.

    VOYAGE_API_KEY

    Sua chave de API do Voyage AI se você não tiver definido a variável de ambiente.

    <DATABASE-NAME>

    Nome do banco de dados no seu cluster do Atlas. Para este exemplo, use sample_airbnb.

    <COLLECTION-NAME>

    Nome da coleção em que você fez a ingestão dos dados. Para este exemplo, use listingsAndReviews.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

    <TEXT-FIELD-NAME>

    Nome do campo que contém o texto a partir do qual você gerou as incorporações. Para este exemplo, use summary.

    <QUERY-TEXT>

    Texto para a query. Para este exemplo, use ocean view.

    <NUMBER-OF-CANDIDATES-TO-CONSIDER>

    Número de vizinhos mais próximos a serem considerados durante a pesquisa. Para este exemplo, use 20.

    <NUMBER-OF-DOCUMENTS-TO-RETURN>

    Número de documentos a retornar nos resultados. Para este exemplo, use 5.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    go run CreateEmbeddingsAndRunQuery.go
    Results from embeddings_float32 embeddings:
    {"_id":"10266175","summary":"A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.","score":{"$numberDouble":"0.7278661131858826"}}
    {"summary":"A short distance from Honolulu's billion dollar mall, and the same distance to Waikiki. Parking included. A great location that work perfectly for business, education, or simple visit. Experience Yacht Harbor views and 5 Star Hilton Hawaiian Village.","score":{"$numberDouble":"0.688639760017395"},"_id":"1001265"}
    Results from embeddings_int8 embeddings:
    {"_id":"10266175","summary":"A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.","score":{"$numberDouble":"0.5215557217597961"}}
    {"_id":"1001265","summary":"A short distance from Honolulu's billion dollar mall, and the same distance to Waikiki. Parking included. A great location that work perfectly for business, education, or simple visit. Experience Yacht Harbor views and 5 Star Hilton Hawaiian Village.","score":{"$numberDouble":"0.5179016590118408"}}
    Results from embeddings_int1 embeddings:
    {"_id":"10266175","summary":"A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.","score":{"$numberDouble":"0.6591796875"}}
    {"_id":"1001265","summary":"A short distance from Honolulu's billion dollar mall, and the same distance to Waikiki. Parking included. A great location that work perfectly for business, education, or simple visit. Experience Yacht Harbor views and 5 Star Hilton Hawaiian Village.","score":{"$numberDouble":"0.6337890625"}}

Para aprender mais sobre como gerar incorporações e convertê-las em vetores binData, veja Como criar incorporações vetoriais.

Crie um projeto Java no seu IDE com as dependências configuradas para o MongoDB Java Driver e, em seguida, execute as seguintes etapas no projeto. Para testar o exemplo, substitua os espaços reservados por valores válidos.

1
  1. No seu IDE, crie um projeto Java usando Maven ou Gradle.

  2. Adicione as seguintes dependências, dependendo do seu gerenciador de pacotes:

    Se você estiver utilizando o Maven, adicione as seguintes dependências à array dependencies no arquivo pom.xml do seu projeto:

    <dependencies>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-sync</artifactId>
    <version>5.3.1</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.16</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.16</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20250517</version>
    </dependency>
    <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
    </dependency>
    </dependencies>

    Se você estiver usando o Gradle, adicione o seguinte à array dependencies no arquivo build.gradle do seu projeto:

    build.gradle
    dependencies {
    // JUnit for testing
    testImplementation 'junit:junit:3.8.1'
    // MongoDB synchronous driver
    implementation 'org.mongodb:mongodb-driver-sync:5.3.1'
    // SLF4J API for logging
    implementation 'org.slf4j:slf4j-api:2.0.16'
    // SLF4J Simple Logger (scope: test)
    testImplementation 'org.slf4j:slf4j-simple:2.0.16'
    // JSON library
    implementation 'org.json:json:20210307'
    // HTTP client for Java
    implementation 'com.squareup.okhttp3:okhttp:4.12.0' // Or the latest version
    }
  3. Execute seu gerenciador de pacote para instalar as dependências em seu projeto.

2

Observação

Este exemplo define as variáveis do projeto no IDE. Os aplicativos de produção podem gerenciar variáveis de ambiente por meio de uma configuração de sistema, pipeline CI/CD ou gerenciador de segredos, mas você pode adaptar o código fornecido para se adequar ao seu caso de uso.

No seu IDE, crie um novo modelo de configuração e adicione as seguintes variáveis ao seu projeto:

Variáveis de ambiente
VOYAGE_API_KEY=<api-key>
MONGODB_URI=<connection-string>

Atualize os espaços reservados com os seguintes valores:

  • Substitua o valor do espaço reservado <api-key> pela chave API do Voyage AI.

  • Substitua o <connection-string> valor do espaço reservado pela string de conexão SRVdo seu Atlas cluster.

    Sua string de conexão deve usar o seguinte formato:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
3

Você pode usar um fornecedor de modelo de incorporação para gerar float int8incorporações, e int1 para seus dados e, em seguida, usar o driver Java do MongoDB para converter sua incorporação de vetor nativo em vetores BSON. O código de exemplo a seguir usa a voyage-3-large API da Voyage AI para gerar vetores de precisão total.

  1. Crie um novo arquivo chamado GenerateAndConvertEmbeddings.java em seu projeto Java.

    touch GenerateAndConvertEmbeddings.java
  2. Copie e cole o seguinte código no arquivo GenerateAndConvertEmbeddings.java.

    Este código faz o seguinte:

    • Gera as incorporações de vetor float32, int8 e ubinary usando o modelo de incorporação voyage-3-large da Voyage AI.

    • Converte as incorporações em vetores BSON binData usando o driver Java do MongoDB.

    • Cria um arquivo chamado embeddings.json e salva os dados com incorporações no arquivo para carregar para o Atlas.

    GenerateAndConvertEmbeddings.java
    1import okhttp3.*;
    2import org.bson.BinaryVector;
    3import org.bson.Document;
    4import org.json.JSONArray;
    5import org.json.JSONObject;
    6
    7import java.io.FileOutputStream;
    8import java.io.IOException;
    9import java.util.ArrayList;
    10import java.util.List;
    11import java.util.Objects;
    12import java.util.concurrent.TimeUnit;
    13
    14public class GenerateAndConvertEmbeddings {
    15 // Sample Data
    16 private static final List<String> DATA = List.of(
    17 "The Great Wall of China is visible from space.",
    18 "The Eiffel Tower was completed in Paris in 1889.",
    19 "Mount Everest is the highest peak on Earth at 8,848m.",
    20 "Shakespeare wrote 37 plays and 154 sonnets during his lifetime.",
    21 "The Mona Lisa was painted by Leonardo da Vinci."
    22 );
    23
    24 // Configuration settings
    25 private static final String VOYAGE_API_URL = "https://api.voyageai.com/v1/embeddings";
    26 private static final int CONNECTION_TIMEOUT = 30;
    27 private static final int READ_TIMEOUT = 60;
    28
    29 public static void main(String[] args) {
    30 String apiKey = System.getenv("VOYAGE_API_KEY"); // Replace with your actual API key
    31
    32 if (Objects.isNull(apiKey) || apiKey.isEmpty()) {
    33 throw new RuntimeException("API key not found.");
    34 }
    35
    36 Document bsonEmbeddings = fetchEmbeddings(apiKey);
    37 writeToFile(bsonEmbeddings, "embeddings.json");
    38 }
    39
    40 // Fetch embeddings from Voyage AI API using the given API key
    41 private static Document fetchEmbeddings(String apiKey) {
    42 OkHttpClient client = new OkHttpClient.Builder()
    43 .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
    44 .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
    45 .build();
    46
    47 List<List<List<Integer>>> embeddingsByOutputType = new ArrayList<>();
    48 List<String> outputDtypes = List.of("float", "int8", "ubinary");
    49
    50 try {
    51 for (String dtype : outputDtypes) {
    52 String responseBody = sendRequest(client, apiKey, dtype);
    53 embeddingsByOutputType.add(parseEmbeddings(responseBody, dtype));
    54 }
    55 } catch (IOException e) {
    56 throw new RuntimeException("Error fetching embeddings: " + e.getMessage(), e);
    57 }
    58
    59 return convertEmbeddingsToBson(embeddingsByOutputType);
    60 }
    61
    62 // Send API request to Voyage AI
    63 private static String sendRequest(OkHttpClient client, String apiKey, String outputDtype) throws IOException {
    64 String requestBody = new JSONObject()
    65 .put("input", DATA)
    66 .put("model", "voyage-3-large")
    67 .put("input_type", "document")
    68 .put("output_dtype", outputDtype)
    69 .put("output_dimension", 1024)
    70 .toString();
    71
    72 Request request = new Request.Builder()
    73 .url(VOYAGE_API_URL)
    74 .post(RequestBody.create(requestBody, MediaType.get("application/json")))
    75 .addHeader("Authorization", "Bearer " + apiKey)
    76 .build();
    77
    78 try (Response response = client.newCall(request).execute()) {
    79 if (!response.isSuccessful()) {
    80 throw new IOException("API error: HTTP " + response.code());
    81 }
    82 return response.body().string();
    83 }
    84 }
    85
    86 // Parse embeddings from Voyage AI API response
    87 private static List<List<Integer>> parseEmbeddings(String responseBody, String outputDtype) {
    88 JSONObject responseJson = new JSONObject(responseBody);
    89 JSONArray dataArray = responseJson.optJSONArray("data");
    90
    91 if (dataArray == null) {
    92 throw new RuntimeException("Invalid response format: 'data' field missing.");
    93 }
    94
    95 List<List<Integer>> embeddings = new ArrayList<>();
    96 for (int i = 0; i < dataArray.length(); i++) {
    97 JSONArray embeddingVector = dataArray.getJSONObject(i).getJSONArray("embedding");
    98
    99 List<Integer> vector = new ArrayList<>();
    100 for (int j = 0; j < embeddingVector.length(); j++) {
    101 int value = embeddingVector.getInt(j);
    102
    103 // Handle binary quantization offset
    104 if ("binary".equals(outputDtype)) {
    105 value = value - 128; // Offset binary method (signed int8 representation)
    106 }
    107
    108 vector.add(value);
    109 }
    110 embeddings.add(vector);
    111 }
    112 return embeddings;
    113 }
    114
    115 // Convert fetched embeddings into BSON format
    116 private static Document convertEmbeddingsToBson(List<List<List<Integer>>> embeddingsByOutputType) {
    117 List<Document> bsonEmbeddings = new ArrayList<>();
    118 for (int i = 0; i < DATA.size(); i++) {
    119 Document embedding = new Document()
    120 .append("text", DATA.get(i))
    121 .append("embeddings_float32", BinaryVector.floatVector(listToFloatArray(embeddingsByOutputType.get(0).get(i))))
    122 .append("embeddings_int8", BinaryVector.int8Vector(listToByteArray(embeddingsByOutputType.get(1).get(i)))) // Binary embeddings
    123 .append("embeddings_int1", BinaryVector.packedBitVector(listToByteArray(embeddingsByOutputType.get(2).get(i)), (byte) 0)); // Ubinary embeddings
    124 bsonEmbeddings.add(embedding);
    125 }
    126 return new Document("data", bsonEmbeddings);
    127 }
    128
    129 // Save BSON embeddings to a JSON file
    130 private static void writeToFile(Document bsonEmbeddings, String fileName) {
    131 try (FileOutputStream fos = new FileOutputStream(fileName)) {
    132 fos.write(bsonEmbeddings.toJson().getBytes());
    133 System.out.println("Embeddings saved to " + fileName);
    134 } catch (IOException e) {
    135 throw new RuntimeException("Error saving file: " + e.getMessage(), e);
    136 }
    137 }
    138
    139 private static float[] listToFloatArray(List<Integer> list) {
    140 float[] array = new float[list.size()];
    141 for (int i = 0; i < list.size(); i++) {
    142 array[i] = list.get(i).floatValue();
    143 }
    144 return array;
    145 }
    146
    147 private static byte[] listToByteArray(List<Integer> list) {
    148 byte[] array = new byte[list.size()];
    149 for (int i = 0; i < list.size(); i++) {
    150 array[i] = list.get(i).byteValue();
    151 }
    152 return array;
    153 }
    154}
  3. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    javac GenerateAndConvertEmbeddings.java
    java GenerateAndConvertEmbeddings
    Embeddings saved to embeddings.json
  4. Verifique as incorporações no arquivo embeddings.json.

Para aprender mais sobre como gerar incorporações e convertê-las em vetores binData, veja Como criar incorporações vetoriais.

4

Você deve carregar seus dados e incorporações em uma coleção no cluster do Atlas e criar um índice Atlas Vector Search nos dados para executar queries $vectorSearch em relação aos dados.

  1. Crie um novo arquivo chamado UploadDataAndCreateIndex.java em seu projeto Java.

    touch UploadDataAndCreateIndex.java
  2. Copie e cole o seguinte código no arquivo UploadDataAndCreateIndex.java.

    Este código faz o seguinte:

    • Carrega os dados do arquivo embeddings.json para o seu cluster do Atlas.

    • Cria um índice do Atlas Vector Search nos campos embeddings_float32, embeddings_int8 e embeddings_int1.

    UploadDataAndCreateIndex.java
    1import com.mongodb.client.MongoClient;
    2import com.mongodb.client.MongoClients;
    3import com.mongodb.client.MongoCollection;
    4import com.mongodb.client.MongoDatabase;
    5import com.mongodb.client.model.SearchIndexModel;
    6import com.mongodb.client.model.SearchIndexType;
    7import org.bson.Document;
    8import org.bson.conversions.Bson;
    9
    10import java.io.IOException;
    11import java.nio.file.Files;
    12import java.nio.file.Path;
    13import java.util.Collections;
    14import java.util.List;
    15import java.util.concurrent.TimeUnit;
    16import java.util.stream.StreamSupport;
    17
    18public class UploadDataAndCreateIndex {
    19
    20 private static final String MONGODB_URI = System.getenv("MONGODB_URI");
    21 private static final String DB_NAME = "<DATABASE-NAME>";
    22 private static final String COLLECTION_NAME = "<COLLECTION-NAME>";
    23 private static final String INDEX_NAME = "<INDEX-NAME>";
    24
    25 public static void main(String[] args) {
    26 try (MongoClient mongoClient = MongoClients.create(MONGODB_URI)) {
    27 storeEmbeddings(mongoClient);
    28 setupVectorSearchIndex(mongoClient);
    29 } catch (IOException | InterruptedException e) {
    30 e.printStackTrace();
    31 }
    32 }
    33
    34 // Upload the documents in the file to the given MongoDB namespace
    35 public static void storeEmbeddings(MongoClient client) throws IOException {
    36 MongoDatabase database = client.getDatabase(DB_NAME);
    37 MongoCollection<Document> collection = database.getCollection(COLLECTION_NAME);
    38
    39 String fileContent = Files.readString(Path.of("embeddings.json"));
    40 List<Document> documents = parseDocuments(fileContent);
    41
    42 collection.insertMany(documents);
    43 System.out.println("Inserted documents into MongoDB");
    44 }
    45
    46 private static List<Document> parseDocuments(String jsonContent) throws IOException {
    47 Document rootDoc = Document.parse(jsonContent);
    48 return rootDoc.getList("data", Document.class);
    49 }
    50
    51 // Create the Vector Search index
    52 public static void setupVectorSearchIndex(MongoClient client) throws InterruptedException {
    53 MongoDatabase database = client.getDatabase(DB_NAME);
    54 MongoCollection<Document> collection = database.getCollection(COLLECTION_NAME);
    55
    56 Bson definition = new Document(
    57 "fields",
    58 List.of(
    59 new Document("type", "vector")
    60 .append("path", "embeddings_float32")
    61 .append("numDimensions", 1024)
    62 .append("similarity", "dotProduct"),
    63 new Document("type", "vector")
    64 .append("path", "embeddings_int8")
    65 .append("numDimensions", 1024)
    66 .append("similarity", "dotProduct"),
    67 new Document("type", "vector")
    68 .append("path", "embeddings_int1")
    69 .append("numDimensions", 1024)
    70 .append("similarity", "euclidean")
    71 )
    72 );
    73
    74 SearchIndexModel indexModel = new SearchIndexModel(
    75 INDEX_NAME,
    76 definition,
    77 SearchIndexType.vectorSearch()
    78 );
    79
    80 List<String> result = collection.createSearchIndexes(Collections.singletonList(indexModel));
    81 System.out.println("Successfully created vector index named: " + result.get(0));
    82 System.out.println("It may take up to a minute for the index to leave the BUILDING status and become queryable.");
    83
    84 System.out.println("Polling to confirm the index has changed from the BUILDING status.");
    85 waitForIndex(collection, INDEX_NAME);
    86 }
    87
    88 // Wait for the index build to complete
    89 public static <T> boolean waitForIndex(final MongoCollection<T> collection, final String indexName) {
    90 long startTime = System.nanoTime();
    91 long timeoutNanos = TimeUnit.SECONDS.toNanos(60);
    92 while (System.nanoTime() - startTime < timeoutNanos) {
    93 Document indexRecord = StreamSupport.stream(collection.listSearchIndexes().spliterator(), false)
    94 .filter(index -> indexName.equals(index.getString("name")))
    95 .findAny().orElse(null);
    96 if (indexRecord != null) {
    97 if ("FAILED".equals(indexRecord.getString("status"))) {
    98 throw new RuntimeException("Search index has FAILED status.");
    99 }
    100 if (indexRecord.getBoolean("queryable")) {
    101 System.out.println(indexName + " index is ready to query");
    102 return true;
    103 }
    104 }
    105 try {
    106 Thread.sleep(100); // busy-wait, avoid in production
    107 } catch (InterruptedException e) {
    108 Thread.currentThread().interrupt();
    109 throw new RuntimeException(e);
    110 }
    111 }
    112 return false;
    113 }
    114}
  3. Substitua os seguintes valores de espaço reservado no código e salve o arquivo.

    <DATABASE-NAME>

    Nome do banco de dados no seu cluster do Atlas.

    <COLLECTION-NAME>

    Nome da coleção em que você deseja carregar os dados.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    javac UploadDataAndCreateIndex.java
    java UploadDataAndCreateIndex
    Inserted documents into MongoDB
    Successfully created vector index named: <INDEX_NAME>
    It may take up to a minute for the index to leave the BUILDING status and become queryable.
    Polling to confirm the index has changed from the BUILDING status.
    <INDEX_NAME> index is ready to query
  5. Conecte-se no cluster do Atlas e verifique o seguinte:

    • Dados no namespace.

    • Índice do Atlas Vector Search para a coleção.

5

Para testar suas incorporações, você pode executar uma query em sua coleção. Utilize um fornecedor de modelo de incorporação para gerar float int8 int1 incorporações, e para seu texto de query. O código de exemplo a seguir usa voyage-3-large a API REST da Voyage AI para gerar vetores de precisão total. Depois de gerar as incorporações, use o driver Java do MongoDB para converter sua incorporação de vetor nativo em vetores BSON e execute $vectorSearch a query na coleção.

  1. Crie um novo arquivo chamado CreateEmbeddingsAndRunQuery.java em seu projeto Java.

    touch CreateEmbeddingsAndRunQuery.java
  2. Copie e cole o seguinte código no arquivo CreateEmbeddingsAndRunQuery.java.

    Este código faz o seguinte:

    • Gera as incorporações de vetor float32, int8 e ubinary usando o modelo de incorporação voyage-3-large da Voyage AI.

    • Converte as incorporações em vetores BSON binData usando o driver Java do MongoDB.

    • Executa a query em relação à sua coleção.

    CreateEmbeddingsAndRunQuery.java
    1import okhttp3.*;
    2import com.mongodb.client.MongoClient;
    3import com.mongodb.client.MongoClients;
    4import com.mongodb.client.MongoCollection;
    5import com.mongodb.client.MongoDatabase;
    6import org.bson.BinaryVector;
    7import org.bson.Document;
    8import org.bson.conversions.Bson;
    9import org.json.JSONArray;
    10import org.json.JSONObject;
    11
    12import java.io.IOException;
    13import java.util.*;
    14import java.util.concurrent.TimeUnit;
    15
    16import static com.mongodb.client.model.Aggregates.project;
    17import static com.mongodb.client.model.Aggregates.vectorSearch;
    18import static com.mongodb.client.model.Projections.fields;
    19import static com.mongodb.client.model.Projections.include;
    20import static com.mongodb.client.model.Projections.exclude;
    21import static com.mongodb.client.model.Projections.metaVectorSearchScore;
    22import static com.mongodb.client.model.search.SearchPath.fieldPath;
    23import static com.mongodb.client.model.search.VectorSearchOptions.approximateVectorSearchOptions;
    24import static java.util.Arrays.asList;
    25
    26public class CreateEmbeddingsAndRunQuery {
    27
    28 // Configurations
    29 private static final String VOYAGE_API_KEY = System.getenv("VOYAGE_API_KEY");
    30 private static final String MONGODB_URI = System.getenv("MONGODB_URI");
    31 private static final String DB_NAME = "<DATABASE-NAME>";
    32 private static final String COLLECTION_NAME = "<COLLECTION-NAME>";
    33 private static final String VECTOR_INDEX_NAME = "<INDEX-NAME>";
    34 private static final String DATA_FIELD_NAME = "<DATA-FIELD-NAME>";
    35 private static final String QUERY_TEXT = "<QUERY-TEXT>";
    36
    37 // Voyage AI API Endpoint
    38 private static final String VOYAGE_API_URL = "https://api.voyageai.com/v1/embeddings";
    39
    40 // Timeout values for API requests
    41 private static final int CONNECTION_TIMEOUT = 30;
    42 private static final int READ_TIMEOUT = 60;
    43
    44 public static void main(String[] args) {
    45 if (VOYAGE_API_KEY == null || VOYAGE_API_KEY.isEmpty()) {
    46 throw new RuntimeException("API key not found. Set VOYAGE_API_KEY in your environment.");
    47 }
    48 if (MONGODB_URI == null || MONGODB_URI.isEmpty()) {
    49 throw new RuntimeException("MongoDB URI not found. Set MONGODB_URI in your environment.");
    50 }
    51
    52 String queryText = <QUERY-TEXT>; // Query text dynamically provided by the user
    53
    54 try {
    55 CreateEmbeddingsAndRunQuery processor = new CreateEmbeddingsAndRunQuery();
    56
    57 System.out.println("Fetching embeddings...");
    58 Document bsonEmbeddings = processor.fetchEmbeddingsForQuery(queryText);
    59
    60 System.out.println("Using embeddings in vector search queries...");
    61 processor.runVectorSearchQuery(bsonEmbeddings);
    62
    63 } catch (Exception e) {
    64 e.printStackTrace();
    65 }
    66 }
    67
    68 // Fetch embeddings from Voyage AI API for multiple output data types
    69 private Document fetchEmbeddingsForQuery(String queryText) {
    70 OkHttpClient client = new OkHttpClient.Builder()
    71 .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
    72 .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
    73 .build();
    74
    75 List<List<List<Integer>>> embeddingsByOutputType = new ArrayList<>();
    76 List<String> outputDtypes = List.of("float", "int8", "ubinary"); // Supported output data types
    77
    78 try {
    79 for (String dtype : outputDtypes) {
    80 String responseBody = sendRequest(client, VOYAGE_API_KEY, queryText, dtype);
    81 embeddingsByOutputType.add(parseEmbeddings(responseBody, dtype));
    82 }
    83 } catch (IOException e) {
    84 throw new RuntimeException("Error fetching embeddings: " + e.getMessage(), e);
    85 }
    86
    87 return convertEmbeddingsToBson(queryText, embeddingsByOutputType); // Convert embeddings to BSON format
    88 }
    89
    90 // Send API request to Voyage AI to generate embeddings for a specific output data type
    91 private String sendRequest(OkHttpClient client, String apiKey, String queryText, String outputDtype) throws IOException {
    92 String requestBody = new JSONObject()
    93 .put("input", List.of(queryText)) // Dynamic user query text as input
    94 .put("model", "voyage-3-large") // Model type
    95 .put("input_type", "query") // Input type for query
    96 .put("output_dtype", outputDtype)
    97 .toString();
    98
    99 Request request = new Request.Builder()
    100 .url(VOYAGE_API_URL)
    101 .post(RequestBody.create(requestBody, MediaType.get("application/json")))
    102 .addHeader("Authorization", "Bearer " + apiKey)
    103 .build();
    104
    105 try (Response response = client.newCall(request).execute()) {
    106 if (!response.isSuccessful()) {
    107 throw new IOException("API error: HTTP " + response.code());
    108 }
    109 return response.body().string();
    110 }
    111 }
    112
    113 // Parse embeddings from API response
    114 private static List<List<Integer>> parseEmbeddings(String responseBody, String outputDtype) {
    115 JSONObject responseJson = new JSONObject(responseBody);
    116 JSONArray dataArray = responseJson.optJSONArray("data");
    117
    118 if (dataArray == null) {
    119 throw new RuntimeException("Invalid response format: 'data' field missing.");
    120 }
    121
    122 List<List<Integer>> embeddings = new ArrayList<>();
    123 for (int i = 0; i < dataArray.length(); i++) {
    124 JSONArray embeddingVector = dataArray.getJSONObject(i).getJSONArray("embedding");
    125
    126 List<Integer> vector = new ArrayList<>();
    127 for (int j = 0; j < embeddingVector.length(); j++) {
    128 int value = embeddingVector.getInt(j);
    129
    130 // Handle binary quantization offset
    131 if ("binary".equals(outputDtype)) {
    132 value = value - 128; // Offset binary method (signed int8 representation)
    133 }
    134
    135 vector.add(value);
    136 }
    137 embeddings.add(vector);
    138 }
    139 return embeddings;
    140 }
    141
    142 // Convert embeddings into BSON format
    143 private Document convertEmbeddingsToBson(String queryText, List<List<List<Integer>>> embeddingsByOutputType) {
    144 Document embedding = new Document()
    145 .append("text", queryText)
    146 .append("embeddings_float32", BinaryVector.floatVector(listToFloatArray(embeddingsByOutputType.get(0).get(0))))
    147 .append("embeddings_int8", BinaryVector.int8Vector(listToByteArray(embeddingsByOutputType.get(1).get(0))))
    148 .append("embeddings_int1", BinaryVector.packedBitVector(listToByteArray(embeddingsByOutputType.get(2).get(0)), (byte) 0));
    149
    150 return new Document("data", List.of(embedding));
    151 }
    152
    153 // Run MongoDB vector search query using the generated embeddings
    154 private void runVectorSearchQuery(Document bsonEmbeddings) {
    155 try (MongoClient mongoClient = MongoClients.create(MONGODB_URI)) {
    156 MongoDatabase database = mongoClient.getDatabase(DB_NAME);
    157 MongoCollection<Document> collection = database.getCollection(COLLECTION_NAME);
    158
    159 List<Document> embeddedDocuments = bsonEmbeddings.getList("data", Document.class);
    160
    161 for (Document embedding : embeddedDocuments) {
    162 for (String embeddingType : List.of("embeddings_float32", "embeddings_int8", "embeddings_int1")) {
    163 System.out.println("Results from " + embeddingType.replace("embeddings_", "") + " embeddings:");
    164
    165 List<Bson> pipeline = asList(
    166 vectorSearch(
    167 fieldPath(embeddingType),
    168 embedding.get(embeddingType, BinaryVector.class),
    169 VECTOR_INDEX_NAME,
    170 2, approximateVectorSearchOptions(5)
    171 ),
    172 project(fields(
    173 exclude("_id"),
    174 include(DATA_FIELD_NAME),
    175 metaVectorSearchScore("vectorSearchScore"))));
    176
    177 List<Document> results = collection.aggregate(pipeline).into(new ArrayList<>());
    178
    179 for (Document result : results) {
    180 System.out.println(result.toJson());
    181 }
    182 }
    183 }
    184 }
    185 }
    186
    187 private static float[] listToFloatArray(List<Integer> list) {
    188 float[] array = new float[list.size()];
    189 for (int i = 0; i < list.size(); i++) {
    190 array[i] = list.get(i).floatValue();
    191 }
    192 return array;
    193 }
    194
    195 private static byte[] listToByteArray(List<Integer> list) {
    196 byte[] array = new byte[list.size()];
    197 for (int i = 0; i < list.size(); i++) {
    198 array[i] = list.get(i).byteValue();
    199 }
    200 return array;
    201 }
    202}
  3. Substitua os seguintes valores de espaço reservado no código e salve o arquivo.

    <DATABASE-NAME>

    Nome do banco de dados no seu cluster do Atlas.

    <COLLECTION-NAME>

    Nome da coleção em que você fez a ingestão dos dados.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

    <DATA-FIELD-NAME>

    Nome do campo que contém o texto a partir do qual você gerou as incorporações. Para este exemplo, use text.

    <QUERY-TEXT>

    Texto para a query. Para este exemplo, use science fact.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    javac CreateEmbeddingsAndRunQuery.java
    java CreateEmbeddingsAndRunQuery
    Fetching embeddings...
    Using embeddings in vector search queries...
    {"text": "The Great Wall of China is visible from space.", "vectorSearchScore": 0.5}
    {"text": "The Eiffel Tower was completed in Paris in 1889.", "vectorSearchScore": 0.5}
    Results from int8 embeddings:
    {"text": "The Great Wall of China is visible from space.", "vectorSearchScore": 0.5051995515823364}
    {"text": "Mount Everest is the highest peak on Earth at 8,848m.", "vectorSearchScore": 0.5044659972190857}
    Results from int1 embeddings:
    {"text": "The Great Wall of China is visible from space.", "vectorSearchScore": 0.6845703125}
    {"text": "Mount Everest is the highest peak on Earth at 8,848m.", "vectorSearchScore": 0.6650390625}

Para aprender mais sobre como gerar incorporações e convertê-las em vetores binData, veja Como criar incorporações vetoriais.

1
  1. No seu IDE, crie um projeto Java usando Maven ou Gradle.

  2. Adicione as seguintes dependências, dependendo do seu gerenciador de pacotes:

    Se você estiver utilizando o Maven, adicione as seguintes dependências à array dependencies no arquivo pom.xml do seu projeto:

    <dependencies>
    <dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.mongodb</groupId>
    <artifactId>mongodb-driver-sync</artifactId>
    <version>5.3.1</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-api</artifactId>
    <version>2.0.16</version>
    </dependency>
    <dependency>
    <groupId>org.slf4j</groupId>
    <artifactId>slf4j-simple</artifactId>
    <version>2.0.16</version>
    <scope>test</scope>
    </dependency>
    <dependency>
    <groupId>org.json</groupId>
    <artifactId>json</artifactId>
    <version>20250517</version>
    </dependency>
    <dependency>
    <groupId>com.squareup.okhttp3</groupId>
    <artifactId>okhttp</artifactId>
    <version>4.12.0</version>
    </dependency>
    </dependencies>

    Se você estiver usando o Gradle, adicione o seguinte à array dependencies no arquivo build.gradle do seu projeto:

    build.gradle
    dependencies {
    // JUnit for testing
    testImplementation 'junit:junit:3.8.1'
    // MongoDB synchronous driver
    implementation 'org.mongodb:mongodb-driver-sync:5.3.1'
    // SLF4J API for logging
    implementation 'org.slf4j:slf4j-api:2.0.16'
    // SLF4J Simple Logger (scope: test)
    testImplementation 'org.slf4j:slf4j-simple:2.0.16'
    // JSON library
    implementation 'org.json:json:20210307'
    // HTTP client for Java
    implementation 'com.squareup.okhttp3:okhttp:4.12.0' // Or the latest version
    }
  3. Execute seu gerenciador de pacote para instalar as dependências em seu projeto.

2

Observação

Este exemplo define as variáveis do projeto no IDE. Os aplicativos de produção podem gerenciar variáveis de ambiente por meio de uma configuração de sistema, pipeline CI/CD ou gerenciador de segredos, mas você pode adaptar o código fornecido para se adequar ao seu caso de uso.

No seu IDE, crie um novo modelo de configuração e adicione as seguintes variáveis ao seu projeto:

Variáveis de ambiente
VOYAGE_API_KEY=<api-key>
MONGODB_URI=<connection-string>

Atualize os espaços reservados com os seguintes valores:

  • Substitua o valor do espaço reservado <api-key> pela chave API do Voyage AI.

  • Substitua o <connection-string> valor do espaço reservado pela string de conexão SRVdo seu Atlas cluster.

    Sua string de conexão deve usar o seguinte formato:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
3

Você pode usar um fornecedor de modelo de incorporação para gerar float int8incorporações, e int1 para seus dados e, em seguida, usar o driver Java do MongoDB para converter sua incorporação de vetor nativo em vetores BSON. O código de amostra a seguir usa a API REST da Voyage AI para gerar vetores de precisão total a partir dos dados no sample_airbnb.listingsAndReviews namespace .

  1. Crie um novo arquivo chamado GenerateAndConvertEmbeddings.java em seu projeto Java.

    touch GenerateAndConvertEmbeddings.java
  2. Copie e cole o seguinte código no arquivo GenerateAndConvertEmbeddings.java.

    Este código faz o seguinte:

    • Obtém o campo summary dos documentos 50 no namespace sample_airbnb.listingsAndReviews.

    • Gera as incorporações de vetor float32, int8 e ubinary usando o modelo de incorporação voyage-3-large da Voyage AI.

    • Converte as incorporações em vetores BSON binData usando o driver Java do MongoDB.

    • Cria um arquivo chamado embeddings.json e salva os dados com as incorporações no arquivo.

    GenerateAndConvertEmbeddings.java
    1import okhttp3.*;
    2
    3import com.mongodb.client.FindIterable;
    4import com.mongodb.client.MongoClient;
    5import com.mongodb.client.MongoClients;
    6import com.mongodb.client.MongoCollection;
    7import com.mongodb.client.MongoDatabase;
    8import org.bson.Document;
    9import org.bson.BinaryVector;
    10import org.slf4j.Logger;
    11import org.slf4j.LoggerFactory;
    12import org.json.JSONArray;
    13import org.json.JSONObject;
    14
    15import java.io.FileOutputStream;
    16import java.io.IOException;
    17import java.util.*;
    18import java.util.concurrent.TimeUnit;
    19
    20public class GenerateAndConvertEmbeddings {
    21 private static final Logger logger = LoggerFactory.getLogger(GenerateAndConvertEmbeddings.class);
    22
    23 // Configuration settings
    24 private static final String VOYAGE_API_URL = "https://api.voyageai.com/v1/embeddings"; // Voyage AI API URL
    25 private static final String VOYAGE_API_KEY = System.getenv("VOYAGE_API_KEY"); // Voyage API key
    26 private static final String MONGODB_URI = System.getenv("MONGODB_URI"); // MongoDB connection URI
    27
    28 // Timeout values for API requests
    29 private static final int CONNECTION_TIMEOUT = 30; // Timeout for API requests
    30 private static final int READ_TIMEOUT = 60; // Timeout for API responses
    31
    32 public static void main(String[] args) {
    33 try {
    34 List<String> summaries = fetchSummariesFromMongoDB();
    35 if (summaries.isEmpty()) {
    36 throw new RuntimeException("No summaries retrieved from MongoDB.");
    37 }
    38
    39 Document bsonEmbeddings = fetchEmbeddingsFromVoyage(summaries, VOYAGE_API_KEY);
    40 if (bsonEmbeddings == null || bsonEmbeddings.isEmpty()) {
    41 throw new RuntimeException("Failed to fetch embeddings.");
    42 }
    43
    44 convertAndSaveEmbeddings(bsonEmbeddings);
    45 } catch (Exception e) {
    46 logger.error("Unexpected error: {}", e.getMessage(), e);
    47 }
    48 }
    49
    50 // Fetch summaries from MongoDB collection
    51 private static List<String> fetchSummariesFromMongoDB() {
    52 List<String> summaries = new ArrayList<>();
    53 if (MONGODB_URI == null || MONGODB_URI.isEmpty()) {
    54 throw new RuntimeException("MongoDB URI is not set.");
    55 }
    56 logger.info("Connecting to MongoDB at URI: {}", MONGODB_URI);
    57
    58 try (MongoClient mongoClient = MongoClients.create(MONGODB_URI)) {
    59 String dbName = "sample_airbnb";
    60 String collName = "listingsAndReviews";
    61 MongoDatabase database = mongoClient.getDatabase(dbName);
    62 MongoCollection<Document> collection = database.getCollection(collName);
    63
    64 // Filter to exclude null or empty summaries
    65 Document filter = new Document("summary", new Document("$nin", Arrays.asList(null, "")));
    66 FindIterable<Document> documentsCursor = collection.find(filter).limit(50);
    67
    68 for (Document doc : documentsCursor) {
    69 String summary = doc.getString("summary");
    70 if (summary != null && !summary.isEmpty()) {
    71 summaries.add(summary);
    72 }
    73 }
    74 logger.info("Retrieved {} summaries from MongoDB.", summaries.size());
    75 } catch (Exception e) {
    76 logger.error("Error fetching from MongoDB: {}", e.getMessage(), e);
    77 throw new RuntimeException("Failed to fetch data from MongoDB", e);
    78 }
    79 return summaries;
    80 }
    81
    82 // Fetch embeddings from Voyage AI API for the given data input
    83 private static Document fetchEmbeddingsFromVoyage(List<String> data, String apiKey) {
    84 if (apiKey == null || apiKey.isEmpty()) {
    85 throw new RuntimeException("API key is not set.");
    86 }
    87
    88 OkHttpClient client = new OkHttpClient.Builder()
    89 .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
    90 .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
    91 .build();
    92
    93 List<List<List<Integer>>> embeddingsByOutputType = new ArrayList<>();
    94 List<String> outputDtypes = List.of("float", "int8", "ubinary");
    95
    96 try {
    97 for (String dtype : outputDtypes) {
    98 String responseBody = sendRequest(client, apiKey, data, dtype);
    99 embeddingsByOutputType.add(parseEmbeddings(responseBody, dtype));
    100 }
    101 } catch (IOException e) {
    102 logger.error("Error fetching embeddings: {}", e.getMessage(), e);
    103 throw new RuntimeException("Error fetching embeddings from Voyage AI.", e);
    104 }
    105
    106 // Convert embeddings to BSON
    107 return convertEmbeddingsToBson(data, embeddingsByOutputType);
    108 }
    109
    110 // Send API request to Voyage AI
    111 private static String sendRequest(OkHttpClient client, String apiKey, List<String> inputData, String outputDtype) throws IOException {
    112 String requestBody = new JSONObject()
    113 .put("input", inputData)
    114 .put("model", "voyage-3-large")
    115 .put("input_type", "document")
    116 .put("output_dtype", outputDtype)
    117 .put("output_dimension", 1024)
    118 .toString();
    119
    120 Request request = new Request.Builder()
    121 .url(VOYAGE_API_URL)
    122 .post(RequestBody.create(requestBody, MediaType.get("application/json")))
    123 .addHeader("Authorization", "Bearer " + apiKey)
    124 .build();
    125
    126 try (Response response = client.newCall(request).execute()) {
    127 if (!response.isSuccessful()) {
    128 throw new IOException("API error: HTTP " + response.code());
    129 }
    130 return response.body().string();
    131 }
    132 }
    133
    134 // Parse embeddings from Voyage AI API response
    135 private static List<List<Integer>> parseEmbeddings(String responseBody, String outputDtype) {
    136 JSONObject responseJson = new JSONObject(responseBody);
    137 JSONArray dataArray = responseJson.optJSONArray("data");
    138
    139 if (dataArray == null) {
    140 throw new RuntimeException("Invalid response format: 'data' field missing.");
    141 }
    142
    143 List<List<Integer>> embeddings = new ArrayList<>();
    144 for (int i = 0; i < dataArray.length(); i++) {
    145 JSONArray embeddingVector = dataArray.getJSONObject(i).getJSONArray("embedding");
    146
    147 List<Integer> vector = new ArrayList<>();
    148 for (int j = 0; j < embeddingVector.length(); j++) {
    149 int value = embeddingVector.getInt(j);
    150
    151 // Handle binary quantization offset for signed int8 representations
    152 if ("binary".equals(outputDtype)) {
    153 value = value - 128; // Offset binary method
    154 }
    155
    156 vector.add(value);
    157 }
    158 embeddings.add(vector);
    159 }
    160 return embeddings;
    161 }
    162
    163 // Convert fetched embeddings into BSON format
    164 private static Document convertEmbeddingsToBson(List<String> inputData, List<List<List<Integer>>> embeddingsByOutputType) {
    165 List<Document> bsonEmbeddings = new ArrayList<>();
    166 for (int i = 0; i < inputData.size(); i++) {
    167 Document embedding = new Document()
    168 .append("text", inputData.get(i))
    169 .append("embeddings_float32", BinaryVector.floatVector(listToFloatArray(embeddingsByOutputType.get(0).get(i))))
    170 .append("embeddings_int8", BinaryVector.int8Vector(listToByteArray(embeddingsByOutputType.get(1).get(i))))
    171 .append("embeddings_int1", BinaryVector.packedBitVector(listToByteArray(embeddingsByOutputType.get(2).get(i)), (byte) 0));
    172 bsonEmbeddings.add(embedding);
    173 }
    174 return new Document("data", bsonEmbeddings);
    175 }
    176
    177 // Save BSON embeddings to a JSON file
    178 private static void convertAndSaveEmbeddings(Document bsonEmbeddings) {
    179 try (FileOutputStream fos = new FileOutputStream("embeddings.json")) {
    180 fos.write(bsonEmbeddings.toJson().getBytes());
    181 logger.info("Embeddings with BSON vectors have been saved to embeddings.json");
    182 } catch (IOException e) {
    183 logger.error("Error writing embeddings to file: {}", e.getMessage(), e);
    184 }
    185 }
    186
    187 private static float[] listToFloatArray(List<Integer> list) {
    188 float[] array = new float[list.size()];
    189 for (int i = 0; i < list.size(); i++) {
    190 array[i] = list.get(i).floatValue();
    191 }
    192 return array;
    193 }
    194
    195 private static byte[] listToByteArray(List<Integer> list) {
    196 byte[] array = new byte[list.size()];
    197 for (int i = 0; i < list.size(); i++) {
    198 array[i] = list.get(i).byteValue();
    199 }
    200 return array;
    201 }
    202}
  3. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    javac GenerateAndConvertEmbeddings.java
    java GenerateAndConvertEmbeddings
    [main] INFO GenerateAndConvertEmbeddings - Connecting to MongoDB at URI: <CONNECTION-STRING>
    ...
    [main] INFO GenerateAndConvertEmbeddings - Retrieved 50 summaries from MongoDB.
    [main] INFO GenerateAndConvertEmbeddings - Embeddings with BSON vectors have been saved to embeddings.json
  4. Verifique as incorporações no arquivo embeddings.json.

Para aprender mais sobre como gerar incorporações e convertê-las em vetores binData, veja Como criar incorporações vetoriais.

4

Você deve carregar seus dados e incorporações em uma coleção no cluster do Atlas e criar um índice Atlas Vector Search nos dados para executar queries $vectorSearch em relação aos dados.

  1. Crie um novo arquivo chamado UploadDataAndCreateIndex.java em seu projeto Java.

    touch UploadDataAndCreateIndex.java
  2. Copie e cole o seguinte código no arquivo UploadDataAndCreateIndex.java.

    Este código faz o seguinte:

    • Carrega as incorporações float32, int8 e int1 no arquivo embeddings.json para o seu cluster do Atlas.

    • Cria um índice do Atlas Vector Search nos campos embeddings.float32, embeddings.int8 e embeddings.int1.

    UploadDataAndCreateIndex.java
    1import com.mongodb.client.MongoClient;
    2import com.mongodb.client.MongoClients;
    3import com.mongodb.client.MongoCollection;
    4import com.mongodb.client.MongoDatabase;
    5import com.mongodb.client.model.SearchIndexModel;
    6import com.mongodb.client.model.SearchIndexType;
    7
    8import org.bson.Document;
    9import org.bson.conversions.Bson;
    10import org.bson.BinaryVector; // Import the BinaryVector
    11
    12import java.io.IOException;
    13import java.nio.file.Files;
    14import java.nio.file.Path;
    15import java.util.Collections;
    16import java.util.List;
    17import java.util.concurrent.TimeUnit;
    18import java.util.stream.StreamSupport;
    19
    20public class UploadDataAndCreateIndex {
    21
    22 private static final String MONGODB_URI = System.getenv("MONGODB_URI");
    23 private static final String DB_NAME = "<DATABASE-NAME>";
    24 private static final String COLLECTION_NAME = "<COLLECTION-NAME>";
    25 private static final String INDEX_NAME = "<INDEX-NAME>";
    26
    27 public static void main(String[] args) {
    28 try (MongoClient mongoClient = MongoClients.create(MONGODB_URI)) {
    29 uploadEmbeddingsData(mongoClient);
    30 setupVectorSearchIndex(mongoClient);
    31 } catch (Exception e) {
    32 e.printStackTrace();
    33 }
    34 }
    35
    36 // Upload the embeddings in the file to the given MongoDB namespace
    37 public static void uploadEmbeddingsData(MongoClient mongoClient) throws IOException {
    38 MongoDatabase database = mongoClient.getDatabase(DB_NAME);
    39 MongoCollection<Document> collection = database.getCollection(COLLECTION_NAME);
    40 String filePath = "embeddings.json";
    41 String fileContent = Files.readString(Path.of(filePath));
    42
    43 Document rootDoc = Document.parse(fileContent);
    44 List<Document> embeddingsDocs = rootDoc.getList("data", Document.class);
    45
    46 for (Document doc : embeddingsDocs) {
    47 // Retrieve the string value from the document
    48 String summary = doc.getString("text");
    49
    50 // Get the BinaryVector objects from the document
    51 BinaryVector embeddingsFloat32 = doc.get("embeddings_float32", BinaryVector.class);
    52 BinaryVector embeddingsInt8 = doc.get("embeddings_int8", BinaryVector.class);
    53 BinaryVector embeddingsInt1 = doc.get("embeddings_int1", BinaryVector.class);
    54
    55 // Create filter and update documents
    56 Document filter = new Document("summary", summary);
    57 Document update = new Document("$set", new Document("summary", summary)
    58 .append("embeddings_float32", embeddingsFloat32)
    59 .append("embeddings_int8", embeddingsInt8)
    60 .append("embeddings_int1", embeddingsInt1));
    61
    62 // Perform update operation with upsert option
    63 collection.updateOne(filter, update, new com.mongodb.client.model.UpdateOptions().upsert(true));
    64 System.out.println("Processed document with summary: " + summary);
    65 }
    66 }
    67
    68 // Create a Vector Search index
    69 public static void setupVectorSearchIndex(MongoClient client) throws InterruptedException {
    70 MongoDatabase database = client.getDatabase(DB_NAME);
    71 MongoCollection<Document> collection = database.getCollection(COLLECTION_NAME);
    72 // Define the index details
    73 Bson definition = new Document(
    74 "fields",
    75 List.of(
    76 new Document("type", "vector")
    77 .append("path", "embeddings_float32")
    78 .append("numDimensions", 1024)
    79 .append("similarity", "dotProduct"),
    80 new Document("type", "vector")
    81 .append("path", "embeddings_int8")
    82 .append("numDimensions", 1024)
    83 .append("similarity", "dotProduct"),
    84 new Document("type", "vector")
    85 .append("path", "embeddings_int1")
    86 .append("numDimensions", 1024)
    87 .append("similarity", "euclidean")
    88 )
    89 );
    90 // Define the index model
    91 SearchIndexModel indexModel = new SearchIndexModel(
    92 INDEX_NAME,
    93 definition,
    94 SearchIndexType.vectorSearch()
    95 );
    96 // Create the index using the defined model
    97 List<String> result = collection.createSearchIndexes(Collections.singletonList(indexModel));
    98 System.out.println("Successfully created vector index named: " + result.get(0));
    99 System.out.println("It may take up to a minute for the index to leave the BUILDING status and become queryable.");
    100 // Wait for Atlas to build the index
    101 System.out.println("Polling to confirm the index has changed from the BUILDING status.");
    102 waitForIndex(collection, INDEX_NAME);
    103 }
    104
    105 // Wait for the index build to complete
    106 public static <T> boolean waitForIndex(final MongoCollection<T> collection, final String indexName) {
    107 long startTime = System.nanoTime();
    108 long timeoutNanos = TimeUnit.SECONDS.toNanos(60);
    109 while (System.nanoTime() - startTime < timeoutNanos) {
    110 Document indexRecord = StreamSupport.stream(collection.listSearchIndexes().spliterator(), false)
    111 .filter(index -> indexName.equals(index.getString("name")))
    112 .findAny().orElse(null);
    113 if (indexRecord != null) {
    114 if ("FAILED".equals(indexRecord.getString("status"))) {
    115 throw new RuntimeException("Search index has FAILED status.");
    116 }
    117 if (indexRecord.getBoolean("queryable")) {
    118 System.out.println(indexName + " index is ready to query");
    119 return true;
    120 }
    121 }
    122 try {
    123 Thread.sleep(100); // busy-wait, avoid in production
    124 } catch (InterruptedException e) {
    125 Thread.currentThread().interrupt();
    126 throw new RuntimeException(e);
    127 }
    128 }
    129 return false;
    130 }
    131}
  3. Substitua o seguinte valor de espaço reservado no código e salve o arquivo.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    javac UploadDataAndCreateIndex.java
    java UploadDataAndCreateIndex
    Processed document with summary: ...
    ...
    Successfully created vector index named: <INDEX_NAME>
    It may take up to a minute for the index to leave the BUILDING status and become queryable.
    Polling to confirm the index has changed from the BUILDING status.
    <INDEX_NAME> index is ready to query
  5. Conecte-se no cluster do Atlas e verifique o seguinte:

    • Dados no namespace.

    • Índice do Atlas Vector Search para a coleção.

5

Para testar suas incorporações, você pode executar uma query em sua coleção. Utilize um fornecedor de modelo de incorporação para gerar float int8incorporações, e int1 para seu texto de query. O código de amostra a seguir usa a API REST da Voyage AI para gerar vetores de precisão total. Depois de gerar as incorporações, use o driver Java do MongoDB para converter sua incorporação de vetor nativo em vetores BSON e execute a query na $vectorSearch coleção.

  1. Crie um novo arquivo chamado CreateEmbeddingsAndRunQuery.java em seu projeto Java.

    touch CreateEmbeddingsAndRunQuery.java
  2. Copie e cole o seguinte código no arquivo CreateEmbeddingsAndRunQuery.java.

    Este código faz o seguinte:

    • Gera as incorporações de vetor float32, int8 e ubinary usando o modelo de incorporação voyage-3-large da Voyage AI.

    • Converte as incorporações em vetores BSON binData usando o driver Java do MongoDB.

    • Executa a query em relação à sua coleção e retorna os resultados.

    CreateEmbeddingsAndRunQuery.java
    1import okhttp3.*;
    2import com.mongodb.client.MongoClient;
    3import com.mongodb.client.MongoClients;
    4import com.mongodb.client.MongoCollection;
    5import com.mongodb.client.MongoDatabase;
    6import org.bson.BinaryVector;
    7import org.bson.Document;
    8import org.bson.conversions.Bson;
    9import org.json.JSONArray;
    10import org.json.JSONObject;
    11
    12import java.io.IOException;
    13import java.util.*;
    14import java.util.concurrent.TimeUnit;
    15
    16import static com.mongodb.client.model.Aggregates.project;
    17import static com.mongodb.client.model.Aggregates.vectorSearch;
    18import static com.mongodb.client.model.Projections.fields;
    19import static com.mongodb.client.model.Projections.include;
    20import static com.mongodb.client.model.Projections.exclude;
    21import static com.mongodb.client.model.Projections.metaVectorSearchScore;
    22import static com.mongodb.client.model.search.SearchPath.fieldPath;
    23import static com.mongodb.client.model.search.VectorSearchOptions.approximateVectorSearchOptions;
    24import static java.util.Arrays.asList;
    25
    26public class CreateEmbeddingsAndRunQuery {
    27
    28 // Configurations
    29 private static final String VOYAGE_API_KEY = System.getenv("VOYAGE_API_KEY");
    30 private static final String MONGODB_URI = System.getenv("MONGODB_URI");
    31 private static final String DB_NAME = "<DATABASE-NAME>";
    32 private static final String COLLECTION_NAME = "<COLLECTION-NAME>";
    33 private static final String VECTOR_INDEX_NAME = "<INDEX-NAME>";
    34 private static final String DATA_FIELD_NAME = "<DATA-FIELD-NAME>";
    35 private static final String QUERY_TEXT = "<QUERY-TEXT>";
    36
    37 // Voyage AI API Endpoint
    38 private static final String VOYAGE_API_URL = "https://api.voyageai.com/v1/embeddings";
    39
    40 // Timeout values for API requests
    41 private static final int CONNECTION_TIMEOUT = 30;
    42 private static final int READ_TIMEOUT = 60;
    43
    44 public static void main(String[] args) {
    45 if (VOYAGE_API_KEY == null || VOYAGE_API_KEY.isEmpty()) {
    46 throw new RuntimeException("API key not found. Set VOYAGE_API_KEY in your environment.");
    47 }
    48 if (MONGODB_URI == null || MONGODB_URI.isEmpty()) {
    49 throw new RuntimeException("MongoDB URI not found. Set MONGODB_URI in your environment.");
    50 }
    51
    52 String queryText = <QUERY-TEXT>; // Query text dynamically provided by the user
    53
    54 try {
    55 CreateEmbeddingsAndRunQuery processor = new CreateEmbeddingsAndRunQuery();
    56
    57 System.out.println("Fetching embeddings...");
    58 Document bsonEmbeddings = processor.fetchEmbeddingsForQuery(queryText);
    59
    60 System.out.println("Using embeddings in vector search queries...");
    61 processor.runVectorSearchQuery(bsonEmbeddings);
    62
    63 } catch (Exception e) {
    64 e.printStackTrace();
    65 }
    66 }
    67
    68 // Fetch embeddings from Voyage AI API for multiple output data types
    69 private Document fetchEmbeddingsForQuery(String queryText) {
    70 OkHttpClient client = new OkHttpClient.Builder()
    71 .connectTimeout(CONNECTION_TIMEOUT, TimeUnit.SECONDS)
    72 .readTimeout(READ_TIMEOUT, TimeUnit.SECONDS)
    73 .build();
    74
    75 List<List<List<Integer>>> embeddingsByOutputType = new ArrayList<>();
    76 List<String> outputDtypes = List.of("float", "int8", "ubinary"); // Supported output data types
    77
    78 try {
    79 for (String dtype : outputDtypes) {
    80 String responseBody = sendRequest(client, VOYAGE_API_KEY, queryText, dtype);
    81 embeddingsByOutputType.add(parseEmbeddings(responseBody, dtype));
    82 }
    83 } catch (IOException e) {
    84 throw new RuntimeException("Error fetching embeddings: " + e.getMessage(), e);
    85 }
    86
    87 return convertEmbeddingsToBson(queryText, embeddingsByOutputType); // Convert embeddings to BSON format
    88 }
    89
    90 // Send API request to Voyage AI to generate embeddings for a specific output data type
    91 private String sendRequest(OkHttpClient client, String apiKey, String queryText, String outputDtype) throws IOException {
    92 String requestBody = new JSONObject()
    93 .put("input", List.of(queryText)) // Dynamic user query text as input
    94 .put("model", "voyage-3-large") // Model type
    95 .put("input_type", "query") // Input type for query
    96 .put("output_dtype", outputDtype)
    97 .toString();
    98
    99 Request request = new Request.Builder()
    100 .url(VOYAGE_API_URL)
    101 .post(RequestBody.create(requestBody, MediaType.get("application/json")))
    102 .addHeader("Authorization", "Bearer " + apiKey)
    103 .build();
    104
    105 try (Response response = client.newCall(request).execute()) {
    106 if (!response.isSuccessful()) {
    107 throw new IOException("API error: HTTP " + response.code());
    108 }
    109 return response.body().string();
    110 }
    111 }
    112
    113 // Parse embeddings from API response
    114 private static List<List<Integer>> parseEmbeddings(String responseBody, String outputDtype) {
    115 JSONObject responseJson = new JSONObject(responseBody);
    116 JSONArray dataArray = responseJson.optJSONArray("data");
    117
    118 if (dataArray == null) {
    119 throw new RuntimeException("Invalid response format: 'data' field missing.");
    120 }
    121
    122 List<List<Integer>> embeddings = new ArrayList<>();
    123 for (int i = 0; i < dataArray.length(); i++) {
    124 JSONArray embeddingVector = dataArray.getJSONObject(i).getJSONArray("embedding");
    125
    126 List<Integer> vector = new ArrayList<>();
    127 for (int j = 0; j < embeddingVector.length(); j++) {
    128 int value = embeddingVector.getInt(j);
    129
    130 // Handle binary quantization offset
    131 if ("binary".equals(outputDtype)) {
    132 value = value - 128; // Offset binary method (signed int8 representation)
    133 }
    134
    135 vector.add(value);
    136 }
    137 embeddings.add(vector);
    138 }
    139 return embeddings;
    140 }
    141
    142 // Convert embeddings into BSON format
    143 private Document convertEmbeddingsToBson(String queryText, List<List<List<Integer>>> embeddingsByOutputType) {
    144 Document embedding = new Document()
    145 .append("text", queryText)
    146 .append("embeddings_float32", BinaryVector.floatVector(listToFloatArray(embeddingsByOutputType.get(0).get(0))))
    147 .append("embeddings_int8", BinaryVector.int8Vector(listToByteArray(embeddingsByOutputType.get(1).get(0))))
    148 .append("embeddings_int1", BinaryVector.packedBitVector(listToByteArray(embeddingsByOutputType.get(2).get(0)), (byte) 0));
    149
    150 return new Document("data", List.of(embedding));
    151 }
    152
    153 // Run MongoDB vector search query using the generated embeddings
    154 private void runVectorSearchQuery(Document bsonEmbeddings) {
    155 try (MongoClient mongoClient = MongoClients.create(MONGODB_URI)) {
    156 MongoDatabase database = mongoClient.getDatabase(DB_NAME);
    157 MongoCollection<Document> collection = database.getCollection(COLLECTION_NAME);
    158
    159 List<Document> embeddedDocuments = bsonEmbeddings.getList("data", Document.class);
    160
    161 for (Document embedding : embeddedDocuments) {
    162 for (String embeddingType : List.of("embeddings_float32", "embeddings_int8", "embeddings_int1")) {
    163 System.out.println("Results from " + embeddingType.replace("embeddings_", "") + " embeddings:");
    164
    165 List<Bson> pipeline = asList(
    166 vectorSearch(
    167 fieldPath(embeddingType),
    168 embedding.get(embeddingType, BinaryVector.class),
    169 VECTOR_INDEX_NAME,
    170 2, approximateVectorSearchOptions(5)
    171 ),
    172 project(fields(
    173 exclude("_id"),
    174 include(DATA_FIELD_NAME),
    175 metaVectorSearchScore("vectorSearchScore"))));
    176
    177 List<Document> results = collection.aggregate(pipeline).into(new ArrayList<>());
    178
    179 for (Document result : results) {
    180 System.out.println(result.toJson());
    181 }
    182 }
    183 }
    184 }
    185 }
    186
    187 private static float[] listToFloatArray(List<Integer> list) {
    188 float[] array = new float[list.size()];
    189 for (int i = 0; i < list.size(); i++) {
    190 array[i] = list.get(i).floatValue();
    191 }
    192 return array;
    193 }
    194
    195 private static byte[] listToByteArray(List<Integer> list) {
    196 byte[] array = new byte[list.size()];
    197 for (int i = 0; i < list.size(); i++) {
    198 array[i] = list.get(i).byteValue();
    199 }
    200 return array;
    201 }
    202}
  3. Substitua os seguintes valores de espaço reservado no código e salve o arquivo.

    <DATABASE-NAME>

    Nome do banco de dados no seu cluster do Atlas. Para este exemplo, use sample_airbnb.

    <COLLECTION-NAME>

    Nome da coleção em que você fez a ingestão dos dados. Para este exemplo, use listingsAndReviews.

    <INDEX-NAME>

    Nome do índice do Atlas Vector Search para a coleção.

    <DATA-FIELD-NAME>

    Nome do campo que contém o texto a partir do qual você gerou as incorporações. Para este exemplo, use summary.

    <QUERY-TEXT>

    Texto para a query. Para este exemplo, use ocean view.

  4. Compile e execute o arquivo usando a configuração de execução do seu aplicativo.

    Se você estiver usando um terminal, execute os seguintes comandos para compilar e executar seu programa.

    javac CreateEmbeddingsAndRunQuery.java
    java CreateEmbeddingsAndRunQuery
    Fetching embeddings...
    Using embeddings in vector search queries...
    Results from float32 embeddings:
    {"summary": "Fantastic duplex apartment with three bedrooms, located in the historic area of Porto, Ribeira (Cube) - UNESCO World Heritage Site. Centenary building fully rehabilitated, without losing their original character.", "vectorSearchScore": 0.5}
    {"summary": "One bedroom + sofa-bed in quiet and bucolic neighbourhood right next to the Botanical Garden. Small garden, outside shower, well equipped kitchen and bathroom with shower and tub. Easy for transport with many restaurants and basic facilities in the area.", "vectorSearchScore": 0.5}
    Results from int8 embeddings:
    {"summary": "A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.", "vectorSearchScore": 0.5056195259094238}
    {"summary": "THIS IS A VERY SPACIOUS 1 BEDROOM FULL CONDO (SLEEPS 4) AT THE BEAUTIFUL VALLEY ISLE RESORT ON THE BEACH IN LAHAINA, MAUI!! YOU WILL LOVE THE PERFECT LOCATION OF THIS VERY NICE HIGH RISE! ALSO THIS SPACIOUS FULL CONDO, FULL KITCHEN, BIG BALCONY!!", "vectorSearchScore": 0.5048412084579468}
    Results from int1 embeddings:
    {"summary": "A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.", "vectorSearchScore": 0.7119140625}
    {"summary": "A short distance from Honolulu's billion dollar mall, and the same distance to Waikiki. Parking included. A great location that work perfectly for business, education, or simple visit. Experience Yacht Harbor views and 5 Star Hilton Hawaiian Village.", "vectorSearchScore": 0.6787109375}

Para aprender mais sobre como gerar incorporações e convertê-las em vetores binData, veja Como criar incorporações vetoriais.

1

Configure seu projeto para usar módulos ES adicionando "type": "module" ao seu arquivo package.json e salvando-o.

{
"type": "module",
// other fields...
}
2

Execute o seguinte comando para instalar o Driver MongoDB Node.js e o dotenv pacote. Esta operação pode levar alguns minutos para ser concluída.

npm install mongodb dotenv

Você deve instalar o driver Node.js v6.11 ou posterior.

Se necessário, você também deve instalar bibliotecas do fornecedor do modelo de incorporação. Neste tutorial, você usa a API REST do Voyage AI para gerar incorporações. Portanto, você não precisa instalar nenhuma biblioteca adicional para o Voyage AI.

3

Em uma janela de terminal, execute os seguintes comandos para criar um novo diretório chamado my-quantization-project e inicializar seu projeto:

mkdir my-quantization-project
cd my-quantization-project
npm init -y
4
  1. Para acessar o provedor de modelo de incorporação para gerar e converter incorporações, configure a variável de ambiente para a chave de API do provedor de modelo de incorporação, se necessário.

    Para utilizar incorporações da Voyage AI, configure a variável de ambiente do VOYAGE_API_KEY.

    export VOYAGE_API_KEY="<VOYAGEAI-API-KEY>"

    Caso não defina a variável de ambiente, substitua o <VOYAGE-API-KEY> no código de exemplo pela chave de API antes de executar o código.

  2. Para acessar o cluster Atlas, defina a variável de ambiente MONGODB_URI.

    export MONGODB_URI="<CONNECTION-STRING>"

    Sua string de conexão deve estar no seguinte formato:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net

    Caso você não configure a variável de ambiente, substitua o <CONNECTION-STRING> no código de exemplo pela sua string de conexão antes de executar o código.

5
  1. Crie um arquivo chamado get-embeddings.js float32int8para int1 gerar incorporações vetoriais,embed e usando a API da Voyage AI .

    touch get-embeddings.js
  2. Copie e cole o seguinte código no arquivo get-embeddings.js.

    Este código faz o seguinte:

    • Gera float32 incorporações, int8 e int1 para os dados fornecidos usando o modelo de incorporação voyage-3-large da Voyage AI.

    • Armazena as incorporações float32, int8 e int1 em campos chamados float, int8 e ubinary, respectivamente.

    • Cria um arquivo chamado embeddings.json e salva as incorporações no arquivo.

    get-embeddings.js
    1import { writeFile } from "fs/promises"; // For saving JSON files
    2
    3// Retrieve API key from environment or use placeholder value
    4const apiKey = process.env.VOYAGE_API_KEY || "<VOYAGE-API-KEY>";
    5
    6if (!apiKey || apiKey === "<VOYAGE-API-KEY>") {
    7 throw new Error("API key not found. Please set VOYAGE_API_KEY in your environment.");
    8}
    9
    10// Define the Voyage AI REST API endpoint
    11const apiEndpoint = "https://api.voyageai.com/v1/embeddings";
    12
    13/**
    14 * Fetch embeddings using Voyage AI REST API for a specific data type (output_dtype)
    15 */
    16async function fetchEmbeddings(data, model, outputDtype, dimension) {
    17 const response = await fetch(apiEndpoint, {
    18 method: "POST",
    19 headers: {
    20 "Content-Type": "application/json",
    21 Authorization: `Bearer ${apiKey}`,
    22 },
    23 body: JSON.stringify({
    24 input: data,
    25 model,
    26 input_type: "document",
    27 output_dtype: outputDtype,
    28 output_dimension: dimension,
    29 }),
    30 });
    31
    32 // Check for non-success status codes
    33 if (!response.ok) {
    34 const errorResponse = await response.text();
    35 throw new Error(`API request failed with status ${response.status}: ${errorResponse}`);
    36 }
    37
    38 const responseData = await response.json();
    39
    40 // Ensure the response contains valid data
    41 if (!responseData.data || !Array.isArray(responseData.data)) {
    42 throw new Error(`Invalid API response for dtype "${outputDtype}": 'data' array is missing.`);
    43 }
    44
    45 // Extract embeddings from the response
    46 const embeddings = responseData.data.map((item) => item.embedding);
    47
    48 // Validate embeddings
    49 if (!Array.isArray(embeddings) || embeddings.length !== data.length) {
    50 throw new Error(`Invalid embeddings received for dtype "${outputDtype}".`);
    51 }
    52
    53 return embeddings; // Return embeddings for the requested dtype
    54}
    55
    56/**
    57 * Generate embeddings for predefined texts and save them to a JSON file
    58 */
    59async function generateEmbeddings() {
    60 const data = [
    61 "The Great Wall of China is visible from space.",
    62 "The Eiffel Tower was completed in Paris in 1889.",
    63 "Mount Everest is the highest peak on Earth at 8,848m.",
    64 "Shakespeare wrote 37 plays and 154 sonnets during his lifetime.",
    65 "The Mona Lisa was painted by Leonardo da Vinci.",
    66 ];
    67
    68 const model = "voyage-3-large";
    69 const dimension = 1024; // Output embedding dimension
    70
    71 try {
    72 // Fetch embeddings for different output types
    73 const floatEmbeddings = await fetchEmbeddings(data, model, "float", dimension);
    74 const int8Embeddings = await fetchEmbeddings(data, model, "int8", dimension); // Use "int8" dtype
    75 const ubinaryEmbeddings = await fetchEmbeddings(data, model, "ubinary", dimension); // Use "ubinary" dtype
    76
    77 // Map embeddings to their corresponding texts
    78 const embeddingsData = data.map((text, index) => ({
    79 text,
    80 embeddings: {
    81 float: floatEmbeddings[index], // Store float embeddings
    82 int8: int8Embeddings[index], // Store int8 embeddings
    83 ubinary: ubinaryEmbeddings[index], // Store ubinary embeddings
    84 },
    85 }));
    86
    87 // Save embeddings to a JSON file
    88 const fileName = "embeddings.json";
    89 await writeFile(fileName, JSON.stringify(embeddingsData, null, 2));
    90 console.log(`Embeddings saved to ${fileName}`);
    91 } catch (error) {
    92 console.error("Error during embedding generation:", error.message);
    93 throw error; // Optionally rethrow to halt execution if desired
    94 }
    95}
    96
    97// Main process
    98(async function main() {
    99 try {
    100 await generateEmbeddings(); // Execute embedding generation
    101 } catch (error) {
    102 console.error("Error in main process:", error.message);
    103 }
    104})();
  3. Substitua o espaço reservado <VOYAGE_API_KEY> se você não definiu sua chave de API para o Voyage AI como uma variável de ambiente e, em seguida, salve o arquivo.

  4. Execute o código para gerar incorporações.

    node get-embeddings.js
    Embeddings saved to embeddings.json
  5. Verifique as incorporações geradas no arquivo embeddings.json gerado.

6
  1. Crie um arquivo chamado convert-embeddings.js para converter as float32 int8 int1 incorporações vetoriais, e dos vetores Voyage AI para BSON binData usando o driver MongoDB Node.js

    touch convert-embeddings.js
  2. Copie e cole o seguinte código no arquivo convert-embeddings.js.

    Este código faz o seguinte:

    • Gera vetores BSON binData para as incorporações float32, int8 e int1.

    • Anexa os vetores float32, int8 e ubinary BSON binData ao arquivo embeddings.json.

    convert-embeddings.js
    1import fs from "fs/promises";
    2import { BSON } from "mongodb";
    3const { Binary } = BSON;
    4
    5async function main() {
    6 try {
    7 // Read the contents of the original 'embeddings.json' file
    8 const fileContent = await fs.readFile("embeddings.json", "utf8");
    9 const embeddingsData = JSON.parse(fileContent); // Parse JSON into a JavaScript object
    10
    11 // Validate the structure of the original input data
    12 if (!Array.isArray(embeddingsData)) {
    13 throw new Error("'embeddings.json' must contain an array of objects.");
    14 }
    15
    16 // Convert embeddings to BSON-compatible format
    17 const convertEmbeddingsData = embeddingsData.map(({ text, embeddings }) => {
    18 // Field validation to ensure all required embeddings are present
    19 if (
    20 !embeddings ||
    21 !Array.isArray(embeddings.float) ||
    22 !Array.isArray(embeddings.int8) ||
    23 !Array.isArray(embeddings.ubinary)
    24 ) {
    25 throw new Error(`Embeddings are missing or invalid for text: "${text}"`);
    26 }
    27
    28 // Convert embeddings to BSON-compatible binary format
    29 const bsonFloat32 = Binary.fromFloat32Array(new Float32Array(embeddings.float));
    30 const bsonInt8 = Binary.fromInt8Array(new Int8Array(embeddings.int8));
    31 const bsonPackedBits = Binary.fromPackedBits(new Uint8Array(embeddings.ubinary));
    32
    33 // Return the updated object structure
    34 return {
    35 text,
    36 embeddings: { // Original embeddings
    37 float: embeddings.float,
    38 int8: embeddings.int8,
    39 ubinary: embeddings.ubinary,
    40 },
    41 bsonEmbeddings: { // BSON embeddings
    42 float32: bsonFloat32,
    43 int8: bsonInt8,
    44 packedBits: bsonPackedBits,
    45 },
    46 };
    47 });
    48
    49 // Serialize the updated data to BSON-compatible JSON using EJSON
    50 const ejsonSerializedData = BSON.EJSON.stringify(convertEmbeddingsData, null, 2, { relaxed: false });
    51
    52 // Write the updated BSON-converted data back to the same 'embeddings.json' file
    53 await fs.writeFile("embeddings.json", ejsonSerializedData);
    54
    55 console.log("Embeddings with BSON vectors have been saved to embeddings.json");
    56 } catch (error) {
    57 // Print detailed error information
    58 console.error("Error processing embeddings:", error);
    59 }
    60}
    61
    62// Execute the conversion process
    63main();
  3. Execute o programa para gerar os vetores BSON binData.

    node convert-embeddings.js
    Embeddings with BSON vectors have been saved to embeddings.json
  4. Verifique as incorporações BSON geradas no arquivo embeddings.json.

7
  1. Crie um arquivo chamado upload-data.js para se conectar ao cluster Atlas e criar uma coleção em um banco de dados para os dados no arquivo embeddings.json.

    touch upload-data.js
  2. Copie e cole o seguinte código no arquivo upload-data.js.

    Este código faz o seguinte:

    • Conecta-se ao seu cluster do Atlas e cria um namespace com o nome do banco de dados e da coleção que você especificar.

    • Carrega os dados, incluindo as incorporações no arquivo embeddings.json, para o namespace especificado.

    upload-data.js
    1import fs from 'fs/promises';
    2import { MongoClient, BSON } from 'mongodb';
    3const { Binary } = BSON;
    4
    5async function main() {
    6 const MONGODB_URI = process.env.MONGODB_URI || "<CONNECTION-STRING>";
    7 const DB_NAME = "<DATABASE-NAME>";
    8 const COLLECTION_NAME = "<COLLECTION-NAME>";
    9
    10 let client;
    11 try {
    12 client = new MongoClient(MONGODB_URI);
    13 await client.connect();
    14 console.log("Connected to MongoDB");
    15
    16 const db = client.db(DB_NAME);
    17 const collection = db.collection(COLLECTION_NAME);
    18
    19 // Read and parse the contents of 'embeddings.json' file using EJSON
    20 const fileContent = await fs.readFile('embeddings.json', 'utf8');
    21 const embeddingsData = BSON.EJSON.parse(fileContent);
    22
    23 // Map embeddings data to recreate BSON binary representations with the correct subtype
    24 const documents = embeddingsData.map(({ text, bsonEmbeddings }) => {
    25 return {
    26 text,
    27 bsonEmbeddings: {
    28 float32: bsonEmbeddings.float32,
    29 int8: bsonEmbeddings.int8,
    30 int1: bsonEmbeddings.packedBits
    31 }
    32 };
    33 });
    34
    35 const result = await collection.insertMany(documents);
    36 console.log(`Inserted ${result.insertedCount} documents into MongoDB`);
    37
    38 } catch (error) {
    39 console.error('Error storing embeddings in MongoDB:', error);
    40 } finally {
    41 if (client) {
    42 await client.close();
    43 }
    44 }
    45}
    46
    47// Run the store function
    48main();
  3. Substitua as seguintes configurações e salve o arquivo.

    <CONNECTION-STRING>

    String de conexão para conectar ao cluster do Atlas onde você deseja criar o banco de dados e a coleção.

    Substitua este valor apenas se você não tiver configurado a variável de ambiente MONGODB_URI.

    <DB-NAME>

    Nome do banco de dados onde você deseja criar a coleção.

    <COLLECTION-NAME>

    Nome da coleção onde você deseja armazenar as incorporações geradas.

  4. Execute o seguinte comando para carregar os dados.

    node upload-data.js
  5. Verifique se os documentos existem na coleção em seu cluster Atlas.

8
  1. Crie um arquivo chamado create-index.js para definir um índice do Atlas Vector Search na coleção.

    touch create-index.js
  2. Copie e cole o seguinte código para criar o índice no arquivo create-index.js.

    O código faz o seguinte:

    • Conecta-se ao cluster do Atlas e cria um índice com o nome especificado para o namespace especificado.

    • Indexa os campos bsonEmbeddings.float32 e bsonEmbeddings.int8 como tipo vector que usa a função de similaridade dotProduct, e o campo bsonEmbeddings.int1 também como tipo vector que usa a função euclidean.

    create-index.js
    1import { MongoClient, BSON } from "mongodb";
    2import { setTimeout } from "timers/promises";
    3
    4// Connect to your Atlas deployment
    5const uri = process.env.MONGODB_URI || "<CONNECTION-STRING>";
    6
    7const client = new MongoClient(uri);
    8
    9async function main() {
    10 try {
    11 const DB_NAME = "<DATABASE-NAME>";
    12 const COLLECTION_NAME = "<COLLECTION-NAME>";
    13 const db = client.db(DB_NAME);
    14 const collection = db.collection(COLLECTION_NAME);
    15
    16 // Define your Atlas Vector Search index
    17 const index = {
    18 name: "<INDEX-NAME>",
    19 type: "vectorSearch",
    20 definition: {
    21 fields: [
    22 {
    23 type: "vector",
    24 numDimensions: 1024,
    25 path: "bsonEmbeddings.float32",
    26 similarity: "dotProduct",
    27 },
    28 {
    29 type: "vector",
    30 numDimensions: 1024,
    31 path: "bsonEmbeddings.int8",
    32 similarity: "dotProduct",
    33 },
    34 {
    35 type: "vector",
    36 numDimensions: 1024,
    37 path: "bsonEmbeddings.int1",
    38 similarity: "euclidean",
    39 },
    40 ],
    41 },
    42 };
    43
    44 // Run the helper method
    45 const result = await collection.createSearchIndex(index);
    46 console.log(`New search index named ${result} is building.`);
    47
    48 // Wait for the index to be ready to query
    49 console.log("Polling to check if the index is ready. This may take up to a minute.");
    50 let isQueryable = false;
    51
    52 // Use filtered search for index readiness
    53 while (!isQueryable) {
    54 const [indexData] = await collection.listSearchIndexes(index.name).toArray();
    55
    56 if (indexData) {
    57 isQueryable = indexData.queryable;
    58 if (!isQueryable) {
    59 await setTimeout(5000); // Wait for 5 seconds before checking again
    60 }
    61 } else {
    62 // Handle the case where the index might not be found
    63 console.log(`Index ${index.name} not found.`);
    64 await setTimeout(5000); // Wait for 5 seconds before checking again
    65 }
    66 }
    67
    68 console.log(`${result} is ready for querying.`);
    69 } catch (error) {
    70 console.error("Error:", error);
    71 } finally {
    72 await client.close();
    73 }
    74}
    75
    76main().catch((err) => {
    77 console.error("Unhandled error:", err);
    78});
  3. Substitua as seguintes configurações e salve o arquivo.

    <CONNECTION-STRING>

    String de conexão para se conectar ao cluster do Atlas onde você deseja criar o índice.

    Substitua este valor apenas se você não tiver configurado a variável de ambiente MONGODB_URI.

    <DB-NAME>

    Nome do banco de dados onde você deseja criar a coleção.

    <COLLECTION-NAME>

    Nome da coleção onde você deseja armazenar as incorporações geradas.

    <INDEX-NAME>

    Nome do índice para a coleção.

  4. Crie o índice.

    node create-index.js
9
  1. Crie um arquivo denominado get-query-embedding.js.

    touch get-query-embeddings.js
  2. Copie e cole o código no arquivo get-query-embedding.js.

    O código de exemplo faz o seguinte:

    • Gera incorporações float32, int8 e int1 para o texto da query usando o Voyage AI.

    • Converte as incorporações geradas em vetores BSON binData usando o PyMongo.

    • Salva as incorporações geradas em um arquivo chamado query-embeddings.json.

    get-query-embedding.js
    1import { BSON } from "mongodb";
    2import { writeFile } from "fs/promises";
    3import dotenv from "dotenv";
    4
    5// Load environment variables
    6dotenv.config();
    7
    8const { Binary, EJSON } = BSON; // Import BSON utilities
    9
    10// Set your API key from environment or fallback to hardcoded value (not recommended for production)
    11const apiKey = process.env.VOYAGE_API_KEY || "<VOYAGEAI-API-KEY>";
    12const QUERY_TEXT = <QUERY-TEXT>;
    13
    14if (!apiKey || apiKey === "<VOYAGEAI-API-KEY>") {
    15 throw new Error("API key not found. Provide the VOYAGEAI_API_KEY in environment variables.");
    16}
    17
    18// Define the Voyage AI REST API endpoint
    19const apiEndpoint = "https://api.voyageai.com/v1/embeddings";
    20
    21/**
    22 * Fetch embeddings using Voyage AI REST API
    23 */
    24async function fetchEmbeddings(data, model, inputType, outputDtype, outputDimension) {
    25 try {
    26 const response = await fetch(apiEndpoint, {
    27 method: "POST",
    28 headers: {
    29 "Content-Type": "application/json",
    30 Authorization: `Bearer ${apiKey}`,
    31 },
    32 body: JSON.stringify({
    33 input: data,
    34 model,
    35 input_type: inputType,
    36 output_dtype: outputDtype,
    37 output_dimension: outputDimension,
    38 }),
    39 });
    40
    41 // Check for non-success status codes
    42 if (!response.ok) {
    43 const errorResponse = await response.text();
    44 throw new Error(`API request failed with status ${response.status}: ${errorResponse}`);
    45 }
    46
    47 const responseData = await response.json();
    48
    49 // Ensure the response contains valid data
    50 if (!responseData.data || !Array.isArray(responseData.data)) {
    51 console.error("Full API Response:", responseData);
    52 throw new Error("Embeddings are not present or not returned in array format.");
    53 }
    54
    55 return responseData.data.map((item) => item.embedding); // Extract embeddings
    56 } catch (error) {
    57 console.error(`Error fetching embeddings for output_dtype "${outputDtype}":`, error);
    58 throw error;
    59 }
    60}
    61
    62/**
    63 * Create BSON Binary objects using VECTOR_TYPE for all embedding types
    64 */
    65function convertEmbeddingsToBSON(data, float, int8, ubinary) {
    66 return data.map((text, index) => ({
    67 text,
    68 bsonEmbeddings: {
    69 float32: Binary.fromFloat32Array(new Float32Array(float[index])),
    70 int8: Binary.fromInt8Array(new Int8Array(int8[index])),
    71 int1: Binary.fromPackedBits(new Uint8Array(ubinary[index])),
    72 },
    73 }));
    74}
    75
    76/**
    77 * Serialize BSON embeddings and save to JSON file
    78 */
    79async function saveBSONEmbeddingsToFile(bsonEmbeddingsData, outputFileName) {
    80 try {
    81 // Serialize BSON data to JSON format using EJSON
    82 const ejsonSerializedData = EJSON.stringify(bsonEmbeddingsData, null, 2, {
    83 relaxed: true, // Store binary as raw binary data without base64 encoding
    84 });
    85
    86 // Write serialized data to a file
    87 await writeFile(outputFileName, ejsonSerializedData);
    88 console.log(`Embeddings with BSON vectors have been saved to ${outputFileName}`);
    89 } catch (error) {
    90 console.error(`Error saving BSON embeddings to file "${outputFileName}":`, error);
    91 throw error;
    92 }
    93}
    94
    95/**
    96 * Process query text, fetch embeddings, convert to BSON, and write to JSON
    97 */
    98async function main(queryText) {
    99 try {
    100 if (!queryText || typeof queryText !== "string" || queryText.trim() === "") {
    101 throw new Error("Invalid query text. It must be a non-empty string.");
    102 }
    103
    104 const data = [queryText];
    105 const model = "voyage-3-large";
    106 const inputType = "query";
    107 const dimension = 1024;
    108
    109 // Fetch embeddings for different data types
    110 const floatEmbeddings = await fetchEmbeddings(data, model, inputType, "float", dimension);
    111 const int8Embeddings = await fetchEmbeddings(data, model, inputType, "int8", dimension);
    112 const packedBitsEmbeddings = await fetchEmbeddings(data, model, inputType, "ubinary", dimension);
    113
    114 // Convert embeddings into BSON-compatible format
    115 const bsonEmbeddingsData = convertEmbeddingsToBSON(
    116 data,
    117 floatEmbeddings,
    118 int8Embeddings,
    119 packedBitsEmbeddings
    120 );
    121
    122 // Save BSON embeddings to JSON file
    123 const outputFileName = "query-embeddings.json";
    124 await saveBSONEmbeddingsToFile(bsonEmbeddingsData, outputFileName);
    125 } catch (error) {
    126 console.error("Error processing query text:", error);
    127 }
    128}
    129
    130// Main function invocation
    131(async () => {
    132 const queryText = QUERY-TEXT;
    133 await main(queryText);
    134})();
  3. Substitua as seguintes configurações e salve o arquivo.

    <VOYAGE-API-KEY>

    Sua chave de API para o Voyage AI. Substitua este valor apenas se você não tiver definido a variável de ambiente.

    <QUERY-TEXT>

    Seu texto de consulta. Para este tutorial, utilize science fact.

  4. Execute o código para gerar as incorporações para o texto da query.

    node get-query-embeddings.js
    Embeddings with BSON vectors have been saved to query-embeddings.json
10
  1. Crie um arquivo denominado run-query.js.

    touch run-query.js
  2. Copie e cole a consulta de amostra $vectorSearch a seguir no arquivo run-query.js.

    A query de amostra faz o seguinte:

    • Conecta-se ao seu cluster do Atlas e executa a consulta $vectorSearch nos campos bsonEmbeddings.float32, bsonEmbeddings.int8 e bsonEmbeddings.int1 na coleção especificada usando as incorporações no arquivo query-embeddings.json.

    • Imprime os resultados das incorporações Float32, Int8 e Binário Empacotado (Int1) no console.

    run-query.js
    1import { MongoClient } from "mongodb";
    2import fs from "fs/promises";
    3import { BSON } from "bson"; // Use the BSON package for EJSON parsing
    4import dotenv from "dotenv";
    5
    6dotenv.config();
    7
    8// MongoDB connection details
    9const mongoUri = process.env.MONGODB_URI || "<CONNECTION-STRING>";
    10const dbName = "<DATABASE-NAME>";
    11const collectionName = "<COLLECTION-NAME>";
    12const VECTOR_INDEX_NAME = "<INDEX-NAME>";
    13const NUM_CANDIDATES = <NUMBER-OF-CANDIDATES-TO-CONSIDER>;
    14const LIMIT = <NUMBER-OF-DOCUMENTS-TO-RETURN>;
    15const dataField = "<TEXT-FIELD-NAME>";
    16
    17// Fields in the collection containing BSON-compatible query vectors
    18const FIELDS = [
    19 { path: "float32", subtype: 9 },
    20 { path: "int8", subtype: 9 },
    21 { path: "int1", subtype: 9 },
    22];
    23
    24async function main() {
    25 const client = new MongoClient(mongoUri);
    26
    27 try {
    28 await client.connect();
    29 console.log("Connected to MongoDB");
    30
    31 const db = client.db(dbName);
    32 const collection = db.collection(collectionName);
    33
    34 // Read the query embeddings from the JSON file
    35 const fileContent = await fs.readFile("query-embeddings.json", "utf8");
    36 const embeddingsData = BSON.EJSON.parse(fileContent, { relaxed: true });
    37
    38 if (!Array.isArray(embeddingsData) || embeddingsData.length === 0) {
    39 throw new Error("No embeddings found in the JSON file");
    40 }
    41
    42 const results = {};
    43
    44 // Perform vector search for each embedding type
    45 for (const field of FIELDS) {
    46 const { path } = field;
    47 const bsonBinary = embeddingsData[0]?.bsonEmbeddings?.[path];
    48
    49 if (!bsonBinary) {
    50 console.warn(`Embedding for path "${path}" not found. Skipping.`);
    51 continue;
    52 }
    53
    54 const pipeline = [
    55 {
    56 $vectorSearch: {
    57 index: VECTOR_INDEX_NAME,
    58 path: `bsonEmbeddings.${path}`,
    59 queryVector: bsonBinary, // Direct raw binary
    60 numCandidates: NUM_CANDIDATES,
    61 limit: LIMIT,
    62 },
    63 },
    64 {
    65 $project: {
    66 _id: 0,
    67 [dataField]: 1,
    68 score: { $meta: "vectorSearchScore" },
    69 },
    70 },
    71 ];
    72
    73 console.log(`Running vector search using "${path}" embedding...`);
    74 results[path] = await collection.aggregate(pipeline).toArray();
    75 }
    76
    77 return results;
    78 } catch (error) {
    79 console.error("Error during vector search:", error);
    80 } finally {
    81 await client.close();
    82 console.log("MongoDB connection closed");
    83 }
    84}
    85
    86// Parse and display search results for each embedding type
    87(async () => {
    88 const results = await main();
    89
    90 if (results) {
    91 console.log("Results from Float32 embeddings:");
    92 (results.float32 || []).forEach((result, index) => {
    93 console.log(`Result ${index + 1}:`, result);
    94 });
    95
    96 console.log("Results from Int8 embeddings:");
    97 (results.int8 || []).forEach((result, index) => {
    98 console.log(`Result ${index + 1}:`, result);
    99 });
    100
    101 console.log("Results from Int1 (PackedBits) embeddings:");
    102 (results.int1 || []).forEach((result, index) => {
    103 console.log(`Result ${index + 1}:`, result);
    104 });
    105 }
    106})();
  3. Substitua as seguintes configurações e salve o arquivo run-query.js.

    <CONNECTION-STRING>

    String de conexão para conectar ao cluster do Atlas onde você deseja executar a consulta.

    Substitua este valor apenas se você não tiver configurado a variável de ambiente MONGODB_URI.

    <DB-NAME>

    Nome do banco de dados que contém a coleção.

    <COLLECTION-NAME>

    Nome da coleção que você deseja consultar.

    <INDEX-NAME>

    Nome do índice para a coleção.

    <NUMBER-OF-CAANDIDATES-TO-CONSIDER>

    Número de vizinhos mais próximos a serem considerados durante a pesquisa. Para este exemplo, especifique 5.

    <NUMBER-OF-DOCUMENTS-TO-RETURN>

    Número de resultados a retornar. Para este exemplo, especifique 2.

    <TEXT-FIELD-NAME>

    Nome do campo que contém os dados de texto. Para este exemplo, especifique text.

  4. Execute o seguinte comando para executar a query.

    node run-query.js
    Connected to MongoDB
    Running vector search using "float32" embedding...
    Running vector search using "int8" embedding...
    Running vector search using "int1" embedding...
    MongoDB connection closed
    Results from Float32 embeddings:
    Result 1: {
    text: 'The Great Wall of China is visible from space.',
    score: 0.7719700336456299
    }
    Result 2: {
    text: 'Mount Everest is the highest peak on Earth at 8,848m.',
    score: 0.735608696937561
    }
    Results from Int8 embeddings:
    Result 1: {
    text: 'The Great Wall of China is visible from space.',
    score: 0.5051995515823364
    }
    Result 2: {
    text: 'Mount Everest is the highest peak on Earth at 8,848m.',
    score: 0.5044659972190857
    }
    Results from Int1 (PackedBits) embeddings:
    Result 1: {
    text: 'The Great Wall of China is visible from space.',
    score: 0.6845703125
    }
    Result 2: {
    text: 'Mount Everest is the highest peak on Earth at 8,848m.',
    score: 0.6650390625
    }
1

Configure seu projeto para usar módulos ES adicionando "type": "module" ao seu arquivo package.json e salvando-o.

{
"type": "module",
// other fields...
}
2

Execute o seguinte comando para instalar o Driver MongoDB Node.js e o dotenv pacote. Esta operação pode levar alguns minutos para ser concluída.

npm install mongodb dotenv

Você deve instalar o driver Node.js v6.11 ou posterior.

Se necessário, você também deve instalar bibliotecas do fornecedor do modelo de incorporação. Neste tutorial, você usa a API REST do Voyage AI para gerar incorporações. Portanto, você não precisa instalar nenhuma biblioteca adicional para o Voyage AI.

3

Em uma janela de terminal, execute os seguintes comandos para criar um novo diretório chamado my-quantization-project e inicializar seu projeto:

mkdir my-quantization-project
cd my-quantization-project
npm init -y
4
  1. Para acessar o provedor de modelo de incorporação para gerar e converter incorporações, configure a variável de ambiente para a chave de API do provedor de modelo de incorporação, se necessário.

    Para utilizar incorporações da Voyage AI, configure a variável de ambiente do VOYAGE_API_KEY.

    export VOYAGE_API_KEY="<VOYAGEAI-API-KEY>"

    Caso não defina a variável de ambiente, substitua o <VOYAGE-API-KEY> no código de exemplo pela chave de API antes de executar o código.

  2. Para acessar o cluster Atlas, defina a variável de ambiente MONGODB_URI.

    export MONGODB_URI="<CONNECTION-STRING>"

    Sua string de conexão deve estar no seguinte formato:

    mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net

    Caso você não configure a variável de ambiente, substitua o <CONNECTION-STRING> no código de exemplo pela sua string de conexão antes de executar o código.

5
  1. Crie um arquivo denominado get-data.js.

    touch get-data.js
  2. Copie e cole o código de exemplo a seguir para buscar os dados do namespace sample_airbnb.listingsAndReviews no seu cluster Atlas.

    O código de exemplo faz o seguinte:

    • Conecta-se ao seu cluster do Atlas e encontra documentos com o campo summary.

    • Cria um arquivo chamado subset.json para o qual grava os dados da coleção.

    get-data.js
    1import { MongoClient, BSON } from 'mongodb';
    2import fs from 'fs/promises';
    3import { writeFile } from "fs/promises";
    4
    5async function main() {
    6 // Replace with your Atlas connection string
    7 const uri = process.env.MONGODB_URI || '<CONNECTION-STRING>';
    8
    9 // Create a new MongoClient instance
    10 const client = new MongoClient(uri);
    11
    12 try {
    13 // Connect to your Atlas cluster
    14 await client.connect();
    15
    16 // Specify the database and collection
    17 const db = client.db('sample_airbnb');
    18 const collection = db.collection('listingsAndReviews');
    19
    20 // Filter to exclude null or empty summary fields
    21 const filter = { summary: { $nin: [null, ''] } };
    22
    23 // Get a subset of documents in the collection
    24 const documentsCursor = collection.find(filter).limit(50);
    25
    26 // Convert the cursor to an array to get the documents
    27 const documents = await documentsCursor.toArray();
    28
    29 // Write the documents to a local file called "subset.json"
    30 const outputFilePath = './subset.json';
    31 fs.writeFile(outputFilePath, JSON.stringify(documents, null, 2), 'utf-8');
    32
    33 // Print the count of documents written to the file
    34 console.log(`Written ${documents.length} documents to ${outputFilePath}`);
    35 } catch (error) {
    36 console.error('An error occurred:', error);
    37 } finally {
    38 // Ensure the client is closed when finished
    39 await client.close();
    40 }
    41}
    42
    43main().catch(console.error);
  3. Substitua o espaço reservado <CONNECTION-STRING> se você não definiu a variável de ambiente para sua string de conexão do Atlas e, em seguida, salve o arquivo.

  4. Execute o seguinte comando para buscar os dados:

    node get-data.js
    Subset of documents written to: ./subset.json
6

Se você já possui as incorporações vetoriais float32, int8 ou int1 na sua coleção, pule esta etapa.

  1. Crie um arquivo chamado get-embeddings.js float32int8para int1 gerar incorporações vetoriais,embed e usando a API da Voyage AI .

    touch get-embeddings.js
  2. Copie e cole o seguinte código no arquivo get-embeddings.js.

    Este código faz o seguinte:

    • Gera float32 incorporações, int8 e int1 para os dados fornecidos usando o modelo de incorporação embed-english-v3.0 da Voyage AI.

    • Armazena as incorporações float32, int8 e int1 em campos chamados float, int8 e ubinary, respectivamente.

    • Cria um arquivo chamado embeddings.json e salva as incorporações no arquivo.

    get-embeddings.js
    1import { readFile, writeFile } from "fs/promises";
    2import dotenv from "dotenv";
    3import fetch from "node-fetch";
    4
    5// Load environment variables from `.env` file
    6dotenv.config();
    7
    8// Set up API key from environment or fallback to hardcoded value
    9const apiKey = process.env.VOYAGE_API_KEY || "<VOYAGE-API-KEY>";
    10
    11if (!apiKey || apiKey === "<VOYAGE-API-KEY>") {
    12 throw new Error("API key not found. Please set VOYAGE_API_KEY in your environment.");
    13}
    14
    15// Define the Voyage AI REST API endpoint
    16const apiEndpoint = "https://api.voyageai.com/v1/embeddings";
    17
    18/**
    19 * Fetch embeddings using Voyage AI REST API for a specific output data type
    20 */
    21async function fetchEmbeddings(data, model, outputDtype, dimension) {
    22 const response = await fetch(apiEndpoint, {
    23 method: "POST",
    24 headers: {
    25 "Content-Type": "application/json",
    26 Authorization: `Bearer ${apiKey}`,
    27 },
    28 body: JSON.stringify({
    29 input: data,
    30 model,
    31 input_type: "document",
    32 output_dtype: outputDtype,
    33 output_dimension: dimension,
    34 }),
    35 });
    36
    37 // Check for non-success status codes
    38 if (!response.ok) {
    39 const errorResponse = await response.text();
    40 throw new Error(`API request failed with status ${response.status}: ${errorResponse}`);
    41 }
    42
    43 const responseData = await response.json();
    44
    45 // Ensure the response contains valid data
    46 if (!responseData.data || !Array.isArray(responseData.data)) {
    47 throw new Error(`Invalid API response for dtype "${outputDtype}": 'data' array is missing.`);
    48 }
    49
    50 // Extract embeddings from the response
    51 const embeddings = responseData.data.map((item) => item.embedding);
    52
    53 // Validate embeddings
    54 if (!Array.isArray(embeddings) || embeddings.length !== data.length) {
    55 throw new Error(`Invalid embeddings received for dtype "${outputDtype}".`);
    56 }
    57
    58 return embeddings; // Return embeddings for the requested dtype
    59}
    60
    61/**
    62 * Main function to read input data, fetch embeddings, and save them to JSON
    63 */
    64async function main() {
    65 try {
    66 // Read and parse the contents of `subset.json`
    67 const subsetData = await readFile("subset.json", "utf-8");
    68 const documents = JSON.parse(subsetData);
    69
    70 // Extract the `summary` fields and keep only non-empty strings
    71 const data = documents
    72 .map((doc) => doc.summary)
    73 .filter((summary) => typeof summary === "string" && summary.trim().length > 0);
    74
    75 // If no valid data is found, throw an error
    76 if (data.length === 0) {
    77 throw new Error("No valid summary texts available in the input file.");
    78 }
    79
    80 // Configuration for embeddings
    81 const model = "voyage-3-large";
    82 const dimension = 1024;
    83
    84 // Fetch embeddings for different output types (float, int8, ubinary)
    85 const floatEmbeddings = await fetchEmbeddings(data, model, "float", dimension);
    86 const int8Embeddings = await fetchEmbeddings(data, model, "int8", dimension);
    87 const ubinaryEmbeddings = await fetchEmbeddings(data, model, "ubinary", dimension);
    88
    89 // Map embeddings to their corresponding texts
    90 const embeddingsData = data.map((text, index) => ({
    91 text,
    92 embeddings: {
    93 float: floatEmbeddings[index],
    94 int8: int8Embeddings[index],
    95 ubinary: ubinaryEmbeddings[index],
    96 },
    97 }));
    98
    99 // Save embeddings to a JSON file
    100 const fileName = "embeddings.json";
    101 await writeFile(fileName, JSON.stringify(embeddingsData, null, 2));
    102 console.log(`Embeddings saved to ${fileName}`);
    103 } catch (error) {
    104 console.error("Error during embedding generation:", error.message);
    105 }
    106}
    107
    108// Execute the main function
    109main();
  3. Se você não definiu a variável de ambiente para sua chave de API do Voyage AI, substitua o espaço reservado <VOYAGEAI-API-KEY> e salve o arquivo.

  4. Execute o código para gerar as incorporações.

    node get-embeddings.js
    Embeddings saved to embeddings.json
  5. Verifique as incorporações geradas abrindo o arquivo embeddings.json gerado.

7
  1. Crie um arquivo chamado convert-embeddings.js para converter as float32 int8 int1 incorporações, e dos binData vetores Voyage AI para BSON.

    touch convert-embeddings.js
  2. Copie e cole o seguinte código no arquivo convert-embeddings.js.

    Este código faz o seguinte:

    • Gera vetores BSON binData para as incorporações float32, int8 e int1.

    • Anexa os vetores float32, int8 e ubinary BSON binData ao arquivo embeddings.json.

    convert-embeddings.js
    1import fs from "fs/promises";
    2import { BSON } from "mongodb";
    3const { Binary } = BSON;
    4
    5async function main() {
    6 try {
    7 // Read the contents of the original 'embeddings.json' file
    8 const fileContent = await fs.readFile("embeddings.json", "utf8");
    9 const embeddingsData = JSON.parse(fileContent); // Parse JSON into a JavaScript object
    10
    11 // Validate the structure of the original input data
    12 if (!Array.isArray(embeddingsData)) {
    13 throw new Error("'embeddings.json' must contain an array of objects.");
    14 }
    15
    16 // Convert embeddings to BSON-compatible format
    17 const convertEmbeddingsData = embeddingsData.map(({ text, embeddings }) => {
    18 // Field validation to ensure all required embeddings are present
    19 if (
    20 !embeddings ||
    21 !Array.isArray(embeddings.float) ||
    22 !Array.isArray(embeddings.int8) ||
    23 !Array.isArray(embeddings.ubinary)
    24 ) {
    25 throw new Error(`Embeddings are missing or invalid for text: "${text}"`);
    26 }
    27
    28 // Convert embeddings to BSON-compatible binary format
    29 const bsonFloat32 = Binary.fromFloat32Array(new Float32Array(embeddings.float));
    30 const bsonInt8 = Binary.fromInt8Array(new Int8Array(embeddings.int8));
    31 const bsonPackedBits = Binary.fromPackedBits(new Uint8Array(embeddings.ubinary));
    32
    33 // Return the updated object structure
    34 return {
    35 text,
    36 embeddings: { // Original embeddings
    37 float: embeddings.float,
    38 int8: embeddings.int8,
    39 ubinary: embeddings.ubinary,
    40 },
    41 bsonEmbeddings: { // BSON embeddings
    42 float32: bsonFloat32,
    43 int8: bsonInt8,
    44 packedBits: bsonPackedBits,
    45 },
    46 };
    47 });
    48
    49 // Serialize the updated data to BSON-compatible JSON using EJSON
    50 const ejsonSerializedData = BSON.EJSON.stringify(convertEmbeddingsData, null, 2, { relaxed: false });
    51
    52 // Write the updated BSON-converted data back to the same 'embeddings.json' file
    53 await fs.writeFile("embeddings.json", ejsonSerializedData);
    54
    55 console.log("Embeddings with BSON vectors have been saved to embeddings.json");
    56 } catch (error) {
    57 // Print detailed error information
    58 console.error("Error processing embeddings:", error);
    59 }
    60}
    61
    62// Execute the conversion process
    63main();
  3. Execute o programa para gerar os vetores BSON binData.

    node convert-embeddings.js
    Embeddings with BSON vectors have been saved to embeddings.json
  4. Verifique as incorporações BSON geradas no arquivo embeddings.json.

8
  1. Crie um arquivo chamado upload-data.js para se conectar ao cluster do Atlas e carregar os dados no namespace sample_airbnb.listingsAndReviews.

    touch upload-data.js
  2. Copie e cole o seguinte código no arquivo upload-data.js.

    Este código faz o seguinte:

    • Conecta-se ao seu cluster do Atlas e cria um namespace com o nome do banco de dados e da coleção que você especificar.

    • Carrega os dados, incluindo as incorporações, no namespace sample_airbnb.listingsAndReviews.

    upload-data.js
    1import fs from 'fs/promises';
    2import { MongoClient, BSON } from 'mongodb';
    3import { EJSON, Binary } from 'bson';
    4
    5async function main() {
    6 const MONGODB_URI = process.env.MONGODB_URI || "<CONNECTION-STRING>";
    7 const DB_NAME = "sample_airbnb";
    8 const COLLECTION_NAME = "listingsAndReviews";
    9
    10 let client;
    11 try {
    12 // Connect to MongoDB
    13 client = new MongoClient(MONGODB_URI);
    14 await client.connect();
    15 console.log("Connected to MongoDB");
    16
    17 // Access database and collection
    18 const db = client.db(DB_NAME);
    19 const collection = db.collection(COLLECTION_NAME);
    20
    21 // Load embeddings from JSON using EJSON.parse
    22 const fileContent = await fs.readFile('embeddings.json', 'utf8');
    23 const embeddingsData = EJSON.parse(fileContent); // Use EJSON.parse
    24
    25 // Map embeddings data to recreate BSON binary representations
    26 const documents = embeddingsData.map(({ text, bsonEmbeddings }) => {
    27 return {
    28 summary: text,
    29 bsonEmbeddings: {
    30 float32: bsonEmbeddings.float32,
    31 int8: bsonEmbeddings.int8,
    32 int1: bsonEmbeddings.packedBits
    33 }
    34 };
    35 });
    36
    37 // Iterate over documents and upsert each into the MongoDB collection
    38 for (const doc of documents) {
    39 const filter = { summary: doc.summary };
    40 const update = { $set: doc };
    41
    42 // Update the document with the BSON binary data
    43 const result = await collection.updateOne(filter, update, { upsert: true });
    44 if (result.matchedCount > 0) {
    45 console.log(`Updated document with summary: ${doc.summary}`);
    46 } else {
    47 console.log(`Inserted new document with summary: ${doc.summary}`);
    48 }
    49 }
    50
    51 console.log("Embeddings stored in MongoDB successfully.");
    52 } catch (error) {
    53 console.error('Error storing embeddings in MongoDB:', error);
    54 } finally {
    55 if (client) {
    56 await client.close();
    57 }
    58 }
    59}
    60
    61// Run the main function to load the data
    62main();
  3. Substitua o espaço reservado <CONNECTION-STRING> se você não definiu a variável de ambiente para sua string de conexão do Atlas e, em seguida, salve o arquivo.

  4. Execute o seguinte comando para carregar os dados.

    node upload-data.js
    Connected to MongoDB
    Updated document with text: ...
    ...
    Embeddings stored in MongoDB successfully.
  5. Verifique fazendo login no seu cluster do Atlas e verificando o namespace no Data Explorer.

9
  1. Crie um arquivo denominado create-index.js.

    touch create-index.js
  2. Copie e cole o seguinte código para criar o índice no arquivo create-index.js.

    O código faz o seguinte:

    • Conecta-se ao cluster do Atlas e cria um índice com o nome especificado para o namespace especificado.

    • Indexa os campos bsonEmbeddings.float32 e bsonEmbeddings.int8 como tipo vector usando a função de similaridade dotProduct, e o campo bsonEmbeddings.int1 também como tipo vector usando a função euclidean.

    create-index.js
    1import { MongoClient, BSON } from "mongodb";
    2import { setTimeout } from "timers/promises";
    3
    4// Connect to your Atlas deployment
    5const uri = process.env.MONGODB_URI || "<CONNECTION-STRING>";
    6
    7const client = new MongoClient(uri);
    8
    9async function main() {
    10 try {
    11 const DB_NAME = "<DATABASE-NAME>";
    12 const COLLECTION_NAME = "<COLLECTION-NAME>";
    13 const db = client.db(DB_NAME);
    14 const collection = db.collection(COLLECTION_NAME);
    15
    16 // Define your Atlas Vector Search index
    17 const index = {
    18 name: "<INDEX-NAME>",
    19 type: "vectorSearch",
    20 definition: {
    21 fields: [
    22 {
    23 type: "vector",
    24 numDimensions: 1024,
    25 path: "bsonEmbeddings.float32",
    26 similarity: "dotProduct",
    27 },
    28 {
    29 type: "vector",
    30 numDimensions: 1024,
    31 path: "bsonEmbeddings.int8",
    32 similarity: "dotProduct",
    33 },
    34 {
    35 type: "vector",
    36 numDimensions: 1024,
    37 path: "bsonEmbeddings.int1",
    38 similarity: "euclidean",
    39 },
    40 ],
    41 },
    42 };
    43
    44 // Run the helper method
    45 const result = await collection.createSearchIndex(index);
    46 console.log(`New search index named ${result} is building.`);
    47
    48 // Wait for the index to be ready to query
    49 console.log("Polling to check if the index is ready. This may take up to a minute.");
    50 let isQueryable = false;
    51
    52 // Use filtered search for index readiness
    53 while (!isQueryable) {
    54 const [indexData] = await collection.listSearchIndexes(index.name).toArray();
    55
    56 if (indexData) {
    57 isQueryable = indexData.queryable;
    58 if (!isQueryable) {
    59 await setTimeout(5000); // Wait for 5 seconds before checking again
    60 }
    61 } else {
    62 // Handle the case where the index might not be found
    63 console.log(`Index ${index.name} not found.`);
    64 await setTimeout(5000); // Wait for 5 seconds before checking again
    65 }
    66 }
    67
    68 console.log(`${result} is ready for querying.`);
    69 } catch (error) {
    70 console.error("Error:", error);
    71 } finally {
    72 await client.close();
    73 }
    74}
    75
    76main().catch((err) => {
    77 console.error("Unhandled error:", err);
    78});
  3. Substitua as seguintes configurações e salve o arquivo.

    <CONNECTION-STRING>

    String de conexão para se conectar ao seu cluster Atlas onde você deseja criar o banco de dados e a coleção.

    Substitua este valor apenas se você não tiver configurado a variável de ambiente MONGODB_URI.

    <DB-NAME>

    Nome da coleção, que é sample_airbnb.

    <COLLECTION-NAME>

    Nome da coleção, que é listingsAndReviews.

    <INDEX-NAME>

    Nome do índice para a coleção.

  4. Crie o índice.

    node create-index.js
    New search index named vector_index is building.
    Polling to check if the index is ready. This may take up to a minute.
    <INDEX-NAME> is ready for querying.
10
  1. Crie um arquivo denominado get-query-embeddings.js.

    touch get-query-embeddings.js
  2. Copie e cole o código no arquivo get-query-embedding.js.

    O código de exemplo faz o seguinte:

    • Gera incorporações float32, int8 e int1 para o texto da query usando o Voyage AI.

    • Converte as incorporações geradas em vetores BSON binData usando o PyMongo.

    • Salva as incorporações geradas em um arquivo chamado query-embeddings.json.

    get-query-embedding.js
    1import { BSON } from "mongodb";
    2import { writeFile } from "fs/promises";
    3import dotenv from "dotenv";
    4
    5// Load environment variables
    6dotenv.config();
    7
    8const { Binary, EJSON } = BSON; // Import BSON utilities
    9
    10// Set your API key from environment or fallback to hardcoded value (not recommended for production)
    11const apiKey = process.env.VOYAGE_API_KEY || "<VOYAGEAI-API-KEY>";
    12const QUERY_TEXT = <QUERY-TEXT>;
    13
    14if (!apiKey || apiKey === "<VOYAGEAI-API-KEY>") {
    15 throw new Error("API key not found. Provide the VOYAGEAI_API_KEY in environment variables.");
    16}
    17
    18// Define the Voyage AI REST API endpoint
    19const apiEndpoint = "https://api.voyageai.com/v1/embeddings";
    20
    21/**
    22 * Fetch embeddings using Voyage AI REST API
    23 */
    24async function fetchEmbeddings(data, model, inputType, outputDtype, outputDimension) {
    25 try {
    26 const response = await fetch(apiEndpoint, {
    27 method: "POST",
    28 headers: {
    29 "Content-Type": "application/json",
    30 Authorization: `Bearer ${apiKey}`,
    31 },
    32 body: JSON.stringify({
    33 input: data,
    34 model,
    35 input_type: inputType,
    36 output_dtype: outputDtype,
    37 output_dimension: outputDimension,
    38 }),
    39 });
    40
    41 // Check for non-success status codes
    42 if (!response.ok) {
    43 const errorResponse = await response.text();
    44 throw new Error(`API request failed with status ${response.status}: ${errorResponse}`);
    45 }
    46
    47 const responseData = await response.json();
    48
    49 // Ensure the response contains valid data
    50 if (!responseData.data || !Array.isArray(responseData.data)) {
    51 console.error("Full API Response:", responseData);
    52 throw new Error("Embeddings are not present or not returned in array format.");
    53 }
    54
    55 return responseData.data.map((item) => item.embedding); // Extract embeddings
    56 } catch (error) {
    57 console.error(`Error fetching embeddings for output_dtype "${outputDtype}":`, error);
    58 throw error;
    59 }
    60}
    61
    62/**
    63 * Create BSON Binary objects using VECTOR_TYPE for all embedding types
    64 */
    65function convertEmbeddingsToBSON(data, float, int8, ubinary) {
    66 return data.map((text, index) => ({
    67 text,
    68 bsonEmbeddings: {
    69 float32: Binary.fromFloat32Array(new Float32Array(float[index])),
    70 int8: Binary.fromInt8Array(new Int8Array(int8[index])),
    71 int1: Binary.fromPackedBits(new Uint8Array(ubinary[index])),
    72 },
    73 }));
    74}
    75
    76/**
    77 * Serialize BSON embeddings and save to JSON file
    78 */
    79async function saveBSONEmbeddingsToFile(bsonEmbeddingsData, outputFileName) {
    80 try {
    81 // Serialize BSON data to JSON format using EJSON
    82 const ejsonSerializedData = EJSON.stringify(bsonEmbeddingsData, null, 2, {
    83 relaxed: true, // Store binary as raw binary data without base64 encoding
    84 });
    85
    86 // Write serialized data to a file
    87 await writeFile(outputFileName, ejsonSerializedData);
    88 console.log(`Embeddings with BSON vectors have been saved to ${outputFileName}`);
    89 } catch (error) {
    90 console.error(`Error saving BSON embeddings to file "${outputFileName}":`, error);
    91 throw error;
    92 }
    93}
    94
    95/**
    96 * Process query text, fetch embeddings, convert to BSON, and write to JSON
    97 */
    98async function main(queryText) {
    99 try {
    100 if (!queryText || typeof queryText !== "string" || queryText.trim() === "") {
    101 throw new Error("Invalid query text. It must be a non-empty string.");
    102 }
    103
    104 const data = [queryText];
    105 const model = "voyage-3-large";
    106 const inputType = "query";
    107 const dimension = 1024;
    108
    109 // Fetch embeddings for different data types
    110 const floatEmbeddings = await fetchEmbeddings(data, model, inputType, "float", dimension);
    111 const int8Embeddings = await fetchEmbeddings(data, model, inputType, "int8", dimension);
    112 const packedBitsEmbeddings = await fetchEmbeddings(data, model, inputType, "ubinary", dimension);
    113
    114 // Convert embeddings into BSON-compatible format
    115 const bsonEmbeddingsData = convertEmbeddingsToBSON(
    116 data,
    117 floatEmbeddings,
    118 int8Embeddings,
    119 packedBitsEmbeddings
    120 );
    121
    122 // Save BSON embeddings to JSON file
    123 const outputFileName = "query-embeddings.json";
    124 await saveBSONEmbeddingsToFile(bsonEmbeddingsData, outputFileName);
    125 } catch (error) {
    126 console.error("Error processing query text:", error);
    127 }
    128}
    129
    130// Main function invocation
    131(async () => {
    132 const queryText = QUERY-TEXT;
    133 await main(queryText);
    134})();
  3. Substitua as seguintes configurações e salve o arquivo.

    <VOYAGEAI-API-KEY>

    Sua chave de API para o Voyage AI. Substitua esse valor somente se você não tiver definido a chave como uma variável de ambiente.

    <QUERY-TEXT>

    Seu texto de consulta. Para este exemplo, use ocean view.

  4. Execute o código para gerar as incorporações para o texto da query.

    node get-query-embeddings.js
    Embeddings with BSON vectors have been saved to query-embeddings.json
11
  1. Crie um arquivo denominado run-query.js.

    touch run-query.js
  2. Copie e cole a consulta de amostra $vectorSearch a seguir no arquivo run-query.js.

    A query de amostra faz o seguinte:

    • Conecta-se ao seu cluster do Atlas e executa a consulta $vectorSearch nos campos bsonEmbeddings.float32, bsonEmbeddings.int8 e bsonEmbeddings.int1 no namespace sample_airbnb.listingsAndReviews usando as incorporações no arquivo query-embeddings.json.

    • Imprime os resultados das incorporações Float32, Int8 e Binário Empacotado (Int1) no console.

    run-query.js
    1import { MongoClient } from "mongodb";
    2import fs from "fs/promises";
    3import { BSON } from "bson"; // Use the BSON package for EJSON parsing
    4import dotenv from "dotenv";
    5
    6dotenv.config();
    7
    8// MongoDB connection details
    9const mongoUri = process.env.MONGODB_URI || "<CONNECTION-STRING>";
    10const dbName = "<DATABASE-NAME>";
    11const collectionName = "<COLLECTION-NAME>";
    12const VECTOR_INDEX_NAME = "<INDEX-NAME>";
    13const NUM_CANDIDATES = <NUMBER-OF-CANDIDATES-TO-CONSIDER>;
    14const LIMIT = <NUMBER-OF-DOCUMENTS-TO-RETURN>;
    15const dataField = "<TEXT-FIELD-NAME>";
    16
    17// Fields in the collection containing BSON-compatible query vectors
    18const FIELDS = [
    19 { path: "float32", subtype: 9 },
    20 { path: "int8", subtype: 9 },
    21 { path: "int1", subtype: 9 },
    22];
    23
    24async function main() {
    25 const client = new MongoClient(mongoUri);
    26
    27 try {
    28 await client.connect();
    29 console.log("Connected to MongoDB");
    30
    31 const db = client.db(dbName);
    32 const collection = db.collection(collectionName);
    33
    34 // Read the query embeddings from the JSON file
    35 const fileContent = await fs.readFile("query-embeddings.json", "utf8");
    36 const embeddingsData = BSON.EJSON.parse(fileContent, { relaxed: true });
    37
    38 if (!Array.isArray(embeddingsData) || embeddingsData.length === 0) {
    39 throw new Error("No embeddings found in the JSON file");
    40 }
    41
    42 const results = {};
    43
    44 // Perform vector search for each embedding type
    45 for (const field of FIELDS) {
    46 const { path } = field;
    47 const bsonBinary = embeddingsData[0]?.bsonEmbeddings?.[path];
    48
    49 if (!bsonBinary) {
    50 console.warn(`Embedding for path "${path}" not found. Skipping.`);
    51 continue;
    52 }
    53
    54 const pipeline = [
    55 {
    56 $vectorSearch: {
    57 index: VECTOR_INDEX_NAME,
    58 path: `bsonEmbeddings.${path}`,
    59 queryVector: bsonBinary, // Direct raw binary
    60 numCandidates: NUM_CANDIDATES,
    61 limit: LIMIT,
    62 },
    63 },
    64 {
    65 $project: {
    66 _id: 0,
    67 [dataField]: 1,
    68 score: { $meta: "vectorSearchScore" },
    69 },
    70 },
    71 ];
    72
    73 console.log(`Running vector search using "${path}" embedding...`);
    74 results[path] = await collection.aggregate(pipeline).toArray();
    75 }
    76
    77 return results;
    78 } catch (error) {
    79 console.error("Error during vector search:", error);
    80 } finally {
    81 await client.close();
    82 console.log("MongoDB connection closed");
    83 }
    84}
    85
    86// Parse and display search results for each embedding type
    87(async () => {
    88 const results = await main();
    89
    90 if (results) {
    91 console.log("Results from Float32 embeddings:");
    92 (results.float32 || []).forEach((result, index) => {
    93 console.log(`Result ${index + 1}:`, result);
    94 });
    95
    96 console.log("Results from Int8 embeddings:");
    97 (results.int8 || []).forEach((result, index) => {
    98 console.log(`Result ${index + 1}:`, result);
    99 });
    100
    101 console.log("Results from Int1 (PackedBits) embeddings:");
    102 (results.int1 || []).forEach((result, index) => {
    103 console.log(`Result ${index + 1}:`, result);
    104 });
    105 }
    106})();
  3. Substitua as seguintes configurações e salve o arquivo run-query.js.

    <CONNECTION-STRING>

    String de conexão para se conectar ao cluster do Atlas onde você deseja criar o índice.

    Substitua este valor apenas se você não tiver configurado a variável de ambiente MONGODB_URI.

    <DB-NAME>

    Nome do banco de dados onde você deseja criar a collection. Para este exemplo, especifique sample_airbnb.

    <COLLECTION-NAME>

    Nome da collection onde você deseja armazenar as embeddings geradas. Para este exemplo, especifique listingsAndReviews.

    <INDEX-NAME>

    Nome do índice para a coleção.

    <NUMBER-OF-CANDIDATES-TO-CONSIDER>

    Número de vizinhos mais próximos a serem considerados. Para este exemplo, especifique 20.

    <NUMBER-OF-DOCUMENTS-TO-RETURN>

    Número de documentos a retornar nos resultados. Para este exemplo, especifique 5.

    <DATA-FIELD-NAME>

    Nome do campo que contém dados de texto. Para este exemplo, especifique summary.

  4. Execute a consulta.

    Para executar a consulta, execute o seguinte comando:

    node run-query.js
    Results from embeddings_float32 embeddings:
    {"_id":"10266175","summary":"A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.","score":{"$numberDouble":"0.799713134765625"}}
    {"_id":"10227000","summary":"THIS IS A VERY SPACIOUS 1 BEDROOM FULL CONDO (SLEEPS 4) AT THE BEAUTIFUL VALLEY ISLE RESORT ON THE BEACH IN LAHAINA, MAUI!! YOU WILL LOVE THE PERFECT LOCATION OF THIS VERY NICE HIGH RISE! ALSO THIS SPACIOUS FULL CONDO, FULL KITCHEN, BIG BALCONY!!","score":{"$numberDouble":"0.7568193078041077"}}
    {"_id":"1001265","summary":"A short distance from Honolulu's billion dollar mall, and the same distance to Waikiki. Parking included. A great location that work perfectly for business, education, or simple visit. Experience Yacht Harbor views and 5 Star Hilton Hawaiian Village.","score":{"$numberDouble":"0.7500505447387695"}}
    {"summary":"Quarto com vista para a Lagoa Rodrigo de Freitas, cartão postal do Rio de Janeiro. Linda Vista. 1 Quarto e 1 banheiro Amplo, arejado, vaga na garagem. Prédio com piscina, sauna e playground. Fácil acesso, próximo da praia e shoppings.","score":{"$numberDouble":"0.7367454171180725"},"_id":"10030955"}
    {"_id":"10220130","summary":"Cozy and comfortable apartment. Ideal for families and vacations. 3 bedrooms, 2 of them suites. Located 20-min walk to the beach and close to the Rio 2016 Olympics Venues. Situated in a modern and secure condominium, with many entertainment available options around.","score":{"$numberDouble":"0.7315733432769775"}}
    Results from embeddings_int8 embeddings:
    {"_id":"10266175","summary":"A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.","score":{"$numberDouble":"0.5056195259094238"}}
    {"_id":"10227000","summary":"THIS IS A VERY SPACIOUS 1 BEDROOM FULL CONDO (SLEEPS 4) AT THE BEAUTIFUL VALLEY ISLE RESORT ON THE BEACH IN LAHAINA, MAUI!! YOU WILL LOVE THE PERFECT LOCATION OF THIS VERY NICE HIGH RISE! ALSO THIS SPACIOUS FULL CONDO, FULL KITCHEN, BIG BALCONY!!","score":{"$numberDouble":"0.5048412084579468"}}
    {"summary":"A short distance from Honolulu's billion dollar mall, and the same distance to Waikiki. Parking included. A great location that work perfectly for business, education, or simple visit. Experience Yacht Harbor views and 5 Star Hilton Hawaiian Village.","score":{"$numberDouble":"0.5047098398208618"},"_id":"1001265"}
    {"_id":"10030955","summary":"Quarto com vista para a Lagoa Rodrigo de Freitas, cartão postal do Rio de Janeiro. Linda Vista. 1 Quarto e 1 banheiro Amplo, arejado, vaga na garagem. Prédio com piscina, sauna e playground. Fácil acesso, próximo da praia e shoppings.","score":{"$numberDouble":"0.5043320655822754"}}
    {"_id":"10220130","summary":"Cozy and comfortable apartment. Ideal for families and vacations. 3 bedrooms, 2 of them suites. Located 20-min walk to the beach and close to the Rio 2016 Olympics Venues. Situated in a modern and secure condominium, with many entertainment available options around.","score":{"$numberDouble":"0.5043137073516846"}}
    Results from embeddings_int1 embeddings:
    {"_id":"10266175","summary":"A beautiful and comfortable 1 Bedroom Air Conditioned Condo in Makaha Valley - stunning Ocean & Mountain views All the amenities of home, suited for longer stays. Full kitchen & large bathroom. Several gas BBQ's for all guests to use & a large heated pool surrounded by reclining chairs to sunbathe. The Ocean you see in the pictures is not even a mile away, known as the famous Makaha Surfing Beach. Golfing, hiking,snorkeling paddle boarding, surfing are all just minutes from the front door.","score":{"$numberDouble":"0.7119140625"}}
    {"_id":"1001265","summary":"A short distance from Honolulu's billion dollar mall, and the same distance to Waikiki. Parking included. A great location that work perfectly for business, education, or simple visit. Experience Yacht Harbor views and 5 Star Hilton Hawaiian Village.","score":{"$numberDouble":"0.6787109375"}}
    {"summary":"A friendly apartment block where everyone knows each other and there is a strong communal vibe. Property has a huge backyard with vege garden and skate ramp. 7min walk to the beach and 2min to buses.","score":{"$numberDouble":"0.671875"},"_id":"10209136"}
    {"_id":"10227000","summary":"THIS IS A VERY SPACIOUS 1 BEDROOM FULL CONDO (SLEEPS 4) AT THE BEAUTIFUL VALLEY ISLE RESORT ON THE BEACH IN LAHAINA, MAUI!! YOU WILL LOVE THE PERFECT LOCATION OF THIS VERY NICE HIGH RISE! ALSO THIS SPACIOUS FULL CONDO, FULL KITCHEN, BIG BALCONY!!","score":{"$numberDouble":"0.6669921875"}}
    {"_id":"10264100","summary":"Having a large airy living room. The apartment is well divided. Fully furnished and cozy. The building has a 24h doorman and camera services in the corridors. It is very well located, close to the beach, restaurants, pubs and several shops and supermarkets. And it offers a good mobility being close to the subway.","score":{"$numberDouble":"0.6669921875"}}

    Seus resultados podem ser diferentes porque as incorporações geradas podem variar conforme o seu ambiente.

Crie um bloco de anotações Python interativo salvando um arquivo com a extensão .ipynb e, em seguida, execute as seguintes etapas no bloco de anotações. Para tentar o exemplo, substitua os espaços reservados por valores válidos.

Trabalhe com uma versão executável deste tutorial como um notebook do Python.

1

Execute o seguinte comando para instalar a Voyage AI e o driver PyMongo. Você deve instalar o driver do PyMongo v4.10 ou posterior.

pip install --quiet --upgrade voyageai pymongo

Esta operação pode levar alguns minutos para ser concluída.

2

Nesta etapa, você define funções para as seguintes finalidades:

  • Gere incorporações usando o Voyage AI.

  • Converta incorporações em vetores BSON usando o driver PyMongo.

Copie, cole e execute o código de exemplo abaixo após substituir o seguinte valor do espaço reservado (destacado no código):

Espaço reservado
Valor Válido

<VOYAGE-API-KEY>

Chave de API da Voyage AI a ser usada para gerar incorporações.

1import os
2import voyageai
3from bson.binary import Binary, BinaryVectorDtype
4
5# Initialize the Voyage AI Client
6os.environ["VOYAGE_API_KEY"] = "<VOYAGEAI-API-KEY>"
7vo = voyageai.Client()
8
9# Define a function to generate embeddings for all strings in `texts`
10def generate_embeddings(texts, model: str, dtype: str, output_dimension: int):
11 embeddings = []
12 for text in texts: # Process eachstring in the data list
13 embedding = vo.embed(
14 texts=[text], # Pass each string as a list with a single item
15 model=model,
16 output_dtype=dtype,
17 output_dimension=output_dimension,
18 ).embeddings[0]
19 embeddings.append(embedding) # Collect the embedding for the current text
20 return embeddings
21
22# Convert embeddings to BSON vectors
23def generate_bson_vector(vector, vector_dtype):
24 return Binary.from_vector(vector, vector_dtype)
3

Para este exemplo, use as frases de exemplo no código a seguir.

1data = [
2 "The Great Wall of China is visible from space.",
3 "The Eiffel Tower was completed in Paris in 1889.",
4 "Mount Everest is the highest peak on Earth at 8,848m.",
5 "Shakespeare wrote 37 plays and 154 sonnets during his lifetime.",
6 "The Mona Lisa was painted by Leonardo da Vinci.",
7]
4

Nesta etapa, você gera incorporações para os dados de amostra e, em seguida, converte as incorporações em vetores BSON usando as generate_embeddings generate_bson_vector funções e, respectivamente.

  1. Gere as incorporações usando o Voyage AI.

    Esta etapa é necessária se você ainda não gerou incorporações de seus dados. Se você já gerou incorporações, pule esta etapa. Para saber mais sobre como gerar incorporações de seus dados, consulte Como criar incorporações vetoriais.

    Copie, cole e execute o código de exemplo abaixo após substituir os seguintes valores de espaço reservado (destacados no código):

    Espaço reservado
    Valor Válido

    <EMBEDDING-MODEL>

    Modelo de incorporação a ser usado para gerar as incorporações. Para este exemplo, especifique voyage-3-large.

    <NUMBER-OF-DIMENSIONS>

    Número de dimensões para as incorporações de saída resultantes. Para este exemplo, especifique 1024.

    1# Use the function with different output data types to generate embeddings
    2model_name = "<EMBEDDING-MODEL>"
    3output_dimension = <NUMBER-OF-DIMENSIONS>
    4
    5# Generate embeddings in all supported data types
    6float32_embeddings = generate_embeddings(data, model=model_name, dtype="float", output_dimension=output_dimension)
    7int8_embeddings = generate_embeddings(data, model=model_name, dtype="int8", output_dimension=output_dimension)
    8int1_embeddings = generate_embeddings(data, model=model_name, dtype="ubinary", output_dimension=output_dimension)
  2. Converta as incorporações em vetores BSON.

    Copie, cole e execute o seguinte código:

    1# For all vectors in your collection, generate BSON vectors of float32, int8, and int1 embeddings
    2bson_float32_embeddings = []
    3bson_int8_embeddings = []
    4bson_int1_embeddings = []
    5for i, (f32_emb, int8_emb, int1_emb) in enumerate(zip(float32_embeddings, int8_embeddings, int1_embeddings)):
    6 bson_float32_embeddings.append(generate_bson_vector(f32_emb, BinaryVectorDtype.FLOAT32))
    7 bson_int8_embeddings.append(generate_bson_vector(int8_emb, BinaryVectorDtype.INT8))
    8 bson_int1_embeddings.append(generate_bson_vector(int1_emb, BinaryVectorDtype.PACKED_BIT))
5

Você pode carregar seus dados a partir da UI do Atlas e programaticamente. Para saber como carregar seus dados a partir da UI do Atlas , consulte Inserir seus dados.

  1. Crie documentos a partir dos dados de amostra e incorporações.

    Copie, cole e execute o código de exemplo abaixo após substituir os seguintes valores de espaço reservado (destacados no código):

    Espaço reservado
    Valor Válido

    <FIELD-NAME-FOR-FLOAT32-TYPE>

    Nome do campo com valores float32.

    <FIELD-NAME-FOR-INT8-TYPE>

    Nome do campo com valores int8.

    <FIELD-NAME-FOR-INT1-TYPE>

    Nome do campo com valores int1.

    <TEXT-FIELD-NAME>

    Nome do campo onde você deseja armazenar os dados de texto.

    1# Specify the field names for the float32, int8, and int1 embeddings
    2float32_field = "<FIELD-NAME-FOR-FLOAT32-TYPE>"
    3int8_field = "<FIELD-NAME-FOR-INT8-TYPE>"
    4int1_field = "<FIELD-NAME-FOR-INT1-TYPE>"
    5
    6# Define function to create documents with BSON vector embeddings
    7def create_new_docs_with_bson_vectors(bson_float32_embeddings, bson_int8_embeddings, bson_int1_embeddings, data):
    8 docs = []
    9 for i, (bson_f32_emb, bson_int8_emb, bson_int1_emb, text) in enumerate(zip(bson_float32_embeddings, bson_int8_embeddings, bson_int1_embeddings, data)):
    10
    11 doc = {
    12 "_id": i,
    13 "<TEXT-FIELD-NAME>": text,
    14 float32_field: bson_f32_emb,
    15 int8_field: bson_int8_emb,
    16 int1_field: bson_int1_emb
    17 }
    18 docs.append(doc)
    19 return docs
    20
    21# Create the documents
    22documents = create_new_docs_with_bson_vectors(bson_float32_embeddings, bson_int8_embeddings, bson_int1_embeddings, data)
  2. Carregue seus dados em seu cluster do Atlas.

    Copie, cole e execute o código de exemplo abaixo após substituir os seguintes valores de espaço reservado (destacados no código):

    Espaço reservado
    Valor Válido

    <CONNECTION-STRING>

    string de conexão do cluster. Para saber mais, consulte Conectar via drivers.

    <DATABASE-NAME>

    Nome do banco de dados.

    <COLLECTION-NAME>

    Nome da collection no banco de dados especificado .

    1import pymongo
    2
    3mongo_client = pymongo.MongoClient("<CONNECTION-STRING>")
    4# Insert documents into a new database and collection
    5db = mongo_client["<DATABASE-NAME>"]
    6collection_name = "<COLLECTION-NAME>"
    7db.create_collection(collection_name)
    8collection = db[collection_name]
    9
    10collection.insert_many(documents)
6

Você pode criar índices do Atlas Vector Search usando a IU do Atlas, a CLI do Atlas, a Administration API do Atlas e os drivers do MongoDB. Para saber mais, consulte Como indexar campos do Vector Search.

Copie, cole e execute o código de exemplo abaixo após substituir o seguinte valor do espaço reservado (destacado no código):

Espaço reservado
Valor Válido

<INDEX-NAME>

Nome do índice de tipo vector.

1from pymongo.operations import SearchIndexModel
2import time
3
4# Define and create the vector search index
5index_name = "<INDEX-NAME>"
6search_index_model = SearchIndexModel(
7 definition={
8 "fields": [
9 {
10 "type": "vector",
11 "path": float32_field,
12 "similarity": "dotProduct",
13 "numDimensions": 1024
14 },
15 {
16 "type": "vector",
17 "path": int8_field,
18 "similarity": "dotProduct",
19 "numDimensions": 1024
20 },
21 {
22 "type": "vector",
23 "path": int1_field,
24 "similarity": "euclidean",
25 "numDimensions": 1024
26 }
27 ]
28 },
29 name=index_name,
30 type="vectorSearch"
31)
32result = collection.create_search_index(model=search_index_model)
33print("New search index named " + result + " is building.")
34
35# Wait for initial sync to complete
36print("Polling to check if the index is ready. This may take up to a minute.")
37predicate=None
38if predicate is None:
39 predicate = lambda index: index.get("queryable") is True
40while True:
41 indices = list(collection.list_search_indexes(index_name))
42 if len(indices) and predicate(indices[0]):
43 break
44 time.sleep(5)
45print(result + " is ready for querying.")
New search index named <INDEX-NAME> is building.
Polling to check if the index is ready. This may take up to a minute.
<INDEX-NAME> is ready for querying.
7
  1. Defina uma função para executar uma query de pesquisa vetorial .

    A função para executar queries do Atlas Vector Search executa as seguintes ações:

    • Gera incorporações usando o Voyage AI para o texto da query.

    • Converte as incorporações em vetores BSON.

    • Define o pipeline de agregação para a pesquisa vetorial.

    • Executa o pipeline de agregação e retorna os resultados.

    Copie, cole e execute o código de exemplo abaixo após substituir os seguintes valores de espaço reservado (destacados no código):

    Espaço reservado
    Valor Válido

    <NUMBER-OF-CANDIDATES-TO-CONSIDER>

    Número de vizinhos mais próximos a serem utilizados durante a pesquisa. Para este exemplo, especifique 5.

    <NUMBER-OF-DOCUMENTS-TO-RETURN>

    Número de documentos a retornar nos resultados. Para este exemplo, especifique 2.

    <EMBEDDING-MODEL>

    Modelo de incorporação a ser usado para gerar as incorporações. Para este exemplo, especifique voyage-3-large.

    <TEXT-FIELD-NAME>

    Nome do campo que contém os dados de texto.

    1import voyageai
    2from bson.binary import Binary, BinaryVectorDtype
    3
    4# Define a function to run a vector search query
    5def run_vector_search(query_text, collection, path):
    6 # Map path to output dtype and BSON vector type
    7 path_to_dtype = {
    8 float32_field: ("float", BinaryVectorDtype.FLOAT32),
    9 int8_field: ("int8", BinaryVectorDtype.INT8),
    10 int1_field: ("ubinary", BinaryVectorDtype.PACKED_BIT),
    11 }
    12
    13 if path not in path_to_dtype:
    14 raise ValueError("Invalid path. Must be one of float32_field, int8_field, int1_field.")
    15
    16 # Get Voyage AI output dtype and BSON vector type based on the path
    17 output_dtype, bson_dtype = path_to_dtype[path]
    18
    19 # Generate query embeddings using Voyage AI
    20 query_vector = vo.embed(
    21 texts=[query_text],
    22 model="<EMBEDDING-MODEL>",
    23 input_type="query",
    24 output_dtype=output_dtype
    25 ).embeddings[0]
    26
    27 # Convert the query vector to BSON format
    28 bson_query_vector = Binary.from_vector(query_vector, bson_dtype)
    29
    30 # Define the aggregation pipeline for vector search
    31 pipeline = [
    32 {
    33 "$vectorSearch": {
    34 "index": index_name, # Replace with your index name
    35 "path": path, # Path to the embedding field
    36 "queryVector": bson_query_vector, # BSON-encoded query vector
    37 "numCandidates": <NUMBER-OF-CANDIDATES-TO-CONSIDER>,
    38 "limit": <NUMBER-OF-DOCUMENTS-TO-RETURN>
    39 }
    40 },
    41 {
    42 "$project": {
    43 "_id": 0,
    44 "<TEXT-FIELD-NAME>": 1,
    45 "score": { "$meta": "vectorSearchScore" } # Include the similarity score
    46 }
    47 }
    48 ]
    49
    50 # Run the aggregation pipeline and return results
    51 return collection.aggregate(pipeline)
  2. Execute a query do Atlas Vector Search.

    Copie, cole e execute o código de exemplo abaixo após substituir o seguinte valor do espaço reservado conforme destacado no código:

    Espaço reservado
    Valor Válido

    <QUERY-TEXT>

    String de texto para a qual recuperar documentos semanticamente semelhantes. Para este exemplo, especifique science fact.

    1from pprint import pprint
    2
    3# Define a list of embedding fields to query
    4embedding_fields = [float32_field, int8_field, int1_field]
    5results = {}
    6
    7# Run vector search queries for each embedding type
    8query_text = "<QUERY-TEXT>"
    9for field in embedding_fields:
    10 results[field] = list(run_vector_search(query_text, collection, field))
    11
    12# Print the results
    13for field, field_results in results.items():
    14 print(f"Results from {field}")
    15 pprint(field_results)
    Results from float32-embeddings embeddings
    [{'data': 'The Great Wall of China is visible from space.',
    'score': 0.7810189723968506},
    {'data': 'Mount Everest is the highest peak on Earth at 8,848m.',
    'score': 0.7339795827865601}]
    Results from int8-embeddings embeddings
    [{'data': 'The Great Wall of China is visible from space.',
    'score': 0.5053843259811401},
    {'data': 'Mount Everest is the highest peak on Earth at 8,848m.',
    'score': 0.5043729543685913}]
    Results from int1-embeddings embeddings
    [{'data': 'The Great Wall of China is visible from space.', 'score': 0.6640625},
    {'data': 'Mount Everest is the highest peak on Earth at 8,848m.',
    'score': 0.6220703125}]

    Para mais informações sobre queries do Atlas Vector Search , consulte Executar queries do Vector Search .

Trabalhe com uma versão executável deste tutorial como um notebook do Python.

1

Execute o seguinte comando para instalar a Voyage AI e o driver PyMongo. Você deve instalar o driver do PyMongo v4.10 ou posterior.

pip install --quiet --upgrade voyageai pymongo

Esta operação pode levar alguns minutos para ser concluída.

2

Nesta etapa, você define funções para as seguintes finalidades:

  • Gere incorporações usando o Voyage AI.

  • Converta incorporações em vetores BSON usando o driver PyMongo.

Copie, cole e execute o código de exemplo abaixo após substituir o seguinte valor do espaço reservado (destacado no código):

Espaço reservado
Valor Válido

<VOYAGE-API-KEY>

Chave de API da Voyage AI a ser usada para gerar incorporações.

1import os
2import voyageai
3from bson.binary import Binary, BinaryVectorDtype
4
5# Initialize the Voyage AI Client
6os.environ["VOYAGE_API_KEY"] = "<VOYAGEAI-API-KEY>"
7vo = voyageai.Client()
8
9# Define a function to generate embeddings for all strings in `texts`
10def generate_embeddings(texts, model: str, dtype: str, output_dimension: int):
11 embeddings = []
12 for text in texts: # Process eachstring in the data list
13 embedding = vo.embed(
14 texts=[text], # Pass each string as a list with a single item
15 model=model,
16 output_dtype=dtype,
17 output_dimension=output_dimension,
18 ).embeddings[0]
19 embeddings.append(embedding) # Collect the embedding for the current text
20 return embeddings
21
22# Convert embeddings to BSON vectors
23def generate_bson_vector(vector, vector_dtype):
24 return Binary.from_vector(vector, vector_dtype)
3

Você deve fornecer o seguinte:

  • String de conexão para conectar ao seu Atlas cluster que contém o banco de dados e a coleção para a qual você deseja gerar incorporações.

  • Nome do banco de dados que contém a collection para a qual você deseja gerar embeddings.

  • Nome da collection para a qual você deseja gerar incorporações.

Para recuperar os dados, copie, cole e execute o código de exemplo abaixo após substituir os valores de espaço reservado (destacados no código):

Espaço reservado
Valor Válido

<CONNECTION-STRING>

string de conexão do cluster. Para saber mais, consulte Conectar via drivers.

<DATABASE-NAME>

Nome do banco de dados que contém a collection para a qual você deseja gerar e converter embeddings. Para este exemplo, especifique sample_airbnb.

<COLLECTION-NAME>

Nome da collection para a qual você deseja gerar e converter incorporações. Para este exemplo, especifique listingsAndReviews.

<TEXT-FIELD-NAME>

Nome do campo de texto para o qual você deseja gerar incorporações. Para este exemplo, especifique summary.

1import pymongo
2
3# Connect to your Atlas cluster
4mongo_client = pymongo.MongoClient("<CONNECTION-STRING>")
5db = mongo_client["<DATABASE-NAME>"]
6collection = db["<COLLECTION-NAME>"]
7
8# Filter to exclude null or empty summary fields
9filter = { "<TEXT-FIELD-NAME>": {"$nin": [None, ""]} }
10
11# Get a subset of documents in the collection
12documents = collection.find(filter).limit(50)
13
14# Initialize the count of updated documents
15updated_doc_count = 0
4

O código de amostra executa as seguintes ações:

  1. Gera incorporações a partir de seus dados usando qualquer modelo de incorporação se seus dados ainda não tiverem incorporações. Para saber mais sobre como gerar incorporações a partir dos seus dados, consulte Como criar incorporações vetoriais.

  2. Converte as incorporações em vetores BSON (como mostrado na linha 7 no exemplo a seguir).

  3. Carrega as incorporações na sua coleção no Atlas cluster.

Essa operação pode levar alguns minutos para ser concluída.

Copie, cole e execute o código abaixo após substituir os seguintes valores de espaço reservado (destacados no código):

Espaço reservado
Valor Válido

<EMBEDDING-MODEL>

Modelo de incorporação a ser usado para gerar as incorporações. Para este exemplo, especifique voyage-3-large.

<NUMBER-OF-DIMENSIONS>

Número de dimensões para as incorporações de saída resultantes. Para este exemplo, especifique 1024.

<FIELD-NAME-FOR-FLOAT32-TYPE>

Nome do campo com valores float32.

<FIELD-NAME-FOR-INT8-TYPE>

Nome do campo com valores int8.

<FIELD-NAME-FOR-INT1-TYPE>

Nome do campo com valores int1.

<EMBEDDING-MODEL>

Modelo de incorporação a ser usado para gerar as incorporações. Para este exemplo, especifique voyage-3-large.

<TEXT-FIELD-NAME>

Nome do campo de texto para o qual você gerou incorporações. Para este exemplo, especifique summary.

1model_name = "<EMBEDDING-MODEL>"
2output_dimension = <NUMBER-OF-DIMENSIONS>
3float32_field = "<FIELD-NAME-FOR-FLOAT32-TYPE>"
4int8_field = "<FIELD-NAME-FOR-INT8-TYPE>"
5int1_field = "<FIELD-NAME-FOR-INT1-TYPE>"
6
7# Process and update each document
8updated_doc_count = 0
9for document in documents:
10 summary = document.get("<TEXT-FIELD-NAME>")
11 if not summary:
12 continue
13
14 # Generate embeddings for the summary field
15 float_embeddings = generate_embeddings([summary], model=model_name, dtype="float", output_dimension=output_dimension)
16 int8_embeddings = generate_embeddings([summary], model=model_name, dtype="int8", output_dimension=output_dimension)
17 ubinary_embeddings = generate_embeddings([summary], model=model_name, dtype="ubinary", output_dimension=output_dimension)
18
19 # Convert embeddings to BSON-compatible format
20 bson_float = generate_bson_vector(float_embeddings[0], BinaryVectorDtype.FLOAT32)
21 bson_int8 = generate_bson_vector(int8_embeddings[0], BinaryVectorDtype.INT8)
22 bson_ubinary = generate_bson_vector(ubinary_embeddings[0], BinaryVectorDtype.PACKED_BIT)
23
24 # Prepare the updated document
25 updated_fields = {
26 float32_field: bson_float,
27 int8_field: bson_int8,
28 int1_field: bson_ubinary,
29 }
30
31 # Update the document in MongoDB
32 result = collection.update_one({"_id": document["_id"]}, {"$set": updated_fields})
33 if result.modified_count > 0:
34 updated_doc_count += 1
35
36# Print the results
37print(f"Number of documents updated: {updated_doc_count}")
5

Você pode criar índices do Atlas Vector Search usando a IU do Atlas, a CLI do Atlas, a Administration API do Atlas e os drivers do MongoDB. Para saber mais, consulte Como indexar campos do Vector Search.

Para criar o índice, copie, cole e execute o código de exemplo abaixo após substituir o seguinte valor de espaço reservado (destacado no código):

Espaço reservado
Valor Válido

<INDEX-NAME>

Nome do índice de tipo vector.

1from pymongo.operations import SearchIndexModel
2import time
3
4# Define and create the vector search index
5index_name = "<INDEX-NAME>"
6search_index_model = SearchIndexModel(
7 definition={
8 "fields": [
9 {
10 "type": "vector",
11 "path": float32_field,
12 "similarity": "dotProduct",
13 "numDimensions": 1024
14 },
15 {
16 "type": "vector",
17 "path": int8_field,
18 "similarity": "dotProduct",
19 "numDimensions": 1024
20 },
21 {
22 "type": "vector",
23 "path": int1_field,
24 "similarity": "euclidean",
25 "numDimensions": 1024
26 }
27 ]
28 },
29 name=index_name,
30 type="vectorSearch"
31)
32result = collection.create_search_index(model=search_index_model)
33print("New search index named " + result + " is building.")
34
35# Wait for initial sync to complete
36print("Polling to check if the index is ready. This may take up to a minute.")
37predicate=None
38if predicate is None:
39 predicate = lambda index: index.get("queryable") is True
40while True:
41 indices = list(collection.list_search_indexes(index_name))
42 if len(indices) and predicate(indices[0]):
43 break
44 time.sleep(5)
45print(result + " is ready for querying.")
New search index named <INDEX-NAME> is building.
Polling to check if the index is ready. This may take up to a minute.
<INDEX-NAME> is ready for querying.
6
  1. Defina uma função para executar uma query de pesquisa vetorial .

    A função para executar queries do Atlas Vector Search executa as seguintes ações:

    • Gera incorporações usando o Voyage AI para o texto da query.

    • Converte as incorporações em vetores BSON.

    • Define o pipeline de agregação para a pesquisa vetorial.

    • Executa o pipeline de agregação e retorna os resultados.

    Espaço reservado
    Valor Válido

    <NUMBER-OF-CANDIDATES-TO-CONSIDER>

    Número de vizinhos mais próximos a serem utilizados durante a pesquisa. Para este exemplo, especifique 20

    <NUMBER-OF-DOCUMENTS-TO-RETURN>

    Número de documentos a retornar nos resultados. Para este exemplo, especifique 5.

    <TEXT-FIELD-NAME>

    Nome do campo que contém os dados de texto. Para este exemplo, especifique summary.

    1import voyageai
    2from bson.binary import Binary, BinaryVectorDtype
    3
    4# Define a function to run a vector search query
    5def run_vector_search(query_text, collection, path):
    6 # Map path to output dtype and BSON vector type
    7 path_to_dtype = {
    8 float32_field: ("float", BinaryVectorDtype.FLOAT32),
    9 int8_field: ("int8", BinaryVectorDtype.INT8),
    10 int1_field: ("ubinary", BinaryVectorDtype.PACKED_BIT),
    11 }
    12
    13 if path not in path_to_dtype:
    14 raise ValueError("Invalid path. Must be one of float32_field, int8_field, int1_field.")
    15
    16 # Get Voyage AI output dtype and BSON vector type based on the path
    17 output_dtype, bson_dtype = path_to_dtype[path]
    18
    19 # Generate query embeddings using Voyage AI
    20 query_vector = vo.embed(
    21 texts=[query_text],
    22 model="<EMBEDDING-MODEL>",
    23 input_type="query",
    24 output_dtype=output_dtype
    25 ).embeddings[0]
    26
    27 # Convert the query vector to BSON format
    28 bson_query_vector = Binary.from_vector(query_vector, bson_dtype)
    29
    30 # Define the aggregation pipeline for vector search
    31 pipeline = [
    32 {
    33 "$vectorSearch": {
    34 "index": index_name, # Replace with your index name
    35 "path": path, # Path to the embedding field
    36 "queryVector": bson_query_vector, # BSON-encoded query vector
    37 "numCandidates": <NUMBER-OF-CANDIDATES-TO-CONSIDER>,
    38 "limit": <NUMBER-OF-DOCUMENTS-TO-RETURN>
    39 }
    40 },
    41 {
    42 "$project": {
    43 "_id": 0,
    44 "<TEXT-FIELD-NAME>": 1,
    45 "score": { "$meta": "vectorSearchScore" } # Include the similarity score
    46 }
    47 }
    48 ]
    49
    50 # Run the aggregation pipeline and return results
    51 return collection.aggregate(pipeline)
  2. Execute a query do Atlas Vector Search.

    Você pode executar queries do Atlas Vector Search de forma programática. Para saber mais, consulte Executar queries de pesquisa vetorial.

    Espaço reservado
    Valor Válido

    <QUERY-TEXT>

    String de texto para a qual recuperar documentos semanticamente semelhantes. Para este exemplo, especifique ocean view.

    1from pprint import pprint
    2
    3# Define a list of embedding fields to query
    4embedding_fields = [float32_field, int8_field, int1_field]
    5results = {}
    6
    7# Run vector search queries for each embedding type
    8query_text = "<QUERY-TEXT>"
    9for field in embedding_fields:
    10 results[field] = list(run_vector_search(query_text, collection, field))
    11
    12# Print the results
    13for field, field_results in results.items():
    14 print(f"Results from {field}")
    15 pprint(field_results)
    Results from float32-embeddings
    [{'score': 0.8044508695602417,
    'summary': 'A beautiful and comfortable 1 Bedroom Air Conditioned Condo in '
    'Makaha Valley - stunning Ocean & Mountain views All the '
    'amenities of home, suited for longer stays. Full kitchen & large '
    "bathroom. Several gas BBQ's for all guests to use & a large "
    'heated pool surrounded by reclining chairs to sunbathe. The '
    'Ocean you see in the pictures is not even a mile away, known as '
    'the famous Makaha Surfing Beach. Golfing, hiking,snorkeling '
    'paddle boarding, surfing are all just minutes from the front '
    'door.'},
    {'score': 0.7622430920600891,
    'summary': 'THIS IS A VERY SPACIOUS 1 BEDROOM FULL CONDO (SLEEPS 4) AT THE '
    'BEAUTIFUL VALLEY ISLE RESORT ON THE BEACH IN LAHAINA, MAUI!! YOU '
    'WILL LOVE THE PERFECT LOCATION OF THIS VERY NICE HIGH RISE! ALSO '
    'THIS SPACIOUS FULL CONDO, FULL KITCHEN, BIG BALCONY!!'},
    {'score': 0.7484776973724365,
    'summary': 'Para 2 pessoas. Vista de mar a 150 mts. Prédio com 2 elevadores. '
    'Tem: - quarto com roupeiro e cama de casal (colchão '
    'magnetizado); - cozinha: placa de discos, exaustor, frigorifico, '
    'micro-ondas e torradeira; casa de banho completa; - sala e '
    'varanda.'},
    {'score': 0.7452666759490967,
    'summary': 'Quarto com vista para a Lagoa Rodrigo de Freitas, cartão postal '
    'do Rio de Janeiro. Linda Vista. 1 Quarto e 1 banheiro Amplo, '
    'arejado, vaga na garagem. Prédio com piscina, sauna e '
    'playground. Fácil acesso, próximo da praia e shoppings.'},
    {'score': 0.73777174949646,
    'summary': 'próximo aos principais pontos turísticos,,do lado do metro, '
    'vista p o CRISTO REDENTOR, GARAGEM, FAXINEIRA, PLAY.'}]
    Results from int8-embeddings embeddings
    [{'score': 0.5057082176208496,
    'summary': 'A beautiful and comfortable 1 Bedroom Air Conditioned Condo in '
    'Makaha Valley - stunning Ocean & Mountain views All the '
    'amenities of home, suited for longer stays. Full kitchen & large '
    "bathroom. Several gas BBQ's for all guests to use & a large "
    'heated pool surrounded by reclining chairs to sunbathe. The '
    'Ocean you see in the pictures is not even a mile away, known as '
    'the famous Makaha Surfing Beach. Golfing, hiking,snorkeling '
    'paddle boarding, surfing are all just minutes from the front '
    'door.'},
    {'score': 0.5048595666885376,
    'summary': 'THIS IS A VERY SPACIOUS 1 BEDROOM FULL CONDO (SLEEPS 4) AT THE '
    'BEAUTIFUL VALLEY ISLE RESORT ON THE BEACH IN LAHAINA, MAUI!! YOU '
    'WILL LOVE THE PERFECT LOCATION OF THIS VERY NICE HIGH RISE! ALSO '
    'THIS SPACIOUS FULL CONDO, FULL KITCHEN, BIG BALCONY!!'},
    {'score': 0.5045757293701172,
    'summary': 'Para 2 pessoas. Vista de mar a 150 mts. Prédio com 2 elevadores. '
    'Tem: - quarto com roupeiro e cama de casal (colchão '
    'magnetizado); - cozinha: placa de discos, exaustor, frigorifico, '
    'micro-ondas e torradeira; casa de banho completa; - sala e '
    'varanda.'},
    {'score': 0.5044537782669067,
    'summary': 'Quarto com vista para a Lagoa Rodrigo de Freitas, cartão postal '
    'do Rio de Janeiro. Linda Vista. 1 Quarto e 1 banheiro Amplo, '
    'arejado, vaga na garagem. Prédio com piscina, sauna e '
    'playground. Fácil acesso, próximo da praia e shoppings.'},
    {'score': 0.5044353604316711,
    'summary': 'The ultimate way to experience Sydney Harbour; fireworks, the '
    'bridge, and the proximity to the city means you can experience '
    'everything this city has to offer. Tucked into the Balmain '
    "Peninsula, you're close to parks, pubs, shops, buses, and more!"}]
    Results from int1-embeddings embeddings
    [{'score': 0.7158203125,
    'summary': 'A beautiful and comfortable 1 Bedroom Air Conditioned Condo in '
    'Makaha Valley - stunning Ocean & Mountain views All the '
    'amenities of home, suited for longer stays. Full kitchen & large '
    "bathroom. Several gas BBQ's for all guests to use & a large "
    'heated pool surrounded by reclining chairs to sunbathe. The '
    'Ocean you see in the pictures is not even a mile away, known as '
    'the famous Makaha Surfing Beach. Golfing, hiking,snorkeling '
    'paddle boarding, surfing are all just minutes from the front '
    'door.'},
    {'score': 0.6865234375,
    'summary': 'Para 2 pessoas. Vista de mar a 150 mts. Prédio com 2 elevadores. '
    'Tem: - quarto com roupeiro e cama de casal (colchão '
    'magnetizado); - cozinha: placa de discos, exaustor, frigorifico, '
    'micro-ondas e torradeira; casa de banho completa; - sala e '
    'varanda.'},
    {'score': 0.677734375,
    'summary': 'próximo aos principais pontos turísticos,,do lado do metro, '
    'vista p o CRISTO REDENTOR, GARAGEM, FAXINEIRA, PLAY.'},
    {'score': 0.6748046875,
    'summary': 'Cozy and comfortable apartment. Ideal for families and '
    'vacations. 3 bedrooms, 2 of them suites. Located 20-min walk '
    'to the beach and close to the Rio 2016 Olympics Venues. Situated '
    'in a modern and secure condominium, with many entertainment '
    'available options around.'},
    {'score': 0.6728515625,
    'summary': 'THIS IS A VERY SPACIOUS 1 BEDROOM FULL CONDO (SLEEPS 4) AT THE '
    'BEAUTIFUL VALLEY ISLE RESORT ON THE BEACH IN LAHAINA, MAUI!! YOU '
    'WILL LOVE THE PERFECT LOCATION OF THIS VERY NICE HIGH RISE! ALSO '
    'THIS SPACIOUS FULL CONDO, FULL KITCHEN, BIG BALCONY!!'}]

Você pode medir a precisão de sua query do Atlas Vector Search avaliando a proximidade dos resultados de uma pesquisa de ANN com os resultados de uma pesquisa de ENN em relação aos seus vetores quantizados. Ou seja, você pode comparar os resultados da pesquisa ANN com os resultados da pesquisa ENN para os mesmos critérios de consulta e medir com que frequência os resultados da pesquisa ANN incluem os vizinhos mais próximos nos resultados da pesquisa ENN.

Para uma demonstração da avaliação dos resultados da query, consulte Como medir a precisão dos resultados da query.

Voltar

Transformar documentos e filtrar coleções

Nesta página