vector-quantization
For the complete MongoDB documentation index, see www.mongodb.com/docs/llms.txt
<!-- Tab options on this page. Append to the .md URL to filter: ?tabs=<id,...> select specific tabs (e.g. ?tabs=nodejs,shell) ?allTabs=true include every tab (no param) default: one tab per tabset
Available tabs: other tabs: maven, gradle, cloud, local -->
Vector Quantization
MongoDB Vector Search supports automatic quantization of your float vector embeddings (both 32-bit and 64-bit). It also supports ingesting and indexing your pre-quantized scalar and binary vectors from certain embedding models.
About Quantization
Quantization is the process of shrinking full-fidelity vectors into fewer bits. It reduces the amount of main memory required to store each vector in a MongoDB Vector Search index by indexing the reduced representation vectors instead. This allows for storage of more vectors or vectors with higher dimensions. Therefore, quantization reduces resource consumption and improves speed. We recommend quantization for applications with a large number of vectors, such as over 100,000.
Scalar Quantization
Binary Quantization
Binary quantization involves assuming a midpoint of 0 for each dimension, which is typically appropriate for embeddings normalized to length 1 such as OpenAI's text-embedding-3-large. Then, each value in the vector is compared to the midpoint and assigned a binary value of 1 if it's greater than the midpoint and a binary value of 0 if it's less than or equal to the midpoint. In MongoDB Vector Search, this quantization reduces the vector embedding's RAM cost to one twenty-fourth (1/24) of the pre-quantization cost. The reason it's not 1/32 is because the data structure containing the Hierarchical Navigable Small Worlds graph itself, separate from the vector values, isn't compressed.
When you run a query, MongoDB Vector Search converts the float value in the query vector into a binary vector using the same midpoint for efficient comparison between the query vector and indexed binary vectors. It then rescores by reevaluating the identified candidates in the binary comparison using the original float values associated with those results from the binary index to further refine the results. The full fidelity vectors are stored in their own data structure on disk, and are only referenced during rescoring when you configure binary quantization or when you perform exact search against either binary or scalar quantized vectors.
Requirements
The following table shows the requirements for automatically quantizing and ingesting quantized vectors.
| Requirement | For int1 Ingestion |
For int8 Ingestion |
For Automatic Scalar Quantization | For Automatic Binary Quantization | For int8 Ingestion with Automatic Binary Quantization |
|---|---|---|---|---|---|
| Requires index definition settings | No | No | Yes | Yes | Yes |
Requires BSON (Binary Javascript Object Notation) binData format |
Yes | Yes | No | No | Yes |
| Storage on mongod | binData(int1) |
binData(int8) |
binData(float32)``array(double) |
binData(float32)``array(double) |
binData(int8) |
| Supported Similarity method | euclidean |
cosine``euclidean``dotProduct |
cosine``euclidean``dotProduct |
cosine``euclidean``dotProduct |
cosine``euclidean``dotProduct |
| Maximum Dimensionality | Multiple of 8 | 8192 | 8192 | 8192 | Multiple of 8 |
| Supports ANN (Approximate Nearest Neighbor) and ENN (Exact Nearest Neighbor) Search | Yes | Yes | Yes | Yes | Yes |
Note:
Atlas stores all floating-point values as the double data type internally; therefore, both 32-bit and 64-bit embeddings are compatible with automatic quantization without conversion.
How to Enable Automatic Quantization of Vectors
You can configure MongoDB Vector Search to automatically quantize float vector embeddings in your collection to reduced representation types, such as int8 (scalar) and binary in your vector indexes.
To set or change the quantization type, specify a quantization field value of either scalar or binary in your index definition. This triggers an index rebuild similar to any other index definition change. The specified quantization type applies to all indexed vectors and query vectors at query-time. You don't need to change your query as your query vectors are automatically quantized.
For most embedding models, we recommend binary quantization with rescoring. If you want to use lower dimension models that are not QAT (Quantization-Aware-Trained), use scalar quantization because it has less representational loss and therefore, incurs less representational capacity loss.
Benefits
MongoDB Vector Search provides native capabilities for scalar quantization as well as binary quantization with rescoring. Automatic quantization increases scalability and cost savings for your applications by reducing the computational resources for efficient processing of your vectors. Automatic quantization reduces the RAM for mongot by 3.75x for scalar and by 24x for binary; the vector values shrink by 4x and 32x respectively, but Hierarchical Navigable Small Worlds graph itself does not shrink. This improves performance, even at the highest volume and scale.
Use Cases
We recommend automatic quantization if you have large number of full fidelity vectors, typically over 100,000 vectors. After quantization, you index reduced representation vectors without compromising the accuracy when retrieving vectors.
Procedure
To enable automatic quantization:
- Specify the type of quantization you want in your MongoDB Vector Search index.
In a new or existing MongoDB Vector Search index, specify one of the following quantization types in the fields.quantization field for your [index definition:](https://www.mongodb.com/docs/vector-search/indexes/vector-search-type.md#std-label-avs-index-definition
-
scalar: to produce byte vectors from float input vectors. -
binary: to produce bit vectors from float orbinData(int8)input vectors.
If you specify scalar quantization on vectors that are not float or double arrays, binData(float32), or binary quantization on binData(int1) vectors, MongoDB Vector Search silently ignores that vector instead of indexing it, and those vectors will be skipped. Since Atlas stores float values (both 32-bit and 64-bit) as the double type internally, embeddings from models that output either precision will work with automatic quantization.
- Create or update the index.
The index should take about one minute to build. While it builds, the index is in an [initial sync](https://www.mongodb.com/docs/search/performance/index-performance.md#std-label-troubleshoot-initial-sync state. When it finishes building, you can start querying the data in your collection.
The specified quantization type applies to all indexed vectors and query vectors at query-time.
Considerations
When you view your quantized index [in the Atlas UI](https://www.mongodb.com/docs/vector-search/indexes/vector-search-type.md#std-label-avs-view-index-procedure, the index size might appear larger than an index without quantization. This is because the Size metric represents the total data stored, which includes the Hierarchical Navigable Small Worlds graph (in memory), the quantized vectors (in memory), and the full-fidelity vectors (on disk). To estimate the amount of memory used by the index at query-time, refer to the Required Memory metric.
How to Ingest Pre-Quantized Vectors
MongoDB Vector Search also supports ingestion and indexing of scalar and binary quantized vectors from certain embedding models. If you don't already have quantized vectors, you can convert your embeddings to BSON (Binary Javascript Object Notation) [BinData](https://www.mongodb.com/docs/manual/reference/method/BinData.md#std-label-server-binData-method vectors with float32, int1, or int8 subtype.
Use Cases
We recommend ingesting quantized BSON (Binary Javascript Object Notation) binData vectors for the following use cases:
-
You need to index quantized vector output from embedding models.
-
You have a large number of float vectors and want to reduce the storage and [WiredTiger](https://www.mongodb.com/docs/manual/core/wiredtiger.md#std-label-storage-wiredtiger footprint (such as disk and memory usage) in
mongod. -
You want binary-quantized search with a smaller
mongodstorage footprint. IngestingbinData(int8)vectors and settingquantizationtobinaryuses up to 4x less storage onmongodthan binary quantization withbinData(float32)vectors.
Benefits
[BinData](https://www.mongodb.com/docs/manual/reference/method/BinData.md#std-label-server-binData-method is a BSON (Binary Javascript Object Notation) data type that stores binary data. It compresses your vector embeddings and requires about three times less disk space in your cluster compared to embeddings that use a standard float32 array. To learn more, see [Vector Compression.](https://www.mongodb.com/docs/vector-search/crud-embeddings/create-embeddings-manual.md#std-label-avs-vector-compression
This subtype also allows you to index your vectors with alternate types such as int1 or int8 vectors, reducing the memory needed to build the MongoDB Vector Search index for your collection. It reduces the RAM for mongot by 3.75x for scalar and by 24x for binary; the vector values shrink by 4x and 32x respectively, but the Hierarchical Navigable Small Worlds graph itself doesn't shrink.
If you don't already have binData vectors, you can convert your embeddings to this format by using any supported driver before writing your data to a collection. The following procedure walks you through the steps for converting your embeddings to the [BinData](https://www.mongodb.com/docs/manual/reference/method/BinData.md#std-label-server-binData-method vectors with float32, int8, and int1 subtypes.
Supported Drivers
BSON (Binary Javascript Object Notation) [BinData](https://www.mongodb.com/docs/manual/reference/method/BinData.md#std-label-server-binData-method vectors with float32, int1, and int8 subtypes is supported by the following drivers:
-
C++ Driver v4.1.0 or later
-
C#/.NET Driver v3.2.0 or later
-
Go Driver v2.1.0 or later
-
PyMongo Driver v4.10 or later
-
Node.js Driver v6.11 or later
-
Java Driver v5.3.1 or later
-
Ruby Driver with
bsongem v5.1 or later
Prerequisites
The examples in this procedure use either new data or existing data and embeddings generated by using Voyage AI's voyage-3-large model. The example for new data uses sample text strings, which you can replace with your own data. The example for existing data uses a subset of documents without any embeddings from the listingsAndReviews collection in the sample_airbnb database, which you can replace with your own database and collection (with or without any embeddings).
Select whether you want to quantize binData vectors for new data or for data you already have in your cluster using the Data Source dropdown menu below. Select your preferred programming language as well.
To quantize your BSON (Binary Javascript Object Notation) binData vectors, you must have the following:
- A cluster running MongoDB version 6.0.11, 7.0.2, or later.
Ensure that your IP address (Internet Protocol address) is included in your Atlas project's [access list.](https://www.mongodb.com/docs/atlas/security/ip-access-list.md#std-label-access-list
- Access to an embedding model that supports byte vector output.
The outputs from the following embedding models can be used to generate BSON (Binary Javascript Object Notation) binData vectors with a supported MongoDB driver:
| Embedding Model Provider | Embedding Model |
|---|---|
| Voyage AI | voyage-3-large |
| Cohere | embed-english-v3.0 |
| Nomic | nomic-embed-text-v1.5 |
| Jina | jina-embeddings-v2-base-en |
| Mixedbread | mxbai-embed-large-v1 |
Scalar quantization preserves recall for these models because these models are all trained to be quantization aware. Therefore, [recall](https://www.mongodb.com/docs/manual/reference/glossary.md#std-term-recall degradation for scalar quantized embeddings produced by these models is minimal even at lower dimensions like 384.
-
A terminal and code editor to run your Node.js project.
-
npm and Node.js installed.
Procedure
- Update your
package.jsonfile.
Configure your project to use [ES modules](https://nodejs.org/api/esm.html#modules-ecmascript-modules by adding “type”: “module” to your package.json file and then saving it.
javascript
{
"type": "module",
// other fields...
}
- Install the required libraries.
Run the following command to install the MongoDB Node.js Driver and the dotenv package. This operation might take a few minutes to complete.
python
npm install mongodb dotenv
You must install Node.js v6.11 or later driver.
If necessary, you must also install libraries from your embedding model provider. In this tutorial, you use the Voyage AI REST API to generate embeddings. Therefore, you don't need to install any additional libraries for Voyage AI.
- Initialize your Node.js project.
In a terminal window, run the following commands to create a new directory named my-quantization-project and initialize your project:
shell
mkdir my-quantization-project
cd my-quantization-project
npm init -y
- Set the environment variables in your terminal.
To access the embedding model provider for generating and converting embeddings, set the environment variable for the embedding model provider's API key, if necessary.
For using embeddings from Voyage AI, set up the VOYAGE_API_KEY environment variable. To learn how to get your API key, see [Manage Voyage AI Model API Keys.](https://www.mongodb.com/docs/voyageai/management/api-keys.md#std-label-voyage-api-keys
text
export VOYAGE_API_KEY="<VOYAGEAI-API-KEY>"
If you don't set the environment variable, replace the <VOYAGE-API-KEY> in the sample code with the API key before running the code.
To access your cluster, set the MONGODB_URI environment variable.
text
export MONGODB_URI="<CONNECTION-STRING>"
Your connection string should be in the following format:
text
mongodb+srv://<db_username>:<db_password>@<clusterName>.<hostname>.mongodb.net
If you don't set the environment variable, replace the <CONNECTION-STRING> in the sample code with your connection string before running the code.
- Generate the vector embeddings for your data.
Create a file named get-embeddings.js to generate float32, int8, and int1 vector embeddings by using Voyage AI's embed API (Application Programming Interface).
shell
touch get-embeddings.js
Copy and paste the following code in the get-embeddings.js file.
This code does the following:
-
Generates
float32,int8, andint1embeddings for the given data by using Voyage AI'svoyage-3-largeembedding model. -
Stores the
float32,int8, andint1embeddings in fields namedfloat,int8, andubinaryrespectively. -
Creates a file named
embeddings.jsonand saves the embeddings in the file.
```javascript import { writeFile } from "fs/promises"; // For saving JSON files
// Retrieve API key from environment or use placeholder value
const apiKey = process.env.VOYAGE_API_KEY || "
if (!apiKey || apiKey === "
// Define the Voyage AI REST API endpoint const apiEndpoint = "https://ai.mongodb.com/v1/embeddings";
/*
* Fetch embeddings using Voyage AI REST API for a specific data type (output_dtype)
/
async function fetchEmbeddings(data, model, outputDtype, dimension) {
const response = await fetch(apiEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: Bearer ${apiKey},
},
body: JSON.stringify({
input: data,
model,
input_type: "document",
output_dtype: outputDtype,
output_dimension: dimension,
}),
});
// Check for non-success status codes
if (!response.ok) {
const errorResponse = await response.text();
throw new Error(`API request failed with status ${response.status}: ${errorResponse}`);
}
const responseData = await response.json();
// Ensure the response contains valid data
if (!responseData.data || !Array.isArray(responseData.data)) {
throw new Error(`Invalid API response for dtype "${outputDtype}": 'data' array is missing.`);
}
// Extract embeddings from the response
const embeddings = responseData.data.map((item) => item.embedding);
// Validate embeddings
if (!Array.isArray(embeddings) || embeddings.length !== data.length) {
throw new Error(`Invalid embeddings received for dtype "${outputDtype}".`);
}
return embeddings; // Return embeddings for the requested dtype
}
/* * Generate embeddings for predefined texts and save them to a JSON file / async function generateEmbeddings() { const data = [ "The Great Wall of China is visible from space.", "The Eiffel Tower was completed in Paris in 1889.", "Mount Everest is the highest peak on Earth at 8,848m.", "Shakespeare wrote 37 plays and 154 sonnets during his lifetime.", "The Mona Lisa was painted by Leonardo da Vinci.", ];
const model = "voyage-3-large";
const dimension = 1024; // Output embedding dimension
try {
// Fetch embeddings for different output types
const floatEmbeddings = await fetchEmbeddings(data, model, "float", dimension);
const int8Embeddings = await fetchEmbeddings(data, model, "int8", dimension); // Use "int8" dtype
const ubinaryEmbeddings = await fetchEmbeddings(data, model, "ubinary", dimension); // Use "ubinary" dtype
// Map embeddings to their corresponding texts
const embeddingsData = data.map((text, index) => ({
text,
embeddings: {
float: floatEmbeddings[index], // Store float embeddings
int8: int8Embeddings[index], // Store int8 embeddings
ubinary: ubinaryEmbeddings[index], // Store ubinary embeddings
},
}));
// Save embeddings to a JSON file
const fileName = "embeddings.json";
await writeFile(fileName, JSON.stringify(embeddingsData, null, 2));
console.log(`Embeddings saved to ${fileName}`);
} catch (error) {
console.error("Error during embedding generation:", error.message);
throw error; // Optionally rethrow to halt execution if desired
}
}
// Main process (async function main() { try { await generateEmbeddings(); // Execute embedding generation } catch (error) { console.error("Error in main process:", error.message); } })();
```
Replace the <VOYAGE_API_KEY> placeholder if you didn't set your API Key for Voyage AI as an environment variable and then save the file.
Run the code to generate embeddings.
shell
node get-embeddings.js
Output:
shell
Embeddings saved to embeddings.json
Verify the generated embeddings in the generated embeddings.json file.
- Convert the vector embeddings to
binDatavectors.
Create a file named convert-embeddings.js to convert the float32, int8, and int1 vector embeddings from Voyage AI to BSON (Binary Javascript Object Notation) binData vectors by using the MongoDB Node.js driver.
shell
touch convert-embeddings.js
Copy and paste the following code in the convert-embeddings.js file.
This code does the following:
-
Generates BSON (Binary Javascript Object Notation)
binDatavectors for thefloat32,int8, andint1embeddings. -
Appends the
float32,int8, andubinaryBSON (Binary Javascript Object Notation)binDatavectors to theembeddings.jsonfile.
```javascript import fs from "fs/promises"; import { BSON } from "mongodb"; const { Binary } = BSON;
async function main() { try { // Read the contents of the original 'embeddings.json' file const fileContent = await fs.readFile("embeddings.json", "utf8"); const embeddingsData = JSON.parse(fileContent); // Parse JSON into a JavaScript object
// Validate the structure of the original input data
if (!Array.isArray(embeddingsData)) {
throw new Error("'embeddings.json' must contain an array of objects.");
}
// Convert embeddings to BSON-compatible format
const convertEmbeddingsData = embeddingsData.map(({ text, embeddings }) => {
// Field validation to ensure all required embeddings are present
if (
!embeddings ||
!Array.isArray(embeddings.float) ||
!Array.isArray(embeddings.int8) ||
!Array.isArray(embeddings.ubinary)
) {
throw new Error(`Embeddings are missing or invalid for text: "${text}"`);
}
// Convert embeddings to BSON-compatible binary format
const bsonFloat32 = Binary.fromFloat32Array(new Float32Array(embeddings.float));
const bsonInt8 = Binary.fromInt8Array(new Int8Array(embeddings.int8));
const bsonPackedBits = Binary.fromPackedBits(new Uint8Array(embeddings.ubinary));
// Return the updated object structure
return {
text,
embeddings: { // Original embeddings
float: embeddings.float,
int8: embeddings.int8,
ubinary: embeddings.ubinary,
},
bsonEmbeddings: { // BSON embeddings
float32: bsonFloat32,
int8: bsonInt8,
packedBits: bsonPackedBits,
},
};
});
// Serialize the updated data to BSON-compatible JSON using EJSON
const ejsonSerializedData = BSON.EJSON.stringify(convertEmbeddingsData, null, 2, { relaxed: false });
// Write the updated BSON-converted data back to the same 'embeddings.json' file
await fs.writeFile("embeddings.json", ejsonSerializedData);
console.log("Embeddings with BSON vectors have been saved to embeddings.json");
} catch (error) {
// Print detailed error information
console.error("Error processing embeddings:", error);
}
}
// Execute the conversion process main();
```
Run the program to generate the BSON (Binary Javascript Object Notation) binData vectors.
shell
node convert-embeddings.js
Output:
shell
Embeddings with BSON vectors have been saved to embeddings.json
Verify the generated BSON (Binary Javascript Object Notation) embeddings in the embeddings.json file.
- Connect to the cluster and upload the data to a collection.
Create a file named upload-data.js to connect to your cluster and create a collection in a database for the data in the embeddings.json file.
shell
touch upload-data.js
Copy and paste the following code in the upload-data.js file.
This code does the following:
-
Connects to your cluster and creates a namespace with the database and collection name that you specify.
-
Uploads the data including the embeddings in the
embeddings.jsonfile to the specified namespace.
```javascript import fs from 'fs/promises'; import { MongoClient, BSON } from 'mongodb'; const { Binary } = BSON;
async function main() {
const MONGODB_URI = process.env.MONGODB_URI || "
let client;
try {
client = new MongoClient(MONGODB_URI);
await client.connect();
console.log("Connected to MongoDB");
const db = client.db(DB_NAME);
const collection = db.collection(COLLECTION_NAME);
// Read and parse the contents of 'embeddings.json' file using EJSON
const fileContent = await fs.readFile('embeddings.json', 'utf8');
const embeddingsData = BSON.EJSON.parse(fileContent);
// Map embeddings data to recreate BSON binary representations with the correct subtype
const documents = embeddingsData.map(({ text, bsonEmbeddings }) => {
return {
text,
bsonEmbeddings: {
float32: bsonEmbeddings.float32,
int8: bsonEmbeddings.int8,
int1: bsonEmbeddings.packedBits
}
};
});
const result = await collection.insertMany(documents);
console.log(`Inserted ${result.insertedCount} documents into MongoDB`);
} catch (error) {
console.error('Error storing embeddings in MongoDB:', error);
} finally {
if (client) {
await client.close();
}
}
}
// Run the store function main();
```
Replace the following settings and save the file.
<CONNECTION-STRING> |
Connection string to connect to the cluster where you want to create the database and collection. Replace this value only if you didn't set the MONGODB_URI environment variable. |
|---|---|
<DB-NAME> |
Name of the database where you want to create the collection. |
<COLLECTION-NAME> |
Name of the collection where you want to store the generated embeddings. |
Run the following command to upload the data.
shell
node upload-data.js
Verify that the documents exist in the collection on your cluster.
- Create the MongoDB Vector Search index on the collection.
Create a file named create-index.js to define a MongoDB Vector Search index on the collection.
shell
touch create-index.js
Copy and paste the following code to create the index in the create-index.js file.
The code does the following:
-
Connects to the cluster and creates an index with the specified name for the specified namespace.
-
Indexes the
bsonEmbeddings.float32andbsonEmbeddings.int8fields asvectortype that uses thedotProductsimilarity function, and thebsonEmbeddings.int1field also asvectortype that uses theeuclideanfunction.
```javascript import { MongoClient, BSON } from "mongodb"; import { setTimeout } from "timers/promises";
// Connect to your MongoDB cluster
const uri = process.env.MONGODB_URI || "
const client = new MongoClient(uri);
async function main() {
try {
const DB_NAME = "
// define your MongoDB Vector Search index
const index = {
name: "<INDEX-NAME>",
type: "vectorSearch",
definition: {
fields: [
{
type: "vector",
numDimensions: 1024,
path: "bsonEmbeddings.float32",
similarity: "dotProduct",
},
{
type: "vector",
numDimensions: 1024,
path: "bsonEmbeddings.int8",
similarity: "dotProduct",
},
{
type: "vector",
numDimensions: 1024,
path: "bsonEmbeddings.int1",
similarity: "euclidean",
},
],
},
};
// Run the helper method
const result = await collection.createSearchIndex(index);
console.log(`New search index named ${result} is building.`);
// Wait for the index to be ready to query
console.log("Polling to check if the index is ready. This may take up to a minute.");
let isQueryable = false;
// Use filtered search for index readiness
while (!isQueryable) {
const [indexData] = await collection.listSearchIndexes(index.name).toArray();
if (indexData) {
isQueryable = indexData.queryable;
if (!isQueryable) {
await setTimeout(5000); // Wait for 5 seconds before checking again
}
} else {
// Handle the case where the index might not be found
console.log(`Index ${index.name} not found.`);
await setTimeout(5000); // Wait for 5 seconds before checking again
}
}
console.log(`${result} is ready for querying.`);
} catch (error) {
console.error("Error:", error);
} finally {
await client.close();
}
}
main().catch((err) => { console.error("Unhandled error:", err); });
```
Replace the following settings and save the file.
<CONNECTION-STRING> |
Connection string to connect to the cluster where you want to create the index. Replace this value only if you didn't set the MONGODB_URI environment variable. |
|---|---|
<DB-NAME> |
Name of the database where you want to create the collection. |
<COLLECTION-NAME> |
Name of the collection where you want to store the generated embeddings. |
<INDEX-NAME> |
Name of the index for the collection. |
Create the index.
shell
node create-index.js
- Generate the embeddings for the query text.
Create a file named get-query-embedding.js.
shell
touch get-query-embeddings.js
Copy and paste the code in the get-query-embedding.js file.
The sample code does the following:
-
Generates
float32,int8, andint1embeddings for the query text by using Voyage AI. -
Converts the generated embeddings to BSON (Binary Javascript Object Notation)
binDatavectors by using PyMongo. -
Saves the generated embeddings to a file named
query-embeddings.json.
```javascript import { BSON } from "mongodb"; import { writeFile } from "fs/promises"; import dotenv from "dotenv";
// Load environment variables dotenv.config();
const { Binary, EJSON } = BSON; // Import BSON utilities
// Set your API key from environment or fallback to hardcoded value (not recommended for production)
const apiKey = process.env.VOYAGE_API_KEY || "
if (!apiKey || apiKey === "
// Define the Voyage AI REST API endpoint const apiEndpoint = "https://ai.mongodb.com/v1/embeddings";
/*
* Fetch embeddings using Voyage AI REST API
/
async function fetchEmbeddings(data, model, inputType, outputDtype, outputDimension) {
try {
const response = await fetch(apiEndpoint, {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: Bearer ${apiKey},
},
body: JSON.stringify({
input: data,
model,
input_type: inputType,
output_dtype: outputDtype,
output_dimension: outputDimension,
}),
});
// Check for non-success status codes
if (!response.ok) {
const errorResponse = await response.text();
throw new Error(`API request failed with status ${response.status}: ${errorResponse}`);
}
const responseData = await response.json();
// Ensure the response contains valid data
if (!responseData.data || !Array.isArray(responseData.data)) {
console.error("Full API Response:", responseData);
throw new Error("Embeddings are not present or not returned in array format.");
}
return responseData.data.map((item) => item.embedding); // Extract embeddings
} catch (error) {
console.error(`Error fetching embeddings for output_dtype "${outputDtype}":`, error);
throw error;
}
}
/* * Create BSON Binary objects using VECTOR_TYPE for all embedding types / function convertEmbeddingsToBSON(data, float, int8, ubinary) { return data.map((text, index) => ({ text, bsonEmbeddings: { float32: Binary.fromFloat32Array(new Float32Array(float[index])), int8: Binary.fromInt8Array(new Int8Array(int8[index])), int1: Binary.fromPackedBits(new Uint8Array(ubinary[index])), }, })); }
/* * Serialize BSON embeddings and save to JSON file / async function saveBSONEmbeddingsToFile(bsonEmbeddingsData, outputFileName) { try { // Serialize BSON data to JSON format using EJSON const ejsonSerializedData = EJSON.stringify(bsonEmbeddingsData, null, 2, { relaxed: true, // Store binary as raw binary data without base64 encoding });
// Write serialized data to a file
await writeFile(outputFileName, ejsonSerializedData);
console.log(`Embeddings with BSON vectors have been saved to ${outputFileName}`);
} catch (error) {
console.error(`Error saving BSON embeddings to file "${outputFileName}":`, error);
throw error;
}
}
/* * Process query text, fetch embeddings, convert to BSON, and write to JSON / async function main(queryText) { try { if (!queryText || typeof queryText !== "string" || queryText.trim() === "") { throw new Error("Invalid query text. It must be a non-empty string."); }
const data = [queryText];
const model = "voyage-3-large";
const inputType = "query";
const dimension = 1024;
// Fetch embeddings for different data types
const floatEmbeddings = await fetchEmbeddings(data, model, inputType, "float", dimension);
const int8Embeddings = await fetchEmbeddings(data, model, inputType, "int8", dimension);
const packedBitsEmbeddings = await fetchEmbeddings(data, model, inputType, "ubinary", dimension);
// Convert embeddings into BSON-compatible format
const bsonEmbeddingsData = convertEmbeddingsToBSON(
data,
floatEmbeddings,
int8Embeddings,
packedBitsEmbeddings
);
// Save BSON embeddings to JSON file
const outputFileName = "query-embeddings.json";
await saveBSONEmbeddingsToFile(bsonEmbeddingsData, outputFileName);
} catch (error) {
console.error("Error processing query text:", error);
}
}
// Main function invocation (async () => { const queryText = QUERY-TEXT; await main(queryText); })();
```
Replace the following settings and save the file.
<VOYAGE-API-KEY> |
Your API Key for Voyage AI. Only replace this value if you didn't set the environment variable. |
|---|---|
<QUERY-TEXT> |
Your query text. For this tutorial, use science fact. |
Run the code to generate the embeddings for the query text.
shell
node get-query-embeddings.js
Output:
shell
Embeddings with BSON vectors have been saved to query-embeddings.json
-
Run a MongoDB Vector Search query.
Create a file named
run-query.js.shell touch run-query.jsCopy and paste the following sample [
$vectorSearch](https://www.mongodb.com/docs/vector-search/query/aggregation-stages/vector-search-stage.md#mongodb-pipeline-pipe.-vectorSearch query in therun-query.jsfile.The sample query does the following:
-
Connects to your cluster and runs the [
$vectorSearch](https://www.mongodb.com/docs/vector-search/query/aggregation-stages/vector-search-stage.md#mongodb-pipeline-pipe.-vectorSearch query against thebsonEmbeddings.float32,bsonEmbeddings.int8, andbsonEmbeddings.int1fields in the specified collection by using the embeddings in thequery-embeddings.jsonfile. -
Prints the results from Float32, Int8, and Packed Binary (Int1) embeddings to the console.
```javascript import { MongoClient } from "mongodb"; import fs from "fs/promises"; import { BSON } from "bson"; // Use the BSON package for EJSON parsing import dotenv from "dotenv";
dotenv.config();
// MongoDB connection details const mongoUri = process.env.MONGODB_URI || "
"; const dbName = " "; const collectionName = " "; const VECTOR_INDEX_NAME = " "; const NUM_CANDIDATES = ; const LIMIT = ; const dataField = " "; // Fields in the collection containing BSON-compatible query vectors const FIELDS = [ { path: "float32", subtype: 9 }, { path: "int8", subtype: 9 }, { path: "int1", subtype: 9 }, ];
async function main() { const client = new MongoClient(mongoUri);
try { await client.connect(); console.log("Connected to MongoDB");
const db = client.db(dbName); const collection = db.collection(collectionName); // Read the query embeddings from the JSON file const fileContent = await fs.readFile("query-embeddings.json", "utf8"); const embeddingsData = BSON.EJSON.parse(fileContent, { relaxed: true }); if (!Array.isArray(embeddingsData) || embeddingsData.length === 0) { throw new Error("No embeddings found in the JSON file"); } const results = {}; // Perform vector search for each embedding type for (const field of FIELDS) { const { path } = field; const bsonBinary = embeddingsData[0]?.bsonEmbeddings?.[path]; if (!bsonBinary) { console.warn(`Embedding for path "${path}" not found. Skipping.`); continue; } const pipeline = [ { $vectorSearch: { index: VECTOR_INDEX_NAME, path: `bsonEmbeddings.${path}`, queryVector: bsonBinary, // Direct raw binary numCandidates: NUM_CANDIDATES, limit: LIMIT, }, }, { $project: { _id: 0, [dataField]: 1, score: { $meta: "vectorSearchScore" }, }, }, ]; console.log(`Running vector search using "${path}" embedding...`); results[path] = await collection.aggregate(pipeline).toArray(); } return results;} catch (error) { console.error("Error during vector search:", error); } finally { await client.close(); console.log("MongoDB connection closed"); } }
// Parse and display search results for each embedding type (async () => { const results = await main();
if (results) { console.log("Results from Float32 embeddings:"); (results.float32 || []).forEach((result, index) => { console.log(
Result ${index + 1}:, result); });console.log("Results from Int8 embeddings:"); (results.int8 || []).forEach((result, index) => { console.log(`Result ${index + 1}:`, result); }); console.log("Results from Int1 (PackedBits) embeddings:"); (results.int1 || []).forEach((result, index) => { console.log(`Result ${index + 1}:`, result); });} })();
```
Replace the following settings and save the
run-query.jsfile.<CONNECTION-STRING>Connection string to connect to the Atlas cluster where you want to run the query. Replace this value only if you didn't set the MONGODB_URIenvironment variable.<DB-NAME>Name of the database which contains the collection. <COLLECTION-NAME>Name of the collection that you want to query. <INDEX-NAME>Name of the index for the collection. <NUMBER-OF-CAANDIDATES-TO-CONSIDER>Number of nearest neighbors to consider during the search. For this example, specify 5.<NUMBER-OF-DOCUMENTS-TO-RETURN>Number of results to return. For this example, specify 2.<TEXT-FIELD-NAME>Name of the field that contains the text data. For this example, specify text.Run the following command to execute the query.
shell node run-query.jsOutput:
shell 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 } -
To quantize your BSON (Binary Javascript Object Notation) binData vectors, you must have the following:
- A cluster running MongoDB version 6.0.11, 7.0.2, or later.
Ensure that your IP address (Internet Protocol address) is included in your Atlas project's [access list.](https://www.mongodb.com/docs/atlas/security/ip-access-list.md#std-label-access-list
- Access to an embedding model that supports byte vector output.
The outputs from the following embedding models can be used to generate BSON (Binary Javascript Object Notation) binData vectors with a supported MongoDB driver:
| Embedding Model Provider | Embedding Model |
|---|---|
| Voyage AI | voyage-3-large |
| Cohere | embed-english-v3.0 |
| Nomic | nomic-embed-text-v1.5 |
| Jina | jina-embeddings-v2-base-en |
| Mixedbread | mxbai-embed-large-v1 |
Scalar quantization preserves recall for these models because these models are all trained to be quantization aware. Therefore, [recall](https://www.mongodb.com/docs/manual/reference/glossary.md#std-term-recall degradation for scalar quantized embeddings produced by these models is minimal even at lower dimensions like 384.
-
A terminal and code editor to run your Node.js project.
-
[npm and Node.js](https:
(本文超出站点单文档体积上限,已截断)
