Skip to main content
Version: v2.0 RC

Vector search

Vector search is a technique for retrieving contextual and semantically related items based on the similarity of their vector representations. It operates on numerical vectors, which represent data such as text, images, or audio. These vectors, known as vector embeddings, are typically generated using embedding models such as Word2Vec, GloVe, BERT, and GPT for text data, ResNet for image data, or Wav2Vec for audio data.

Vector search is widely used in various applications, especially to power generative AI workflows, such as conversational agents and chatbots. It is also used for building recommendation systems for personalized content and product suggestions, and to enable semantic search for context-aware document retrieval.

Vector indexes

Every vector search application requires a method to calculate the similarity between two vectors. Similarity metrics such as Cosine similarity and Euclidean distance help calculate the distance between vectors and are essential for finding the nearest neighbors of a query from the same embedding model.

FerretDB supports the following vector index kinds:

  • Hierarchical Navigable Small World (HNSW): HNSW is a graph-based index that uses a hierarchical structure to store vectors, suitable for high-speed vector search in memory.
  • Inverted File (IVF): IVF is an inverted file index that partitions the vector space (data sets) into clusters (inverted lists) and performs approximate nearest neighbor search within selected clusters.

Creating an index

Vector index can be created using the usual createIndexes command with the following syntax:

db.runCommand({
createIndexes: "<collectionName>",
indexes: [
{
name: "<indexName>",
key: {
"<path>": "cosmosSearch",
},
cosmosSearchOptions: {
kind: "<kind>",
similarity: "<similarity>",
dimensions: "<dimensions>",

// HNSW only
m: "<m>",
efConstruction: "<efConstruction>",

// IVF only
numLists: "<numLists>",
},
},
],
});

A vector index definition can take the following parameters, depending on the kind of index:

FieldTypeDescriptionIndex kind
<path>stringThe path to the field containing the vector embeddings. The field must be mapped to "cosmosSearch" to enable creation of a vector index.All
cosmosSearchOptionsdocumentIt specifies the configuration parameters (kind, similarity, dimensions, etc.) for the vector index to suit your specific use caseAll
kindstringThe kind of index to create. Possible values: vector-hnsw, vector-ivf.All
similaritystringThe similarity metric to use for nearest neighbor search. Option could be COS for cosine similarity, L2 for Euclidean distance, or IP for inner product.All
dimensionsintegerThe number of dimensions in the vector. Note that all vectors in the collection must have the same dimensionality. Must range from 2-16000All
mintegerThe maximum number of connections per layer. Typically range from 2 to 100 (default: 16).HNSW
efConstructionintegerThe number of neighbors or dynamic candidate list to search during graph construction. Typically 4 to 1000 (default: 64). Must be at least 2 * m.HNSW
numListsintegerThe number of lists to store in the index. Ranges from 1 to 32768 (default: 100).IVF

Index creation example

In the following sections, we will demonstrate how to create and use vector indexes by inserting the following documents with vector embeddings into a collection:

db.runCommand({
insert: "books",
documents: [
{
_id: "pride_prejudice_1813",
title: "Pride and Prejudice",
author: "Jane Austen",
summary:
"The novel follows the story of Elizabeth Bennet, a spirited young woman navigating love, " +
"societal expectations, and family drama in 19th-century England.",
vector: [
0.014391838572919369, -0.07001544535160065, 0.03249300271272659, 0.017455201596021652, -0.012363946065306664,
0.04970458894968033, 0.05334962531924248, -0.04171367362141609, -0.042840130627155304, 0.038735587149858475,
-0.036975011229515076, 0.02225673384964466,
],
},
{
_id: "moby_dick_1851",
title: "Moby Dick",
author: "Herman Melville",
summary:
"The narrative follows Ishmael and his voyage aboard the whaling ship Pequod, commanded by Captain Ahab, " +
"who is obsessed with hunting the elusive white whale, Moby Dick.",
vector: [
-0.0016038859030231833, 0.08863562345504761, 0.006037247832864523, 0.044850509613752365, -0.019985735416412354,
-0.017665650695562363, 0.07435955852270126, 0.0025448515079915524, -0.08427142351865768, 0.07445722818374634,
-0.02302693948149681, -0.0778273269534111,
],
},
{
_id: "frankenstein_1818",
title: "Frankenstein",
author: "Mary Shelley",
summary:
"Victor Frankenstein, driven by an unquenchable thirst for knowledge, creates a living being, " +
"only to face tragic consequences as his creation turns monstrous.",
vector: [
-0.010190412402153015, 0.049356549978256226, -0.012309172190725803, 0.10420369356870651, 0.010599562898278236,
0.057357728481292725, 0.02385704033076763, 0.04186723381280899, 0.003379989881068468, 0.02957085147500038,
-0.08477196842432022, -0.0017921233084052801,
],
},
],
});

The vector field represents the vector embeddings generated for the summary field using the SentenceTransformer("all-MiniLM-L6-v2") model. You can use any embedding model to generate the vectors.

To create an HNSW index, set the kind field to vector-hnsw when creating the vector index.

db.runCommand({
createIndexes: "books",
indexes: [
{
name: "vector_hnsw_index",
key: {
vector: "cosmosSearch",
},
cosmosSearchOptions: {
kind: "vector-hnsw",
similarity: "COS",
dimensions: 12,
m: 16,
efConstruction: 64,
},
},
],
});

Once an index is created, you can perform vector searches using the $search stage in the aggregation pipeline:

db.runCommand({
aggregate: "collectionName",
pipeline: [
{
$search: {
cosmosSearch: {
vector: "<vector>",
path: "<path>",
k: "<k>",

// HNSW only
efSearch: "<efSearch>",
},
},
},
],
cursor: {},
});

A typical vector search query includes the query vector, the path to the field containing the vector, and the number of neighbors to return, as described below:

FieldTypeDescriptionApplicable Index
cosmosSearchdocumentAn operator that specifies query parameters (vector, path, k, efSearch, etc.) for the vector search.All
vectorarrayThe vector to search for.All
pathstringThe path to the field containing the vector.All
kintegerThe number of neighbors (results) to return.All
efSearchintegerThe number of neighbors or dynamic candidate list to search (default: 40). Must range from 1 to 1000HSNW

Vector search example

Using the same embedding model used for generating the vectors, a query vector is generated for An exciting tale of adventure and exploration at sea. Next, a vector search is performed on the vector field in the books collection to find the two nearest neighbors of the query vector.

db.runCommand({
aggregate: "books",
pipeline: [
{
$search: {
cosmosSearch: {
vector: [
0.02232860028743744, 0.06849973648786545, 0.030828291550278664, 0.0903232991695404, -0.028270352631807327,
-0.036311957985162735, 0.02430308423936367, -0.051550041884183884, -0.06737732142210007,
0.011019553989171982, -0.013402754440903664, -0.004793450236320496,
],
path: "vector",
k: 2,
efSearch: 40,
},
},
},
],
cursor: {},
});

The query returns the two nearest neighbors of the query vector.

[
{
"_id": "moby_dick_1851",
"title": "Moby Dick",
"author": "Herman Melville",
"summary": "The narrative follows Ishmael and his voyage aboard the whaling ship Pequod, commanded by Captain Ahab, who is obsessed with hunting the elusive white whale, Moby Dick.",
"vector": [
-0.0016038859030231833, 0.08863562345504761, 0.006037247832864523, 0.044850509613752365, -0.019985735416412354,
-0.017665650695562363, 0.07435955852270126, 0.0025448515079915524, -0.08427142351865768, 0.07445722818374634,
-0.02302693948149681, -0.0778273269534111
]
},
{
"_id": "frankenstein_1818",
"title": "Frankenstein",
"author": "Mary Shelley",
"summary": "Victor Frankenstein, driven by an unquenchable thirst for knowledge, creates a living being, only to face tragic consequences as his creation turns monstrous.",
"vector": [
-0.010190412402153015, 0.049356549978256226, -0.012309172190725803, 0.10420369356870651, 0.010599562898278236,
0.057357728481292725, 0.02385704033076763, 0.04186723381280899, 0.003379989881068468, 0.02957085147500038,
-0.08477196842432022, -0.0017921233084052801
]
}
]