The Korvus SDK is specifically designed to provide powerful, flexible vector search. Pipeline
s are required to perform search. See Pipelines for more information about using Pipeline
s.
This section will assume we have previously ran the following code:
content_copy
const pipeline = korvus.newPipeline("test_pipeline", {
abstract: {
semantic_search: {
model: "Alibaba-NLP/gte-base-en-v1.5",
},
full_text_search: { configuration: "english" },
},
body: {
splitter: { model: "recursive_character" },
semantic_search: {
model: "mixedbread-ai/mxbai-embed-large-v1",
},
},
});
const collection = korvus.newCollection("test_collection");
await collection.add_pipeline(pipeline);
content_copy
pipeline = Pipeline(
"test_pipeline",
{
"abstract": {
"semantic_search": {
"model": "Alibaba-NLP/gte-base-en-v1.5",
},
"full_text_search": {"configuration": "english"},
},
"body": {
"splitter": {"model": "recursive_character"},
"semantic_search": {
"model": "mixedbread-ai/mxbai-embed-large-v1",
},
},
},
)
collection = Collection("test_collection")
await collection.add_pipeline(pipeline);
content_copy
let mut pipeline = Pipeline::new(
"test_pipeline",
Some(
serde_json::json!(
{
"abstract": {
"semantic_search": {
"model": "Alibaba-NLP/gte-base-en-v1.5",
},
"full_text_search": {"configuration": "english"},
},
"body": {
"splitter": {"model": "recursive_character"},
"semantic_search": {
"model": "mixedbread-ai/mxbai-embed-large-v1",
},
},
}
)
.into(),
),
)?;
let mut collection = Collection::new("test_collection", None)?;
collection.add_pipeline(&mut pipeline).await?;
content_copy
PipelineC *pipeline = korvus_pipelinec_new("test_pipeline", "{\
\"abstract\": {\
\"semantic_search\": {\
\"model\": \"Alibaba-NLP/gte-base-en-v1.5\"\
},\
\"full_text_search\": {\"configuration\": \"english\"}\
},\
\"body\": {\
\"splitter\": {\"model\": \"recursive_character\"},\
\"semantic_search\": {\
\"model\": \"mixedbread-ai/mxbai-embed-large-v1\"\
}\
}\
}");
CollectionC * collection = korvus_collectionc_new("test_collection", NULL);
korvus_collectionc_add_pipeline(collection, pipeline);
This creates a Pipeline
that is capable of full text search and semantic search on the abstract
and semantic search on the body
of documents.
content_copy
const results = await collection.vector_search(
{
query: {
fields: {
body: {
query: "What is the best database?",
parameters: {
prompt:
"Represent this sentence for searching relevant passages: ",
}
},
},
},
document: {
keys: [
"id",
"abstract"
]
},
limit: 5,
},
pipeline,
);
content_copy
results = await collection.vector_search(
{
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"prompt": "Represent this sentence for searching relevant passages: ",
},
},
},
},
"document": {
"keys": [
"id",
"abstract"
]
},
"limit": 5,
},
pipeline,
)
content_copy
let results = collection
.vector_search(
serde_json::json!({
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"prompt": "Represent this sentence for searching relevant passages: ",
},
},
},
},
"document": {
"keys": [
"id",
"abstract"
]
},
"limit": 5,
})
.into(),
&mut pipeline,
)
.await?;
content_copy
r_size = 0;
char **results = korvus_collectionc_vector_search(collection, "{\
\"query\": {\
\"fields\": {\
\"body\": {\
\"query\": \"What is the best database?\",\
\"parameters\": {\
\"prompt\": \"Represent this sentence for searching relevant passages: \"\
}\
}\
}\
},\
\"document\": {\
\"keys\": [\
\"id\",\
\"abstract\"\
]\
},\
\"limit\": 5\
}",
pipeline, &r_size);
Let's break this down. The vector_search
function takes in a JSON
object and a Pipeline
. The JSON
object currently supports four keys:
query
document
rerank
limit
The query
object specifies the actual query to perform. Each key specified in the Pipeline
can be searched or filtered over according to the specification in the Pipeline
.
The limit
key limits how many chunks should be returned.
The document
object can restrict which fields to return from the document. If left out, the whole document is returned. In this case we are specifying we only want the id
and abstract
returned.
the rerank
object specifies what type of re-ranking to perform. If left out, no re-ranking is done. See the Re-ranking section for more information.
Note that mixedbread-ai/mxbai-embed-large-v1
takes in a prompt when creating embeddings for searching against a corpus which we provide in the parameters
.
Let's see another more complicated example:
content_copy
const query = "What is the best database?";
const results = await collection.vector_search(
{
query: {
fields: {
abstract: {
query: query,
full_text_filter: "database"
},
body: {
query: query,
parameters: {
instruction:
"Represent this sentence for searching relevant passages: ",
}
},
},
},
limit: 5,
},
pipeline,
);
content_copy
query = "What is the best database?"
results = await collection.vector_search(
{
"query": {
"fields": {
"abastract": {
"query": query,
"full_text_filter": "database",
},
"body": {
"query": query,
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
},
"limit": 5,
},
pipeline,
)
content_copy
let query = "What is the best database?";
let results = collection
.vector_search(
serde_json::json!({
"query": {
"fields": {
"abastract": {
"query": query,
"full_text_filter": "database",
},
"body": {
"query": query,
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
},
"limit": 5,
})
.into(),
&mut pipeline,
)
.await?;
content_copy
r_size = 0;
char **results = korvus_collectionc_vector_search(collection, "{\
\"query\": {\
\"fields\": {\
\"abastract\": {\
\"query\": \"What is the best database?\",\
\"full_text_filter\": \"database\"\
},\
\"body\": {\
\"query\": \"What is the best database?\",\
\"parameters\": {\
\"instruction\": \"Represent this sentence for searching relevant passages: \"\
}\
}\
}\
},\
\"limit\": 5,\
}", pipeline, &r_size);
The query
in this example is slightly more intricate. We are doing vector search over both the abstract
and body
keys of our documents. This means our search may return chunks from both the abstract
and body
of our documents. We are also filtering out all abstract
chunks that do not contain the text "database"
we can do this because we enabled full_text_search
on the abstract
key in the Pipeline
schema. Also note that the model used for embedding the body
takes parameters, but not the model used for embedding the abstract
.
We provide powerful and flexible arbitrarly nested filtering based off of MongoDB Comparison Operators. We support each operator mentioned in Mongo's docs except the $nin
.
Vector search with $eq filtering
content_copy
const results = await collection.vector_search(
{
query: {
fields: {
body: {
query: "What is the best database?",
parameters: {
instruction:
"Represent this sentence for searching relevant passages: ",
}
},
},
filter: {
user_id: {
$eq: 1
}
}
},
limit: 5,
},
pipeline,
);
content_copy
results = await collection.vector_search(
{
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
"filter": {"user_id": {"$eq": 1}},
},
"limit": 5,
},
pipeline,
)
content_copy
let results = collection
.vector_search(
serde_json::json!({
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
"filter": {"user_id": {"$eq": 1}},
},
"limit": 5,
})
.into(),
&mut pipeline,
)
.await?;
content_copy
r_size = 0;
char **results = korvus_collectionc_vector_search(collection, "{\
\"query\": {\
\"fields\": {\
\"body\": {\
\"query\": \"What is the best database?\",\
\"parameters\": {\
\"instruction\": \"Represent this sentence for searching relevant passages: \"\
}\
}\
},\
\"filter\": {\"user_id\": {\"$eq\": 1}}\
},\
\"limit\": 5\
}", pipeline, &r_size);
The above query would filter out all chunks from documents that do not contain a key user_id
equal to 1
.
Vector search with $gte filtering
content_copy
const results = await collection.vector_search(
{
query: {
fields: {
body: {
query: "What is the best database?",
parameters: {
instruction:
"Represent this sentence for searching relevant passages: ",
}
},
},
filter: {
user_id: {
$gte: 1
}
}
},
limit: 5,
},
pipeline,
);
content_copy
results = await collection.vector_search(
{
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
"filter": {"user_id": {"$gte": 1}},
},
"limit": 5,
},
pipeline,
)
content_copy
let results = collection
.vector_search(
serde_json::json!({
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
"filter": {"user_id": {"$gte": 1}},
},
"limit": 5,
})
.into(),
&mut pipeline,
)
.await?;
content_copy
r_size = 0;
char **results = korvus_collectionc_vector_search(collection, "{\
\"query\": {\
\"fields\": {\
\"body\": {\
\"query\": \"What is the best database?\",\
\"parameters\": {\
\"instruction\": \"Represent this sentence for searching relevant passages: \"\
}\
}\
},\
\"filter\": {\"user_id\": {\"$eq\": 1}}\
},\
\"limit\": 5\
}", pipeline, &r_size);
The above query would filter out all documents that do not contain a key user_id
with a value greater than or equal to 1
.
Vector search with $or and $and filtering
content_copy
const results = await collection.vector_search(
{
query: {
fields: {
body: {
query: "What is the best database?",
parameters: {
instruction:
"Represent this sentence for searching relevant passages: ",
}
},
},
filter: {
$or: [
{
$and: [
{
$eq: {
user_id: 1
}
},
{
$lt: {
user_score: 100
}
}
]
},
{
special: {
$ne: true
}
}
]
}
},
limit: 5,
},
pipeline,
);
content_copy
results = await collection.vector_search(
{
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
"filter": {
"$or": [
{"$and": [{"$eq": {"user_id": 1}}, {"$lt": {"user_score": 100}}]},
{"special": {"$ne": True}},
],
},
},
"limit": 5,
},
pipeline,
)
content_copy
let results = collection
.vector_search(
serde_json::json!({
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"instruction": "Represent this sentence for searching relevant passages: ",
},
},
},
"filter": {
"$or": [
{"$and": [{"$eq": {"user_id": 1}}, {"$lt": {"user_score": 100}}]},
{"special": {"$ne": True}},
],
},
},
"limit": 5,
})
.into(),
&mut pipeline,
)
.await?;
content_copy
r_size = 0;
char **results = korvus_collectionc_vector_search(collection, "{\
\"query\": {\
\"fields\": {\
\"body\": {\
\"query\": \"What is the best database?\",\
\"parameters\": {\
\"instruction\": \"Represent this sentence for searching relevant passages: \"\
}\
}\
},\
\"filter\": {\
\"$or\": [\
{\"$and\": [{\"$eq\": {\"user_id\": 1}}, {\"$lt\": {\"user_score\": 100}}]},\
{\"special\": {\"$ne\": True}}\
]\
}\
},\
\"limit\": 5\
}", pipeline, &r_size);
The above query would filter out all documents that do not have a key special
with a value True
or (have a key user_id
equal to 1 and a key user_score
less than 100).
Vector search results can be reranked in the same query they are retrieved in. To enable this, provide the rerank
key.
content_copy
const results = await collection.vector_search(
{
query: {
fields: {
body: {
query: "What is the best database?", parameters: {
prompt:
"Represent this sentence for searching relevant passages: ",
}
},
},
},
rerank: {
model: "mixedbread-ai/mxbai-rerank-base-v1",
query: "What is the best database?",
num_documents_to_rerank: 100,
},
limit: 5,
},
pipeline,
);
content_copy
results = await collection.vector_search(
{
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"prompt": "Represent this sentence for searching relevant passages: ",
},
},
},
},
"rerank": {
"model": "mixedbread-ai/mxbai-rerank-base-v1",
"query": "What is the best database",
"num_documents_to_rerank": 100,
},
"limit": 5,
},
pipeline,
)
content_copy
let results = collection
.vector_search(
serde_json::json!({
"query": {
"fields": {
"body": {
"query": "What is the best database?",
"parameters": {
"prompt": "Represent this sentence for searching relevant passages: ",
},
},
},
},
"rerank": {
"model": "mixedbread-ai/mxbai-rerank-base-v1",
"query": "What is the best database",
"num_documents_to_rerank": 100,
},
"limit": 5,
})
.into(),
&mut pipeline,
)
.await?;
content_copy
r_size = 0;
char **results = korvus_collectionc_vector_search(collection, "{\
\"query\": {\
\"fields\": {\
\"body\": {\
\"query\": \"What is the best database?\",\
\"parameters\": {\
\"prompt\": \"Represent this sentence for searching relevant passages: \"\
}\
}\
}\
},\
\"rerank\": {\
\"model\": \"mixedbread-ai/mxbai-rerank-base-v1\",\
\"query\": \"What is the best database\",\
\"num_documents_to_rerank\": 100\
},\
\"limit\": 5\
}",
pipeline, &r_size);
This query will first get the top 100 documents from the initial vector search and then rerank them using the mixedbread-ai/mxbai-rerank-base-v1
cross-encoder.
You can specify the number of documents to rerank with the num_documents_to_rerank
parameter. The query returns the top limit
results after re-ranking.