Skip to content

Commit 4ed1cbc

Browse files
Implement scan_factor and max_candidates for query (#617)
## Problem There are new parameters available on `query` for indexes with dedicated read nodes: - `scan_factor` - `max_candidates` These were pulled into the `2025-10` API release and need to be added to the clients. ## Solution - Regenerate core from OpenAPI and protos off of `2025-10` to pull in `scan_factor` and `max_candidates`. - Add `max_candidates` and `scan_factor` to the following resources and thread things through the API: - `VectorResourceAsyncio.query()` && `VectorResourceAsyncio.query_namespaces()` - `VectorResource.query()` && `VectorResource.query_namepspaces()` - `Index.query()` && `Index.query_namespaces()` - `_IndexAsyncio.query()` && `_IndexAsyncio.query_namespaces()` - `IndexRequestFactory.query_request()` - `GRPCIndex.query()` && `GRPCIndex.query_namespaces() ## Type of Change - [ ] Bug fix (non-breaking change which fixes an issue) - [X] New feature (non-breaking change which adds functionality) - [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected) - [ ] This change requires a documentation update - [ ] Infrastructure change (CI configs, etc) - [ ] Non-code change (docs, etc) - [ ] None of the above: (explain here) ## Test Plan CI - unit and integration tests <!-- CURSOR_SUMMARY --> --- > [!NOTE] > **Medium Risk** > Touches core query request construction and propagates new parameters through both REST and gRPC layers; risk is mainly incorrect serialization/forwarding or validation edge cases, mitigated by added unit coverage. > > **Overview** > Adds two new query tuning parameters, `scan_factor` and `max_candidates`, to the `QueryRequest` schema and surfaces them through all query entrypoints (`Index.query`, `query_namespaces`, sync/async vector resources, and `GRPCIndex.query`). > > Regenerates the 2025-10 OpenAPI and protobuf bindings to include the new fields (with validations and typing) and updates the request factory to include them only when provided. Unit tests are expanded to assert correct forwarding/omission behavior for REST, asyncio, and gRPC query calls, and the generated API repo SHA is bumped. > > <sup>Written by [Cursor Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit 0c40a43. This will update automatically on new commits. Configure [here](https://cursor.com/dashboard?tab=bugbot).</sup> <!-- /CURSOR_SUMMARY -->
1 parent 8a2d2e5 commit 4ed1cbc

File tree

14 files changed

+405
-45
lines changed

14 files changed

+405
-45
lines changed

codegen/apis

Submodule apis updated from be7f2b2 to 103cc9d

pinecone/core/grpc/protos/db_data_2025_10_pb2.py

Lines changed: 42 additions & 42 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pinecone/core/grpc/protos/db_data_2025_10_pb2.pyi

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,8 @@ class QueryRequest(_message.Message):
200200
VECTOR_FIELD_NUMBER: _ClassVar[int]
201201
SPARSE_VECTOR_FIELD_NUMBER: _ClassVar[int]
202202
ID_FIELD_NUMBER: _ClassVar[int]
203+
SCAN_FACTOR_FIELD_NUMBER: _ClassVar[int]
204+
MAX_CANDIDATES_FIELD_NUMBER: _ClassVar[int]
203205
namespace: str
204206
top_k: int
205207
filter: _struct_pb2.Struct
@@ -209,7 +211,9 @@ class QueryRequest(_message.Message):
209211
vector: _containers.RepeatedScalarFieldContainer[float]
210212
sparse_vector: SparseValues
211213
id: str
212-
def __init__(self, namespace: _Optional[str] = ..., top_k: _Optional[int] = ..., filter: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., include_values: _Optional[bool] = ..., include_metadata: _Optional[bool] = ..., queries: _Optional[_Iterable[_Union[QueryVector, _Mapping]]] = ..., vector: _Optional[_Iterable[float]] = ..., sparse_vector: _Optional[_Union[SparseValues, _Mapping]] = ..., id: _Optional[str] = ...) -> None: ...
214+
scan_factor: float
215+
max_candidates: int
216+
def __init__(self, namespace: _Optional[str] = ..., top_k: _Optional[int] = ..., filter: _Optional[_Union[_struct_pb2.Struct, _Mapping]] = ..., include_values: _Optional[bool] = ..., include_metadata: _Optional[bool] = ..., queries: _Optional[_Iterable[_Union[QueryVector, _Mapping]]] = ..., vector: _Optional[_Iterable[float]] = ..., sparse_vector: _Optional[_Union[SparseValues, _Mapping]] = ..., id: _Optional[str] = ..., scan_factor: _Optional[float] = ..., max_candidates: _Optional[int] = ...) -> None: ...
213217

214218
class SingleQueryResults(_message.Message):
215219
__slots__ = ()

pinecone/core/openapi/db_data/model/query_request.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,8 @@ class QueryRequest(ModelNormal):
8080
("queries",): {},
8181
("vector",): {},
8282
("id",): {"max_length": 512},
83+
("scan_factor",): {"inclusive_maximum": 4.0, "inclusive_minimum": 0.5},
84+
("max_candidates",): {"inclusive_maximum": 100000, "inclusive_minimum": 1},
8385
}
8486

8587
@cached_class_property
@@ -114,6 +116,8 @@ def openapi_types(cls):
114116
"vector": ([float],), # noqa: E501
115117
"sparse_vector": (SparseValues,), # noqa: E501
116118
"id": (str,), # noqa: E501
119+
"scan_factor": (float,), # noqa: E501
120+
"max_candidates": (int,), # noqa: E501
117121
}
118122

119123
@cached_class_property
@@ -130,6 +134,8 @@ def discriminator(cls):
130134
"vector": "vector", # noqa: E501
131135
"sparse_vector": "sparseVector", # noqa: E501
132136
"id": "id", # noqa: E501
137+
"scan_factor": "scanFactor", # noqa: E501
138+
"max_candidates": "maxCandidates", # noqa: E501
133139
}
134140

135141
read_only_vars: Set[str] = set([])
@@ -194,6 +200,8 @@ def _from_openapi_data(cls: Type[T], top_k, *args, **kwargs) -> T: # noqa: E501
194200
vector ([float]): The query vector. This should be the same length as the dimension of the index being queried. Each `query` request can contain only one of the parameters `id` or `vector`. [optional] # noqa: E501
195201
sparse_vector (SparseValues): [optional] # noqa: E501
196202
id (str): The unique ID of the vector to be used as a query vector. Each request can contain either the `vector` or `id` parameter. [optional] # noqa: E501
203+
scan_factor (float): An optimization parameter for IVF dense indexes in dedicated read node indexes. It adjusts how much of the index is scanned to find vector candidates. Range: 0.5 – 4 (default). Keep the default (4.0) for the best search results. If query latency is too high, try lowering this value incrementally (minimum 0.5) to speed up the search at the cost of slightly lower accuracy. This parameter is only supported for dedicated (DRN) dense indexes. [optional] # noqa: E501
204+
max_candidates (int): An optimization parameter that controls the maximum number of candidate dense vectors to rerank. Reranking computes exact distances to improve recall but increases query latency. Range: top_k – 100000. Keep the default for a balance of recall and latency. Increase this value if recall is too low, or decrease it to reduce latency at the cost of accuracy. This parameter is only supported for dedicated (DRN) dense indexes. [optional] # noqa: E501
197205
"""
198206

199207
_enforce_allowed_values = kwargs.pop("_enforce_allowed_values", False)
@@ -295,6 +303,8 @@ def __init__(self, top_k, *args, **kwargs) -> None: # noqa: E501
295303
vector ([float]): The query vector. This should be the same length as the dimension of the index being queried. Each `query` request can contain only one of the parameters `id` or `vector`. [optional] # noqa: E501
296304
sparse_vector (SparseValues): [optional] # noqa: E501
297305
id (str): The unique ID of the vector to be used as a query vector. Each request can contain either the `vector` or `id` parameter. [optional] # noqa: E501
306+
scan_factor (float): An optimization parameter for IVF dense indexes in dedicated read node indexes. It adjusts how much of the index is scanned to find vector candidates. Range: 0.5 – 4 (default). Keep the default (4.0) for the best search results. If query latency is too high, try lowering this value incrementally (minimum 0.5) to speed up the search at the cost of slightly lower accuracy. This parameter is only supported for dedicated (DRN) dense indexes. [optional] # noqa: E501
307+
max_candidates (int): An optimization parameter that controls the maximum number of candidate dense vectors to rerank. Reranking computes exact distances to improve recall but increases query latency. Range: top_k – 100000. Keep the default for a balance of recall and latency. Increase this value if recall is too low, or decrease it to reduce latency at the cost of accuracy. This parameter is only supported for dedicated (DRN) dense indexes. [optional] # noqa: E501
298308
"""
299309

300310
_enforce_allowed_values = kwargs.pop("_enforce_allowed_values", True)

pinecone/db_data/index.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -945,6 +945,8 @@ def query(
945945
include_values: bool | None = None,
946946
include_metadata: bool | None = None,
947947
sparse_vector: SparseValues | SparseVectorTypedDict | None = None,
948+
scan_factor: float | None = None,
949+
max_candidates: int | None = None,
948950
**kwargs,
949951
) -> QueryResponse | ApplyResult:
950952
"""Query a namespace using a query vector.
@@ -970,6 +972,14 @@ def query(
970972
sparse_vector: Sparse values of the query vector. Expected to be either a SparseValues object or a dict
971973
of the form: ``{'indices': list[int], 'values': list[float]}``, where the lists each have
972974
the same length. [optional]
975+
scan_factor: An optimization parameter for the IVF dense indexes in dedicated
976+
read node indexes. It adjusts how much of the index is scanned to find
977+
vector candidates. Range: 0.5 - 4 (default). This parameter is only
978+
supported for dedicated (DRN) dense indexes. [optional]
979+
max_candidates: An optimization parameter that controls the maximum number of
980+
candidate dense vectors to rerank. Reranking computes exact distances to
981+
improve recall but increases query latency. Range: top_k - 100000. This
982+
parameter is only supported for dedicated (DRN) dense indexes. [optional]
973983
**kwargs: Additional keyword arguments for the API call.
974984
975985
Returns:
@@ -1033,6 +1043,8 @@ def query(
10331043
include_values=include_values,
10341044
include_metadata=include_metadata,
10351045
sparse_vector=sparse_vector,
1046+
scan_factor=scan_factor,
1047+
max_candidates=max_candidates,
10361048
**kwargs,
10371049
)
10381050

@@ -1054,6 +1066,8 @@ def _query(
10541066
include_values: bool | None = None,
10551067
include_metadata: bool | None = None,
10561068
sparse_vector: SparseValues | SparseVectorTypedDict | None = None,
1069+
scan_factor: float | None = None,
1070+
max_candidates: int | None = None,
10571071
**kwargs,
10581072
) -> OpenAPIQueryResponse:
10591073
if len(args) > 0:
@@ -1073,6 +1087,8 @@ def _query(
10731087
include_values=include_values,
10741088
include_metadata=include_metadata,
10751089
sparse_vector=sparse_vector,
1090+
scan_factor=scan_factor,
1091+
max_candidates=max_candidates,
10761092
**kwargs,
10771093
)
10781094
from typing import cast
@@ -1092,6 +1108,8 @@ def query_namespaces(
10921108
include_values: bool | None = None,
10931109
include_metadata: bool | None = None,
10941110
sparse_vector: SparseValues | SparseVectorTypedDict | None = None,
1111+
scan_factor: float | None = None,
1112+
max_candidates: int | None = None,
10951113
**kwargs,
10961114
) -> QueryNamespacesResults:
10971115
"""Query multiple namespaces in parallel and combine the results.
@@ -1116,6 +1134,14 @@ def query_namespaces(
11161134
include_values: Boolean field indicating whether vector values should be included with results. Defaults to None. [optional]
11171135
include_metadata: Boolean field indicating whether vector metadata should be included with results. Defaults to None. [optional]
11181136
sparse_vector: If you are working with a dotproduct index, you can pass a sparse vector as part of your hybrid search. Defaults to None. [optional]
1137+
scan_factor: An optimization parameter for the IVF dense indexes in dedicated
1138+
read node indexes. It adjusts how much of the index is scanned to find
1139+
vector candidates. Range: 0.5 - 4 (default). This parameter is only
1140+
supported for dedicated (DRN) dense indexes. [optional]
1141+
max_candidates: An optimization parameter that controls the maximum number of
1142+
candidate dense vectors to rerank. Reranking computes exact distances to
1143+
improve recall but increases query latency. Range: top_k - 100000. This
1144+
parameter is only supported for dedicated (DRN) dense indexes. [optional]
11191145
**kwargs: Additional keyword arguments for the API call.
11201146
11211147
Returns:
@@ -1171,6 +1197,8 @@ def query_namespaces(
11711197
include_values=include_values,
11721198
include_metadata=include_metadata,
11731199
sparse_vector=sparse_vector,
1200+
scan_factor=scan_factor,
1201+
max_candidates=max_candidates,
11741202
async_threadpool_executor=True,
11751203
_preload_content=False,
11761204
**kwargs,

pinecone/db_data/index_asyncio.py

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,8 @@ async def query(
728728
include_values: bool | None = None,
729729
include_metadata: bool | None = None,
730730
sparse_vector: (SparseValues | SparseVectorTypedDict) | None = None,
731+
scan_factor: float | None = None,
732+
max_candidates: int | None = None,
731733
**kwargs,
732734
) -> QueryResponse:
733735
"""
@@ -832,6 +834,14 @@ async def main():
832834
sparse_vector: (Union[SparseValues, dict[str, Union[list[float], list[int]]]]): sparse values of the query vector.
833835
Expected to be either a SparseValues object or a dict of the form:
834836
{'indices': list[int], 'values': list[float]}, where the lists each have the same length.
837+
scan_factor: An optimization parameter for the IVF dense indexes in dedicated
838+
read node indexes. It adjusts how much of the index is scanned to find
839+
vector candidates. Range: 0.5 - 4 (default). This parameter is only
840+
supported for dedicated (DRN) dense indexes. [optional]
841+
max_candidates: An optimization parameter that controls the maximum number of
842+
candidate dense vectors to rerank. Reranking computes exact distances to
843+
improve recall but increases query latency. Range: top_k - 100000. This
844+
parameter is only supported for dedicated (DRN) dense indexes. [optional]
835845
836846
Returns: QueryResponse object which contains the list of the closest vectors as ScoredVector objects,
837847
and namespace name.
@@ -846,6 +856,8 @@ async def main():
846856
include_values=include_values,
847857
include_metadata=include_metadata,
848858
sparse_vector=sparse_vector,
859+
scan_factor=scan_factor,
860+
max_candidates=max_candidates,
849861
**kwargs,
850862
)
851863
return parse_query_response(response)
@@ -861,6 +873,8 @@ async def _query(
861873
include_values: bool | None = None,
862874
include_metadata: bool | None = None,
863875
sparse_vector: (SparseValues | SparseVectorTypedDict) | None = None,
876+
scan_factor: float | None = None,
877+
max_candidates: int | None = None,
864878
**kwargs,
865879
) -> OpenAPIQueryResponse:
866880
if len(args) > 0:
@@ -877,6 +891,8 @@ async def _query(
877891
include_values=include_values,
878892
include_metadata=include_metadata,
879893
sparse_vector=sparse_vector,
894+
scan_factor=scan_factor,
895+
max_candidates=max_candidates,
880896
**kwargs,
881897
)
882898
from typing import cast
@@ -897,6 +913,8 @@ async def query_namespaces(
897913
include_metadata: bool | None = None,
898914
vector: list[float] | None = None,
899915
sparse_vector: (SparseValues | SparseVectorTypedDict) | None = None,
916+
scan_factor: float | None = None,
917+
max_candidates: int | None = None,
900918
**kwargs,
901919
) -> QueryNamespacesResults:
902920
"""The query_namespaces() method is used to make a query to multiple namespaces in parallel and combine the results into one result set.
@@ -909,6 +927,14 @@ async def query_namespaces(
909927
include_values (Optional[bool], optional): Boolean field indicating whether vector values should be included with results. Defaults to None.
910928
include_metadata (Optional[bool], optional): Boolean field indicating whether vector metadata should be included with results. Defaults to None.
911929
sparse_vector (Optional[ Union[SparseValues, dict[str, Union[list[float], list[int]]]] ], optional): If you are working with a dotproduct index, you can pass a sparse vector as part of your hybrid search. Defaults to None.
930+
scan_factor: An optimization parameter for the IVF dense indexes in dedicated
931+
read node indexes. It adjusts how much of the index is scanned to find
932+
vector candidates. Range: 0.5 - 4 (default). This parameter is only
933+
supported for dedicated (DRN) dense indexes. [optional]
934+
max_candidates: An optimization parameter that controls the maximum number of
935+
candidate dense vectors to rerank. Reranking computes exact distances to
936+
improve recall but increases query latency. Range: top_k - 100000. This
937+
parameter is only supported for dedicated (DRN) dense indexes. [optional]
912938
913939
Returns:
914940
QueryNamespacesResults: A QueryNamespacesResults object containing the combined results from all namespaces, as well as the combined usage cost in read units.
@@ -965,6 +991,8 @@ async def main():
965991
sparse_vector=sparse_vector,
966992
async_threadpool_executor=True,
967993
_preload_content=False,
994+
scan_factor=scan_factor,
995+
max_candidates=max_candidates,
968996
**kwargs,
969997
)
970998
for ns in target_namespaces

pinecone/db_data/request_factory.py

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,8 @@ def query_request(
5656
include_values: bool | None = None,
5757
include_metadata: bool | None = None,
5858
sparse_vector: SparseValues | SparseVectorTypedDict | None = None,
59+
scan_factor: float | None = None,
60+
max_candidates: int | None = None,
5961
**kwargs,
6062
) -> QueryRequest:
6163
if vector is not None and id is not None:
@@ -73,6 +75,8 @@ def query_request(
7375
("include_values", include_values),
7476
("include_metadata", include_metadata),
7577
("sparse_vector", sparse_vector_normalized),
78+
("scan_factor", scan_factor),
79+
("max_candidates", max_candidates),
7680
]
7781
)
7882

0 commit comments

Comments
 (0)