Skip to main content
Version: User Guides (BYOC)

Hybrid Search
Public Preview

Zilliz Cloud introduced multi-vector support and a hybrid search framework, which means users can bring in several vector fields into a single collection. These vectors in different columns represent diverse facets of data, originating from different embedding models or undergoing distinct processing methods. The results of hybrid searches are integrated using reranking strategies, such as Reciprocal Rank Fusion (RRF) and Weighted Scoring. To learn more about reranking strategies, refer to Reranking.

This feature is particularly useful in comprehensive search scenarios, such as identifying the most similar person in a vector library based on various attributes like pictures, voice, fingerprints, etc.

In this tutorial, you will learn how to:

  1. Create multiple AnnSearchRequest instances for similarity searches on different vector fields;

  2. Configure a reranking strategy to combine search results from multiple AnnSearchRequests;

  3. Use the hybrid_search() method to perform a hybrid search.

📘Notes

The code snippets on this page use the PyMilvus ORM module to interact with Zilliz Cloud. Code snippets with the new MilvusClient SDK will be available soon.

Preparations​

Before starting a hybrid search, ensure you have a collection with multiple vector fields. Currently, Zilliz Cloud introduces a default of four vector fields per collection.

Below is an example of creating a collection named test_collection with two vector fields, filmVector and posterVector, and inserting random entities into it.

from pymilvus import connections, Collection, FieldSchema, CollectionSchema, DataType
import random

CLUSTER_ENDPOINT="YOUR_CLUSTER_ENDPOINT" # Set your cluster endpoint
TOKEN="YOUR_CLUSTER_TOKEN" # Set your token

# Connect to cluster
connections.connect(
uri=CLUSTER_ENDPOINT,
token=API_KEY
)

# Create schema
fields = [
FieldSchema(name="film_id", dtype=DataType.INT64, is_primary=True),
# Vector field for film vectors
FieldSchema(name="filmVector", dtype=DataType.FLOAT_VECTOR, dim=5),
# Vector field for poster vectors
FieldSchema(name="posterVector", dtype=DataType.FLOAT_VECTOR, dim=5)]

schema = CollectionSchema(fields=fields,enable_dynamic_field=False)

# Create collection
collection = Collection(name="test_collection", schema=schema)

# Create index for each vector field
index_params = {
"metric_type": "L2",
"index_type": "AUTOINDEX"
}

collection.create_index("filmVector", index_params)
collection.create_index("posterVector", index_params)

# Generate random entities to insert
entities = []

for _ in range(1000):
# generate random values for each field in the schema
film_id = random.randint(1, 1000)
film_vector = [ random.random() for _ in range(5) ]
poster_vector = [ random.random() for _ in range(5) ]

# creat a dictionary for each entity
entity = {
"film_id": film_id,
"filmVector": film_vector,
"posterVector": poster_vector
}

# add the entity to the list
entities.append(entity)

collection.insert(entities)

Step 1: Create Multiple AnnSearchRequest Instances​

A hybrid search uses the hybrid_search() API to perform multiple ANN search requests in a single call. Each AnnSearchRequest represents a single search request on a specific vector field.

The following example creates two AnnSearchRequest instances to perform individual similarity searches on two vector fields.

from pymilvus import AnnSearchRequest

# Create ANN search request 1 for filmVector
query_filmVector = [[0.8896863042430693, 0.370613100114602, 0.23779315077113428, 0.38227915951132996, 0.5997064603128835]]

search_param_1 = {
"data": query_filmVector, # Query vector
"anns_field": "filmVector", # Vector field name
"param": {
"metric_type": "L2", # This parameter value must be identical to the one used in the collection schema
"params": {"nprobe": 10}
},
"limit": 2 # Number of search results to return in this AnnSearchRequest
}
request_1 = AnnSearchRequest(**search_param_1)

# Create ANN search request 2 for posterVector
query_posterVector = [[0.02550758562349764, 0.006085637357292062, 0.5325251250159071, 0.7676432650114147, 0.5521074424751443]]
search_param_2 = {
"data": query_posterVector, # Query vector
"anns_field": "posterVector", # Vector field name
"param": {
"metric_type": "L2", # This parameter value must be identical to the one used in the collection schema
"params": {"nprobe": 10}
},
"limit": 2 # Number of search results to return in this AnnSearchRequest
}
request_2 = AnnSearchRequest(**search_param_2)

# Store these two requests as a list in `reqs`
reqs = [request_1, request_2]

Parameters:

  • AnnSearchRequest (object)

    A class representing an ANN search request. Each hybrid search can contain 1 to 1,024 ANNSearchRequest objects at a time.

  • data (list)

    The query vector to search in a singular AnnSearchRequest. Currently, this parameter accepts a list containing only a single query vector, for example, [[0.5791814851218929, 0.5792985702614121, 0.8480776460143558, 0.16098005945243, 0.2842979317256803]]. In the future, this parameter will be expanded to accept multiple query vectors.

  • anns_field (string)

    The name of the vector field to use in a singular AnnSearchRequest.

  • param (dict)

    A dictionary of search parameters for a singular AnnSearchRequest. These search parameters are identical to those for a single-vector search. For more information, refer to Search parameters.

  • limit (int)

    The maximum number of search results to include in a single ANNSearchRequest.

    This parameter only affects the number of search results to return within an individual ANNSearchRequest, and it does not decide the final results to return for a hybrid_search call. In a hybrid search, the final results are determined by combining and reranking the results from multiple ANNSearchRequest instances.

Step 2: Configure a Reranking Strategy​

After creating AnnSearchRequest instances, configure a reranking strategy to combine and rerank the results. Currently, there are two options: WeightedRanker and RRFRanker.

  • Use weighted scoring

    The WeightedRanker is used to assign importance to the results from each vector field search with specified weights. If you prioritize some vector fields over others, WeightedRanker(value1, value2, ..., valueN) can reflect this in the combined search results.

    from pymilvus import WeightedRanker
    # Use WeightedRanker to combine results with specified weights
    # Assign weights of 0.8 to text search and 0.2 to image search
    rerank = WeightedRanker(0.8, 0.2)

    When using WeightedRanker, note that:

    • Each weight value ranges from 0 (least important) to 1 (most important), influencing the final aggregated score.

    • The total number of weight values provided in WeightedRanker should equal the number of AnnSearchRequest instances you have created.

  • Use Reciprocal Rank Fusion (RFF)

    # Alternatively, use RRFRanker for reciprocal rank fusion reranking
    rerank = RRFRanker()

With the AnnSearchRequest instances and reranking strategy set, use the hybrid_search() method to perform the hybrid search.

# Before conducting hybrid search, load the collection into memory.
collection.load()

res = collection.hybrid_search(
reqs, # List of AnnSearchRequests created in step 1
rerank, # Reranking strategy specified in step 2
limit=2 # Number of final search results to return
)

print(res)

Parameters:

  • reqs (list)

    A list of search requests, where each request is an ANNSearchRequest object. Each request can correspond to a different vector field and a different set of search parameters.

  • rerank (object)

    The reranking strategy to use for hybrid search. Possible values:

    • WeightedRanker(value1, value2, ..., valueN)

    • RRFRanker()

  • limit (int)

    The maximum number of final results to return in the hybrid search.

The output is similar to the following:

["['id: 844, distance: 0.006047376897186041, entity: {}', 'id: 876, distance: 0.006422005593776703, entity: {}']"]

Limits​

  • Typically, each collection has a default allowance of up to 4 vector fields.

  • Partially indexed or loaded vector fields in a collection will result in an error.

  • Currently, each AnnSearchRequest in a hybrid search can carry one query vector.

FAQ​

  1. In which scenarios is hybrid search recommended?

    Hybrid search is ideal for complex situations demanding high accuracy, especially when an entity can be represented by multiple, diverse vectors. This applies to cases where the same data, such as a sentence, is processed through different embedding models or when multimodal information (like images, fingerprints, and voiceprints of an individual) is converted into various vector formats. By assigning weights to these vectors, their combined influence can significantly enrich recall and improve the effectiveness of search results.

  2. How does a weighted ranker normalize distances between different vector fields?

    A weighted ranker normalizes the distances between vector fields using assigned weights to each field. It calculates the importance of each vector field according to its weight, prioritizing those with higher weights. It's advised to use the same metric type across ANN search requests to ensure consistency. This method ensures that vectors deemed more significant have a greater influence on the overall ranking.

  3. Is it possible to use alternative rankers like Cohere Ranker or BGE Ranker?

    Currently, only the provided rankers are supported. Plans to include additional rankers are underway for future updates.

  4. Is it possible to conduct multiple hybrid search operations at the same time?

    Yes, simultaneous execution of multiple hybrid search operations is supported.

  5. Can I use the same vector field in multiple AnnSearchRequest objects to perform hybrid searches?

    Technically, it is possible to use the same vector field in multiple AnnSearchRequest objects for hybrid searches. It is not necessary to have multiple vector fields for a hybrid search.