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:
- Groups results by the value of
group_by_field_nameduring vector search. - Ranks groups by the most relevant document in each group and returns up to
group_countgroups. - Keeps up to
topk_per_groupdocuments 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.
Performing Grouped Search
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():
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:
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
| Parameter | Type | Default | Description |
|---|---|---|---|
query | Query | Required | A 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_name | str | Required | The name of the non-array scalar field used for grouping. It cannot be empty. |
group_count | int | 2 | The maximum number of groups to return. Must be a positive integer. |
topk_per_group | int | 3 | The maximum number of documents to return per group. Must be a positive integer. |
filter | str | None | None | A filter expression applied before the search. |
include_vector | bool | False | Whether to include vector fields in the returned documents. |
output_fields | list[str] | None | None | Scalar 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:
| Attribute | Type | Description |
|---|---|---|
group_by_value | str | The string representation of the grouping field value. This attribute is a string even when the original field is an integer or boolean. |
docs | list[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_countandtopk_per_group, respectively. When there are not enough candidates, Zvec prioritizesgroup_count. - Increasing
group_countortopk_per_grouprequires collecting and sorting more candidates and typically increases query latency.