Zvec Logo

Grouped Search

Grouped search organizes vector search results by scalar field values and returns the most relevant groups, along with the most relevant documents in each group.

For example, grouping product search results by category prevents one category from dominating the results while preserving the most relevant products in each category.


How It Works

When you call group_by_query(), Zvec:

  1. Groups results by the value of group_by_field_name during vector search.
  2. Ranks groups by the most relevant document in each group and returns up to group_count groups.
  3. Keeps up to topk_per_group documents in relevance order within each group.

Documents whose grouping field is null are excluded from the results.


Prerequisites

This guide assumes that you have opened a collection and that:

  • The query field is a vector field with an index that supports grouped search.
  • The grouping field is a non-array scalar field, such as an integer, float, string, or boolean field.


Pass a single vector Query, a grouping field name, the number of groups to return, and the number of documents per group to group_by_query():

Group vector search results by category
import zvec

results = collection.group_by_query(  
    query=zvec.Query(
        field_name="dense_embedding",
        vector=[0.1] * 768,  # Replace with a real embedding in practice
        param=zvec.HnswQueryParam(ef=200),
    ),
    group_by_field_name="category",  
    group_count=3,                    # Return up to 3 categories
    topk_per_group=2,                 # Return up to 2 documents per category
    filter="publish_year >= 2020",
    output_fields=["title", "category", "publish_year"],
)

for group in results:
    print(f"Category: {group.group_by_value}")
    for doc in group.docs:
        print(doc.id, doc.field("title"), doc.score)

If fewer matching groups or documents are available, the actual result counts will be lower than group_count or topk_per_group. An empty collection or a search with no matches returns an empty list.

Using the Vector from an Existing Document

Instead of providing an embedding directly, you can use id to reuse the vector from an existing document in the collection:

Use the vector from an existing document
results = collection.group_by_query(
    query=zvec.Query(
        field_name="dense_embedding",
        id="product_123",
    ),
    group_by_field_name="category",
    group_count=3,
    topk_per_group=2,
)

The document specified by id must exist and contain the vector identified by field_name.


Parameters

ParameterTypeDefaultDescription
queryQueryRequiredA single vector search specification. Provide an embedding through vector, or use id to reuse the vector from an existing document. You can pass index-specific query parameters through param.
group_by_field_namestrRequiredThe name of the non-array scalar field used for grouping. It cannot be empty.
group_countint2The maximum number of groups to return. Must be a positive integer.
topk_per_groupint3The maximum number of documents to return per group. Must be a positive integer.
filterstr | NoneNoneA filter expression applied before the search.
include_vectorboolFalseWhether to include vector fields in the returned documents.
output_fieldslist[str] | NoneNoneScalar fields to return. None returns all scalar fields; an empty list returns no scalar fields.

Results

group_by_query() returns a list[GroupResult]. Each GroupResult contains:

AttributeTypeDescription
group_by_valuestrThe string representation of the grouping field value. This attribute is a string even when the original field is an integer or boolean.
docslist[Doc]The documents in the group, ordered by vector relevance.

Groups are ordered by the relevance of the first document in each group. The direction of distance or similarity scores depends on the metric used by the vector field. For example, higher inner product scores usually indicate greater relevance, while lower L2 and cosine distance scores usually indicate greater relevance.

group_by_value is returned independently of output_fields. You can use it to identify a group even when the grouping field is not included in output_fields.


Limitations and Considerations

  • Grouped search supports only single-vector search. It does not support full-text search or multi-vector search.
  • The grouping field cannot be a vector or array field.
  • Grouped search currently does not support IVF, DiskANN, or Vamana vector indexes.
  • Grouped search cannot be used with vector refinement (refiner).
  • Grouped search is best-effort. Depending on the data distribution and search conditions, the actual number of groups and documents per group may be lower than group_count and topk_per_group, respectively. When there are not enough candidates, Zvec prioritizes group_count.
  • Increasing group_count or topk_per_group requires collecting and sorting more candidates and typically increases query latency.

On this page