GrpcIndex¶
Obtain a GrpcIndex instance via pinecone.Pinecone.index() with
grpc=True, or construct one directly.
from pinecone import Pinecone
pc = Pinecone(api_key="your-api-key")
# Resolve host automatically by index name
idx = pc.index("my-index", grpc=True)
# — or — construct directly with a host URL
from pinecone.grpc import GrpcIndex
idx = GrpcIndex(host="my-index-abc123.svc.pinecone.io", api_key="your-api-key")
GrpcIndex carries the data-plane operations of
Index except for the documents namespace, over gRPC
transport (backed by a Rust extension), and returns
PineconeFuture objects from the *_async()
methods.
Method groups:
Vectors —
upsert(),upsert_from_dataframe(),upsert_records(),query(),query_namespaces(),fetch(),fetch_by_metadata(),update(),delete(),list(),list_paginated()Stats —
describe_index_stats()Integrated Inference —
search(),search_records()Namespaces —
create_namespace(),describe_namespace(),delete_namespace(),list_namespaces(),list_namespaces_paginated()Bulk Import —
start_import(),describe_import(),cancel_import(),list_imports(),list_imports_paginated()Async variants —
upsert_async(),query_async(),query_namespaces_async(),fetch_async(),update_async(),delete_async()
GrpcIndex has no documents namespace — the document interface is HTTP-only.
Use Index or
AsyncIndex for a schema-based index.
- class pinecone.grpc.GrpcIndex(*, host, api_key=None, api_version='2026-07', source_tag=None, secure=True, grpc_scheme=None, timeout=20.0, connect_timeout=1.0, retry_config=None, proxy_url=None, on_throttle=None, limiter_registry=None)[source]¶
Bases:
objectSynchronous gRPC data plane client targeting a specific Pinecone index.
Reach it as
pc.index(name="articles-en", grpc=True), which resolves the host for you, or construct it directly when you already know the host.It offers the same data-plane methods as
Indexand is the one to reach for when throughput on a long ingest matters; on everything elseIndexis the better default, because gRPC has no asyncio twin and needs a compiled extension. Three differences are visible in the code you write: the*_asyncmethods here return aPineconeFuturerather than something youawait;retry_config.retryable_status_codeshas no effect, since this transport retries gRPC status codes rather than HTTP ones; andupsert_records()andsearch()still travel over REST, because the gRPC API has no records operations. See Using the gRPC Client.- Parameters:
host (str) – The index-specific data plane host URL.
api_key (str | None) – Pinecone API key. Falls back to
PINECONE_API_KEYenv var.api_version (str) – API version string. Defaults to the current data plane version.
source_tag (str | None) – Tag appended to the User-Agent string for request attribution.
secure (bool) – Whether the channel is given TLS material — system root certificates for gRPC, certificate verification for the REST calls this client makes alongside it. Defaults to
True. It supplies the default forgrpc_scheme, andgrpc_schemeis what decides whether the wire is actually encrypted.grpc_scheme ("http" | "https" | None) – URL scheme used to dial the data plane. State it when the data plane is reached over something other than public TLS — a plaintext gateway, an egress proxy, a private endpoint, or a local simulator — rather than leaving the SDK to assume one.
None(default) takes the scheme fromsecure:httpswhenTrue,httpwhenFalse. Falls back to thePINECONE_GRPC_SCHEMEenv var before that default applies."https"requiressecure=True, since an https endpoint cannot connect without the TLS materialsecure=Falsewithholds."http"withsecure=Trueis a plaintext channel: the scheme, not the TLS material, decides what goes on the wire. A resolvedhttpscheme against a host outside loopback and the RFC 1918 private ranges warns once per process, because the API key and every payload then cross a public network unencrypted.timeout (float) – Deadline in seconds for a single attempt of a request, not for the call as a whole. Defaults to
20.0. A per-calltimeout=does not replace it — the channel keeps this one too, so the shorter of the two governs.connect_timeout (float) – Connection timeout in seconds. Defaults to
1.0.retry_config (RetryConfig | None) – Retry policy for transient gRPC errors. Accepts the same
RetryConfigREST uses.None(default) uses the gRPC defaults:max_retries=5,backoff_factor=0.1,max_wait=60.0, which differ from REST’s — so aretry_configyou leave unset onPineconedoes not carry over here. Itsretryable_status_codesfield is ignored on this transport: it carries HTTP statuses, and the codes retried here are gRPC ones. See Retries and Resilience.proxy_url (str | None) – HTTP proxy URL. gRPC traffic is tunnelled through it with HTTP CONNECT.
limiter_registry (_AdaptiveLimiterRegistry | None) – SDK-internal. Registry the bulk paths consult to back off under throttling. Wired by
Pinecone.index(); not intended for user configuration.on_throttle (Callable[[str], None] | None)
- Raises:
PineconeValueError – If no API key can be resolved, the host is invalid,
grpc_schemenames a scheme other thanhttporhttps, orgrpc_scheme="https"is combined withsecure=False.
Examples
from pinecone.grpc import GrpcIndex idx = GrpcIndex(host="movie-recs-abc123.svc.pinecone.io", api_key="...")
A data plane fronted by a plaintext gateway or served by a local simulator is dialled over
httpby saying so:idx = GrpcIndex( host="http://127.0.0.1:5085", api_key="...", grpc_scheme="http", )
Note
Four timeout layers apply to every gRPC call, and only the first three bound a single request:
Connect —
connect_timeout.Per attempt —
timeout, or a per-calltimeout=. This is a deadline on one attempt, not on the call. Both apply when a call passes its own, so the shorter of the two is what fires.Retry budget —
retry_config.max_retriesattempts after the first, with backoff between them.Whole job — for bulk methods only,
total_timeout.
Layers 2 and 3 compound only across retryable failures, and this transport retries exactly three gRPC status codes: UNAVAILABLE, RESOURCE_EXHAUSTED, and ABORTED. So the multiplied worst case — every attempt burning nearly its full deadline and then failing with one of those — is what a lower
max_retriesshrinks.An expiring deadline is not one of the three. Layer 2 firing raises
PineconeTimeoutErrorafter a single attempt, somax_retriesis not the knob for a timeout. Raisetimeout=to give the server longer per attempt — raising the index-leveltimeouttoo if it is the lower of the two — or bound a bulk job withtotal_timeout.See also
Index— the REST client, and the better default unless you are ingesting at volume. Using the gRPC Client compares the two, and Retries and Resilience gives the full retry policy for both.- __init__(*, host, api_key=None, api_version='2026-07', source_tag=None, secure=True, grpc_scheme=None, timeout=20.0, connect_timeout=1.0, retry_config=None, proxy_url=None, on_throttle=None, limiter_registry=None)[source]¶
- Parameters:
- Return type:
None
- upsert(*, vectors, namespace='', batch_size=None, max_concurrency=8, show_progress=True, timeout=None, total_timeout=None)[source]¶
Upsert a batch of vectors into a namespace.
If a vector with the same ID already exists in the namespace, it is overwritten.
One request is capped both on the number of vectors it carries and on its encoded size, and with wide vectors or heavy metadata the size cap is usually the one reached first. Pass
batch_sizeto split a long sequence into requests that stay under both.- Parameters:
vectors (Sequence[Vector | tuple[str, Sequence[float]] | tuple[str, Sequence[float], Mapping[str, Any]] | Mapping[str, Any]]) – Sequence of vectors to upsert. Each element can be a
Vectorinstance, a tuple of(id, values)or(id, values, metadata), or a dict withid,values, and optionalsparse_values/metadatakeys.namespace (str) – Target namespace. Defaults to the default (empty-string) namespace.
batch_size (int | None) – If set, splits
vectorsinto batches of this size and submits them in parallel.None(default) sends all vectors in a single request. Must be a positive integer when set.max_concurrency (int) – Number of parallel threads used when
batch_sizeis set. Default8, range[1, 64]. Ignored whenbatch_sizeisNone.show_progress (bool) – If
Trueandtqdmis installed, display a progress bar while submitting batches. Ignored whenbatch_sizeisNone. Defaults toTrue.timeout (float | None) – Per-call timeout in seconds. Applied per batch when batching. None uses the client-level default.
total_timeout (float | None) – Deadline in seconds for the whole batched operation (only meaningful with
batch_size). On expiry no further batches are submitted; batches already in flight are awaited and never cancelled; unsent batches are reported infailed_items.None(default) means no deadline.
- Returns:
UpsertResponsewithupserted_count. Withbatch_sizeset it also carriesfailed_item_count,errors, andfailed_items: a batch that fails does not raise, so checkfailed_item_countand handfailed_itemsstraight back toupsert()to retry only what did not land. Upserts are idempotent by vector ID, so a retry that overlaps is harmless.- Raises:
PineconeTypeError – If a vector element is not a recognized format.
PineconeValueError – If a vector element is malformed, if
batch_sizeis not a positive integer, or ifmax_concurrencyis outside[1, 64].ApiError – If one request exceeds the server’s cap on vectors per request or on encoded request size. Lower
batch_sizeand retry.
- Return type:
Examples
Each element can be a
Vector, a(id, values)tuple, or a dict — the three forms below are interchangeable, and the values are truncated here for length:from pinecone.grpc import GrpcIndex from pinecone.models.vectors.vector import Vector idx = GrpcIndex(host="article-search-abc123.svc.pinecone.io", api_key="...") response = idx.upsert( vectors=[ Vector(id="article-101", values=[0.012, -0.087, 0.153]), ("article-102", [0.045, 0.021, -0.064]), {"id": "article-103", "values": [0.091, -0.032, 0.178]}, ], namespace="articles-en", ) print(response.upserted_count)
For a long sequence, set
batch_sizeand read the failure fields rather than relying on an exception:response = idx.upsert( vectors=all_vectors, namespace="articles-en", batch_size=200, total_timeout=600.0, ) if response.failed_item_count: idx.upsert(vectors=response.failed_items, namespace="articles-en")
See also
upsert_records()— for an index with integrated inference, where you send text and the server embeds it.start_import()— for a one-off load of millions of vectors already sitting in cloud storage. 10.0: gRPC upsert_from_dataframe reports partial failures instead of raising — how to read the partial-failure fields, and what changed for callers who expected a raise.
- query(*, top_k, vector=None, id=None, namespace='', filter=None, include_values=False, include_metadata=False, sparse_vector=None, scan_factor=None, max_candidates=None, timeout=None)[source]¶
Query a namespace for the nearest neighbors of a vector.
Use this on an index you upsert your own vectors into. An index that carries a document schema is read through
search()instead, which embeds the query text server-side.- Parameters:
top_k (int) – Number of results to return, 1-10000.
id (str | None) – ID of a stored vector to use as the query.
namespace (str) – Namespace to query. Defaults to the default namespace.
filter (dict[str, Any] | None) – Metadata filter expression.
include_values (bool) – Whether to include vector values in results.
include_metadata (bool) – Whether to include metadata in results.
sparse_vector (SparseValues | dict[str, Any] | None) – Sparse query vector with indices and values.
scan_factor (float | None) – Recall/latency trade for dedicated read node (DRN) indexes — a multiplier on how much of the index is scanned. Above 1 scans more and favours recall; below 1 scans less and favours latency. Omit to let the server choose.
max_candidates (int | None) – Recall/latency trade for dedicated read node (DRN) indexes — caps how many candidates are reranked before
top_kis taken. Must be at leasttop_k: a smaller value is rejected rather than clamped, since it could not fill the page.timeout (float | None) – Per-call timeout in seconds. None uses the client-level default.
- Returns:
QueryResponsewith matches, namespace, and usage info.- Raises:
PineconeValueError – If top_k is not between 1 and 10000,
idis combined withvectororsparse_vector, none ofvector,id, orsparse_vectoris provided, oridis not a legal vector ID.ApiError – If
scan_factorormax_candidatesis out of range, or the index is not a dense DRN index — both knobs are rejected on on-demand indexes and on sparse indexes.
- Return type:
Examples
response = idx.query( top_k=10, vector=[0.012, -0.087, 0.153, ...], # 1536-dim embedding ) for match in response.matches: print(match.id, match.score)
See also
search()— for an index with integrated inference, where you send query text and the server embeds it.query_namespaces()— to run the same query across several namespaces and merge the results.
- query_namespaces(*, vector=None, namespaces, metric, top_k=None, filter=None, include_values=False, include_metadata=False, sparse_vector=None, scan_factor=None, max_candidates=None, timeout=None)[source]¶
Query multiple namespaces in parallel and return merged top results.
Fans out individual
query()calls across all given namespaces using a thread pool, then merges results via a heap-based aggregator that returns the overall top-k matches ranked by the specified metric.- Parameters:
vector (Sequence[float] | None) – Dense query vector values. Required for dense and hybrid indexes; omit for sparse-only indexes (use sparse_vector instead).
namespaces (Sequence[str]) – Namespaces to query (must be non-empty). Duplicates are removed while preserving order.
metric (str) – The metric the index was created with —
"cosine","euclidean", or"dotproduct". It decides which direction counts as better when the per-namespace results are merged, and"euclidean"is the one where lower wins. Name the wrong one and the merge is not rejected, it is just ordered backwards.top_k (int | None) – Maximum number of results to return. Defaults to 10.
filter (Mapping[str, Any] | None) – Metadata filter expression applied to every namespace.
include_values (bool) – Whether to include vector values in results.
include_metadata (bool) – Whether to include metadata in results.
sparse_vector (SparseValues | Mapping[str, Any] | None) – Sparse query vector with indices and values. Required for sparse-only indexes when vector is omitted.
scan_factor (float | None) – Recall/latency trade for dedicated read node (DRN) indexes — a multiplier on how much of the index is scanned. Above 1 scans more and favours recall; below 1 scans less and favours latency. Applied to every namespace queried.
max_candidates (int | None) – Recall/latency trade for dedicated read node (DRN) indexes — caps how many candidates are reranked before
top_kis taken, per namespace. Must be at leasttop_k.timeout (float | None)
- Returns:
QueryNamespacesResultswith the merged top-k matches, total usage, and per-namespace usage.- Raises:
PineconeValueError – If namespaces is empty, if both vector and sparse_vector are absent/empty, or if metric is not a recognized value.
ApiError – If any individual namespace query fails.
- Return type:
Examples
results = idx.query_namespaces( vector=[0.012, -0.087, 0.153], namespaces=["articles-en", "articles-fr", "articles-de"], metric="cosine", top_k=10, ) for match in results.matches: print(match.id, match.score)
On a sparse-only index, send
sparse_vectorinstead and rank by"dotproduct":results = idx.query_namespaces( sparse_vector={"indices": [412, 8871, 20114], "values": [0.42, 0.19, 0.08]}, namespaces=["articles-en", "articles-fr"], metric="dotproduct", top_k=10, )
See also
query()— one namespace, and the only form that takes anidas the query.
- fetch(*, ids, namespace='', timeout=None)[source]¶
Fetch vectors by their IDs from a namespace.
- Parameters:
- Returns:
FetchResponsewith a map of vector IDs to Vector objects, namespace, and usage info.- Raises:
PineconeValueError – If ids is empty or any ID is not 1-512 ASCII characters without a NUL.
- Return type:
Examples
response = idx.fetch( ids=["article-101", "article-102"], namespace="articles-en", ) for vid, vec in response.vectors.items(): print(vid, len(vec.values))
See also
fetch_by_metadata()— when you know what the vectors look like but not their IDs.
- fetch_by_metadata(*, filter, namespace='', limit=None, pagination_token=None, timeout=None)[source]¶
Fetch vectors matching a metadata filter expression.
- Parameters:
filter (Mapping[str, Any]) – Metadata filter expression (required, at least one condition).
namespace (str) – Namespace to fetch from. Defaults to the default namespace.
limit (int | None) – Maximum number of vectors to return per page, 1-10000. Omit to let the server choose the page size.
pagination_token (str | None) – Token from a previous response to fetch the next page.
timeout (float | None) – Per-call timeout in seconds.
- Returns:
FetchByMetadataResponsewith matched vectors, namespace, usage, and pagination token for the next page (if any).- Raises:
PineconeValueError – If
filteris empty orlimitfalls outside 1-10000.- Return type:
Examples
page = idx.fetch_by_metadata( filter={"topic": {"$eq": "science"}}, namespace="articles-en", limit=50, ) for vid, vec in page.vectors.items(): print(vid, vec.metadata) next_token = page.pagination.next if page.pagination else None
See also
fetch()— when you already know the IDs, and want them all in one response rather than a page at a time. Pagination — followingpagination.next.
- delete(*, ids=None, delete_all=False, filter=None, namespace='', timeout=None)[source]¶
Delete vectors from a namespace by ID, filter, or delete-all flag.
Exactly one of
ids,delete_all, orfiltermust be specified.A by-filter delete selects on metadata alone, so a text-match operator (
$match_phrase,$match_all,$match_any) in the filter is rejected rather than ignored — evaluated there it would match everything and widen the delete to every record the rest of the filter admits. Text matching belongs insearch().A by-filter delete also reads before it writes, so a dedicated index scaled to zero replicas refuses it; add replicas first. Deleting by ID or with
delete_allis unaffected.- Parameters:
delete_all (bool) – If True, delete all vectors in the namespace.
filter (dict[str, Any] | None) – Metadata filter expression selecting vectors to delete.
namespace (str) – Namespace to delete from. Defaults to the default namespace.
timeout (float | None) – Per-call timeout in seconds. None uses the client-level default.
- Returns:
None
- Raises:
PineconeValueError – If zero or more than one deletion mode is specified, any ID is not a legal vector ID, or
filteris empty.ApiError – If a by-filter delete uses a text-match operator, or the index is a dedicated index scaled to zero replicas.
- Return type:
None
Examples
Delete named vectors:
idx.delete(ids=["article-101", "article-102"], namespace="articles-en")
Delete everything a metadata filter selects:
idx.delete(filter={"category": {"$eq": "obsolete"}}, namespace="articles-en")
Empty a namespace entirely. There is no undo and no dry run — every vector in it goes:
idx.delete(delete_all=True, namespace="articles-deprecated")
See also
delete_namespace()— removes the namespace itself, not just the vectors in it.
- update(*, id=None, values=None, sparse_values=None, set_metadata=None, namespace='', filter=None, dry_run=False, timeout=None)[source]¶
Update vectors by ID or metadata filter.
A by-filter update selects on metadata alone, so a text-match operator (
$match_phrase,$match_all,$match_any) in the filter is rejected rather than ignored — evaluated there it would match everything and widen the patch to every record the rest of the filter admits. Text matching belongs insearch().A by-filter update also reads before it writes, so a dedicated index scaled to zero replicas refuses it; add replicas first. Updating by ID is unaffected.
- Parameters:
id (str | None) – ID of the vector to update.
sparse_values (SparseValues | dict[str, Any] | None) – New sparse vector.
set_metadata (dict[str, Any] | None) – Metadata fields to set or overwrite.
namespace (str) – Namespace to target. Defaults to the default namespace.
filter (dict[str, Any] | None) – Metadata filter expression selecting vectors to update.
dry_run (bool) – If True, return the count of records that would be affected without applying changes.
timeout (float | None) – Per-call timeout in seconds. None uses the client-level default.
- Returns:
UpdateResponsewith matched_records count (when available).- Raises:
PineconeValueError – If both or neither of id and filter are provided, if
filteris combined withvaluesorsparse_values, iffilteris empty, or ifidis not a legal vector ID.ApiError – If a by-filter update uses a text-match operator, or the index is a dedicated index scaled to zero replicas.
- Return type:
Examples
Replace one vector’s values, leaving its metadata as it was:
idx.update( id="article-101", values=[0.012, -0.087, 0.153], namespace="articles-en", )
Set metadata on every record a filter selects. Fields you do not name in
set_metadataare left alone:response = idx.update( filter={"topic": {"$eq": "science"}}, set_metadata={"reviewed_by": "editorial-team"}, namespace="articles-en", ) print(response.matched_records)
Pass
dry_run=Truefirst to see how many records a filter would touch before touching them:preview = idx.update( filter={"topic": {"$eq": "science"}}, set_metadata={"reviewed_by": "editorial-team"}, namespace="articles-en", dry_run=True, ) print(preview.matched_records)
- list_paginated(*, prefix=None, limit=None, pagination_token=None, namespace='', timeout=None)[source]¶
Fetch a single page of vector IDs from a namespace.
- Parameters:
prefix (str | None) – Return only IDs starting with this prefix.
limit (int | None) – Maximum number of IDs to return in this page, 1-100.
pagination_token (str | None) – Token from a previous response to fetch the next page.
namespace (str) – Namespace to list from. Defaults to the default namespace.
timeout (float | None) – Per-call timeout in seconds. None uses the client-level default.
- Returns:
ListResponsewith vector IDs, pagination info, namespace, and usage.- Raises:
PineconeValueError – If
prefixis not legal orlimitfalls outside 1-100.- Return type:
Examples
page = idx.list_paginated(prefix="article-2024#", namespace="articles-en") for item in page.vectors: print(item.id) next_token = page.pagination.next if page.pagination else None
See also
list()— the same walk with the tokens handled for you. Pagination — when to drive the tokens yourself.
- list(*, prefix=None, limit=None, namespace='', timeout=None)[source]¶
List vector IDs in a namespace, automatically following pagination.
Yields one
ListResponseper page.- Parameters:
prefix (str | None) – Return only IDs starting with this prefix.
limit (int | None) – Maximum number of IDs to return per page.
namespace (str) – Namespace to list from. Defaults to the default namespace.
timeout (float | None) – Per-call timeout in seconds applied to each page request. None uses the client-level default.
- Yields:
ListResponsefor each page of results.- Raises:
PineconeValueError – If
prefixis not legal orlimitfalls outside 1-100.- Return type:
Examples
for page in idx.list(prefix="article-2024#", namespace="articles-en"): for item in page.vectors: print(item.id)
See also
list_paginated()— one page at a time, when you need to persist a token between calls. See Pagination.
- describe_index_stats(*, filter=None, timeout=None)[source]¶
Return statistics for this index.
- Parameters:
filter (dict[str, Any] | None) – Metadata filter expression. Accepted for API compatibility, but a non-empty filter is rejected for every index type, so the call fails instead of returning filtered counts. Leave it unset: the statistics returned always describe the whole index.
timeout (float | None) – Per-call timeout in seconds. None uses the client-level default.
- Returns:
DescribeIndexStatsResponsewith namespace summaries, dimension, total vector count, and fullness metrics.- Raises:
ApiError – If a non-empty
filteris provided, since it is rejected for every index type.- Return type:
Examples
stats = idx.describe_index_stats() print(stats.total_vector_count, stats.dimension) for name, summary in stats.namespaces.items(): print(name, summary.vector_count)
See also
list_namespaces()— per-namespace record counts plussize_bytes, which this does not report.
- upsert_from_dataframe(df, namespace='', batch_size=500, show_progress=True, timeout=None, *, max_concurrency=None, total_timeout=None, on_error=None)[source]¶
Upsert vectors from a pandas DataFrame.
Splits the DataFrame into batches of
batch_sizerows, submits batches in parallel, and aggregates the results into a single response.- Parameters:
df (pd.DataFrame) – A
pandas.DataFramewith at leastidandvaluescolumns.sparse_valuesandmetadatacolumns are included when present and non-None.namespace (str) – Target namespace. Defaults to the default namespace.
batch_size (int) – Number of rows per upsert batch. Defaults to 500.
show_progress (bool) – If
Trueandtqdmis installed, display a progress bar. The bar advances as batches complete. Iftqdmis not installed, silently falls back to no progress bar.max_concurrency (int | None) – Number of batches in flight at once, range
[1, 64].None(default) uses8— flat and identical across every transport and machine, so throughput is reproducible across hosts. The host’s adaptive limit still applies underneath; raise this only when the backend has headroom for a larger committed retry burst.on_error (Literal['raise', 'collect'] | None) – What to do when some batches fail.
"collect"returns anUpsertResponsecarryingfailed_item_count,errorsandfailed_items, so the caller can retry only what failed — the same contract the REST client has had since v9.0.0."raise"re-raises the lowest-indexed batch failure, after all batches have settled, with the partial result attached to the exception’sresponseattribute.None(default) behaves as"collect"and additionally warns once per process when a partial failure occurs, since this method used to raise; pass"collect"explicitly to silence that.total_timeout (float | None) – Deadline in seconds for the whole ingest, as opposed to timeout, which bounds a single attempt of a single batch. On expiry no further batches are submitted; batches already in flight are allowed to settle rather than being abandoned, since dropping them client-side would not stop the server from applying them.
PineconeTimeoutErroris then raised carrying the partialUpsertResponseon itsresponseattribute, whosefailed_itemsare the rows that were never sent.None(default) means the ingest is bounded only by the per-batch deadlines.timeout (float | None) – Deadline in seconds for a single attempt of a single batch — not for the batch, and not for the DataFrame. A batch that keeps failing on a retryable code is retried, so its wall-clock can exceed this several times over; a batch whose attempt runs out of time is not retried and fails after one attempt, so a larger timeout is the fix for a timeout and
max_retriesis not.None(default) uses thetimeoutthe index was constructed with. See the four timeout layers onGrpcIndexand Retries and Resilience.
- Returns:
UpsertResponsewith the total count of vectors upserted across all batches.- Raises:
RuntimeError – If
pandasis not installed. It is not an SDK dependency; install it yourself withpip install pandas.PineconeValueError – If df is not a
pandas.DataFrameor batch_size is not a positive integer.PineconeTimeoutError – If a batch exceeds timeout on
the server, – or if total_timeout expires before every batch is submitted. In the latter case the exception carries the partial
UpsertResponseon itsresponseattribute.
- Return type:
Examples
import pandas as pd from pinecone.grpc import GrpcIndex idx = GrpcIndex( host="article-search-abc123.svc.pinecone.io", api_key="your-api-key", ) df = pd.DataFrame([ {"id": "article-101", "values": [0.012, -0.087, 0.153]}, {"id": "article-102", "values": [0.045, 0.021, -0.064]}, ]) response = idx.upsert_from_dataframe(df) response.upserted_count
df = pd.DataFrame([ { "id": "article-101", "values": [0.012, -0.087, 0.153], "metadata": {"topic": "science", "year": 2024}, }, { "id": "article-102", "values": [0.045, 0.021, -0.064], "metadata": {"topic": "technology", "year": 2024}, }, ]) response = idx.upsert_from_dataframe( df, namespace="articles-en", batch_size=100, )
Give each batch a longer server-side deadline for large or slow ingests, and check what failed rather than waiting for a raise:
response = idx.upsert_from_dataframe( df, batch_size=200, timeout=120.0, on_error="collect", ) if response.failed_item_count: idx.upsert(vectors=response.failed_items, batch_size=200)
See also
upsert()— the same batching without the pandas dependency. How Bulk Ingest Behaves — choosingbatch_size,max_concurrency, andtotal_timeout.Changed in version 10.0.0: Partial failures are aggregated into the response rather than raised, matching
upsert()withbatch_sizeand the REST client. The old raise discarded the partial count, so no caller could tell what had landed. Passon_error="raise"to keep the previous behavior. See 10.0: gRPC upsert_from_dataframe reports partial failures instead of raising.
- upsert_async(*, vectors, namespace='', timeout=None)[source]¶
Send one upsert request without waiting for it.
A narrower
upsert(): it sends exactly one request, so there is nobatch_sizeand none of the batching arguments that go with it. To overlap several requests, issue several of these and collect the futures.- Parameters:
vectors (Sequence[Vector | tuple[str, Sequence[float]] | tuple[str, Sequence[float], Mapping[str, Any]] | Mapping[str, Any]]) – The vectors to upsert, in any of the forms
upsert()accepts.namespace (str) – Target namespace. Defaults to the default (empty-string) namespace.
timeout (float | None) – Per-attempt deadline in seconds for the request itself, unrelated to the deadline you later pass to
PineconeFuture.result().Noneuses the index-level default.
- Returns:
PineconeFutureresolving to anUpsertResponse.- Return type:
Examples
future = idx.upsert_async( vectors=[("article-101", [0.012, -0.087, 0.153])], namespace="articles-en", ) print(future.result().upserted_count)
- query_async(*, top_k, vector=None, id=None, namespace='', filter=None, include_values=False, include_metadata=False, sparse_vector=None, scan_factor=None, max_candidates=None, timeout=None)[source]¶
Send one query without waiting for it, as
query()otherwise would.Takes the same arguments as
query(); only the return type differs. Reach for it to have several queries in flight at once — over different namespaces, or with different filters.- Returns:
PineconeFutureresolving to aQueryResponse.- Parameters:
- Return type:
Examples
future = idx.query_async( vector=[0.012, -0.087, 0.153], top_k=5, namespace="articles-en", ) for match in future.result().matches: print(match.id, match.score)
- fetch_async(*, ids, namespace='', timeout=None)[source]¶
Send one fetch without waiting for it, as
fetch()otherwise would.Takes the same arguments as
fetch(); only the return type differs. Reach for it to fetch from several namespaces at once.- Returns:
PineconeFutureresolving to aFetchResponse.- Parameters:
- Return type:
Examples
future = idx.fetch_async( ids=["article-101", "article-102"], namespace="articles-en", ) for vid, vec in future.result().vectors.items(): print(vid, len(vec.values))
- delete_async(*, ids=None, delete_all=False, filter=None, namespace='', timeout=None)[source]¶
Send one delete without waiting for it, as
delete()otherwise would.Takes the same arguments as
delete(); only the return type differs. Note that the delete is already on its way when this returns: dropping the future does not call it back, andPineconeFuture.cancel()only helps before a worker thread picks it up.- Returns:
PineconeFutureresolving toNoneonce the delete has been accepted. Collect it even though there is no payload — that is where a failure surfaces.- Parameters:
- Return type:
PineconeFuture[None]
Examples
future = idx.delete_async( ids=["article-101", "article-102"], namespace="articles-en", ) future.result()
- update_async(*, id=None, values=None, sparse_values=None, set_metadata=None, filter=None, namespace='', dry_run=False, timeout=None)[source]¶
Send one update without waiting for it, as
update()otherwise would.Takes the same arguments as
update(); only the return type differs.- Returns:
PineconeFutureresolving to anUpdateResponse.- Parameters:
- Return type:
Examples
future = idx.update_async( id="article-101", values=[0.012, -0.087, 0.153], namespace="articles-en", ) future.result()
- query_namespaces_async(*, vector=None, namespaces, metric, top_k=None, filter=None, include_values=False, include_metadata=False, sparse_vector=None, scan_factor=None, max_candidates=None, timeout=None)[source]¶
Start a
query_namespaces()fan-out without waiting for it.Takes the same arguments as
query_namespaces(); only the return type differs. The fan-out across namespaces already happens on its own thread pool, so this is worth it only to overlap the whole fan-out with other work.- Returns:
PineconeFutureresolving to aQueryNamespacesResults.- Parameters:
- Return type:
Examples
future = idx.query_namespaces_async( vector=[0.012, -0.087, 0.153], namespaces=["articles-en", "articles-fr", "articles-de"], metric="cosine", top_k=10, ) for match in future.result(timeout=30.0).matches: print(match.id, match.score)
- upsert_records(*, records, namespace, timeout=None)[source]¶
Upsert records for indexes with integrated inference.
Embeddings are generated server-side from the fields you provide, so each record carries source data (e.g. text) rather than precomputed vector values. Like
search(), this call travels over REST even on aGrpcIndex, because the gRPC API has no records operations.- Parameters:
records (list[dict[str, Any]]) – List of record dicts. Each must contain an
_idoridfield. Additional fields are passed through for server-side embedding.namespace (str) – Target namespace (required). Unlike
upsert(), namespace has no default because the records API requires an explicit namespace (must be non-empty).timeout (float | None) – Per-request deadline in seconds.
Noneuses thetimeoutthe index was constructed with.
- Returns:
UpsertRecordsResponsewhoserecord_countis how many records the client sent, counted locally — not a server confirmation that each one embedded.- Raises:
PineconeValueError – If namespace is not a string or is empty/whitespace, records is empty, or a record is missing an identifier field.
- Return type:
Examples
idx = pc.index(name="articles-en", grpc=True) response = idx.upsert_records( namespace="published", records=[ {"_id": "article-101", "text": "Vector DBs enable similarity search."}, {"_id": "article-102", "text": "RAG combines search with LLMs."}, ], ) print(response.record_count)
- search(*, namespace, top_k=None, inputs=None, vector=None, id=None, filter=None, fields=None, rerank=None, match_terms=None, query=None, timeout=None)[source]¶
Search records by text, vector, or ID with optional reranking.
Use this on an index with integrated inference: you send query text and the server embeds it. This call travels over REST even on a
GrpcIndex, because the gRPC API has no records search — so aretry_configyou passed toGrpcIndexdoes not govern it, and it retries on the REST data plane’s own fixed terms (Retries and Resilience).- Parameters:
namespace (str) – Namespace to search in (required).
top_k (int) – Number of results to return (must be >= 1).
inputs (SearchInputs | dict[str, Any] | None) – Inputs for server-side embedding (e.g.
{"text": "query text"}).id (str | None) – ID of an existing record to use as the query.
filter (dict[str, Any] | None) – Metadata filter expression.
fields (list[str] | None) – Field names to include in results. When
None, the server returns all available fields.rerank (RerankConfig | dict[str, Any] | None) – Reranking configuration with
model(required),rank_fields(required), and optionaltop_n,parameters,querykeys. UseRerankConfigfor IDE autocompletion.match_terms (dict[str, Any] | None) – Term-matching constraint for sparse search. Requires keys
"strategy"(currently only"all") and"terms"(list of strings). Valid only on a text query — combined withvectororidit is rejected — and only on a sparse index whose embedding model supports it; the server names the supported model when it refuses.Nonedisables term matching.timeout (float | None) – Per-request deadline in seconds.
Noneuses thetimeoutthe index was constructed with.query (dict[str, Any] | None) – Legacy query body containing
top_kplus one ofinputs,vector, orid. Prefer passing these fields directly.
- Returns:
SearchRecordsResponsewhoseresult.hitsareHitobjects — readhit.id,hit.score, andhit.fields— and whoseusagereports what the search, and any rerank, consumed.- Raises:
PineconeValueError – If
namespaceis not a string,top_k < 1, orrerankis missing required keys.- Return type:
Examples
response = idx.search( namespace="articles-en", top_k=10, inputs={"text": "benefits of vector databases for search"}, ) for hit in response.result.hits: print(hit.id, hit.score)
Search with reranking:
response = idx.search( namespace="articles-en", top_k=10, inputs={"text": "benefits of vector databases"}, rerank={ "model": "bge-reranker-v2-m3", "rank_fields": ["text"], "top_n": 5, }, ) for hit in response.result.hits: print(hit.id, hit.score)
See also
query()— for an index you upsert your own vectors into.Inference.rerank()— for reranking results that came from somewhere other than this index, or reranking without searching; the inlinererankabove covers the single-call case.
- search_records(*, namespace, top_k=None, inputs=None, vector=None, id=None, filter=None, fields=None, rerank=None, match_terms=None, query=None, timeout=None)[source]¶
Alias for
search(), kept for callers written against the old name.Identical arguments, identical behavior — it forwards straight to
search(), which is where the arguments are documented. Prefersearch()in new code.Examples
response = idx.search_records( namespace="articles-en", top_k=10, inputs={"text": "benefits of vector databases for search"}, ) for hit in response.result.hits: print(hit.id, hit.score)
See also
search()— the current name, and the full argument reference.
- list_namespaces_paginated(*, prefix=None, limit=None, pagination_token=None, timeout=None)[source]¶
Fetch a single page of namespace descriptions.
- Parameters:
prefix (str | None) – Return only namespaces whose names start with this prefix. Must be ASCII, must not contain the NUL character, and must be at most 512 characters. The empty prefix matches every namespace.
limit (int | None) – Maximum number of namespaces to return in this page, 1-100.
pagination_token (str | None) – Token from a previous response to fetch the next page.
timeout (float | None) – Per-call timeout in seconds.
- Returns:
ListNamespacesResponsewith namespace descriptions, pagination info, and total count. Each description carriessize_bytes.- Raises:
PineconeValueError – If prefix or limit violates the rules above. Raised locally, before the request is sent, with the same message the REST and asyncio clients raise.
- Return type:
Examples
page = idx.list_namespaces_paginated(prefix="articles-", limit=50) for ns in page.namespaces: print(ns.name, ns.record_count, ns.size_bytes) next_token = page.pagination.next if page.pagination else None
See also
list_namespaces()— the same walk with the tokens handled for you. See Pagination.
- list_namespaces(*, prefix=None, limit=None, timeout=None)[source]¶
List namespaces, automatically following pagination.
Yields one
ListNamespacesResponseper page. The generator automatically follows pagination tokens until all pages have been retrieved.- Parameters:
prefix (str | None) – Return only namespaces whose names start with this prefix. Must be ASCII, must not contain the NUL character, and must be at most 512 characters. The empty prefix matches every namespace.
limit (int | None) – Maximum number of namespaces to return per page, 1-100.
timeout (float | None) – Per-call timeout in seconds.
- Yields:
ListNamespacesResponsefor each page of results. EachNamespaceDescriptioncarriessize_bytes.- Raises:
PineconeValueError – If prefix or limit violates the rules above. Raised on the first iteration, before the request is sent.
- Return type:
Examples
for page in idx.list_namespaces(prefix="articles-"): for ns in page.namespaces: print(ns.name, ns.record_count, ns.size_bytes)
See also
list_namespaces_paginated()— one page at a time, when you need to persist a token between calls.describe_namespace()— for a single namespace, though prefer this method for more than one.
- create_namespace(*, name, schema=None, timeout=None)[source]¶
Create a named namespace in the index.
- Parameters:
name (str) – Name for the new namespace. Must be ASCII, must not contain the NUL character, and must be 1-512 characters long.
__default__is reserved and cannot be created: it names the namespace requests address when they omit a namespace, so it always exists.schema (dict[str, Any] | None) – Optional metadata-index configuration,
{"fields": {<field>: {"filterable": True}}}. Omitting it does not mean “index everything”: the namespace inherits the index’s own metadata-index configuration, so an index that restricts which fields are indexed passes that restriction on. Supply schema to override the inherited configuration for this namespace, indexing exactly the fields listed.filterableis required on each field and must beTrue— to leave a field unindexed, omit it fromfields.timeout (float | None) – Per-call timeout in seconds.
- Returns:
NamespaceDescriptionwith the namespace name, record count, schema, indexed fields, andsize_bytes.- Raises:
PineconeValueError – If name violates the rules above, or schema is malformed. Raised locally, before the request is sent, with the same message the REST and asyncio clients raise.
- Return type:
Examples
ns = idx.create_namespace(name="articles-en") print(ns.name, ns.record_count, ns.size_bytes)
Restrict which metadata fields this namespace indexes, overriding what it would otherwise inherit from the index:
ns = idx.create_namespace( name="articles-fr", schema={"fields": {"topic": {"filterable": True}}}, )
See also
describe_namespace()— read back the schema and indexed fields the namespace ended up with.
- describe_namespace(*, name=None, timeout=None, **kwargs)[source]¶
Describe a namespace by name.
This operation is rate limited per index, independently of the other namespace operations. Prefer
list_namespaces()when describing more than one namespace: it returns the same information for every namespace in a single request and is not subject to that limit.- Parameters:
- Returns:
NamespaceDescriptionwith the namespace name, record count, schema, indexed fields, andsize_bytes.- Raises:
PineconeValueError – If name violates the rules above. Raised locally, before the request is sent, with the same message the REST and asyncio clients raise.
TypeError – If unexpected keyword arguments are passed.
- Return type:
Examples
ns = idx.describe_namespace(name="articles-en") print(ns.name, ns.record_count, ns.size_bytes)
See also
list_namespaces()— the same fields for every namespace in one request, and not subject to this method’s rate limit.
- delete_namespace(*, name=None, timeout=None, **kwargs)[source]¶
Delete a namespace by name, removing all its vectors.
- Parameters:
- Returns:
None — a successful delete returns no payload.
- Raises:
PineconeValueError – If name violates the rules above. Raised locally, before the request is sent, with the same message the REST and asyncio clients raise.
TypeError – If unexpected keyword arguments are passed.
- Return type:
None
Examples
idx.delete_namespace(name="articles-en")
See also
delete()withdelete_all=True— empties a namespace but keeps the namespace itself, and its schema.
- start_import(uri, *, error_mode=None, integration_id=None)[source]¶
Start a bulk import operation from an external data source.
Initiates an asynchronous bulk import of vectors from cloud storage into the index. The import runs server-side; use
describe_import()to poll for progress and completion.Note
The import URI must point to a directory of Parquet files in cloud storage. Each Parquet file must follow the Pinecone-required schema. See Pinecone import docs for the required Parquet schema and supported storage formats.
- Parameters:
uri (str) – Directory prefix holding the Parquet files, not a single file. Three forms are accepted:
s3://for Amazon S3,gs://for Google Cloud Storage, and anhttps://URL naming an Azure Blob Storage container.s3://additionally requires that the index itself be hosted on AWS.error_mode (str | None) – How to handle a record the import cannot read.
"continue"skips it and imports the rest;"abort"ends the whole import at the first such record. Case-insensitive. Defaults to"abort"when omitted, so an unreadable record fails the import unless you opt into skipping.integration_id (str | None) – Optional integration ID for the import.
- Returns:
StartImportResponsewith the ID of the created import operation.- Raises:
PineconeValueError – If
error_modeis supplied but not"continue"or"abort".ApiError – If
uriis empty or longer than the server accepts, uses an unsupported scheme, is ans3://URI on an index not hosted on AWS, or names an S3 directory bucket, which imports do not support.
- Return type:
Examples
The call returns as soon as the import is accepted, so poll
describe_import()for the outcome:import time response = idx.start_import(uri="s3://my-bucket/vectors/") import_op = idx.describe_import(response.id) while import_op.status not in ("Completed", "Failed", "Cancelled"): time.sleep(10) import_op = idx.describe_import(response.id) print(import_op.status, import_op.records_imported)
Skip unreadable records rather than failing the whole import:
response = idx.start_import( uri="s3://my-bucket/vectors/", error_mode="continue", )
See also
upsert()— for upserting vectors directly in small batches (single request per call).upsert_records()— for indexes with integrated inference (text in, server-side embedding).upsert_from_dataframe()— for loading vectors from a pandas DataFrame with automatic batching.
- describe_import(id)[source]¶
Describe a bulk import operation by ID.
- Parameters:
id (str | int) – Import operation ID. Integers are converted to strings silently.
- Returns:
ImportModelwith the import operation details.- Raises:
PineconeValueError – If the ID is empty or exceeds 1000 characters.
- Return type:
Examples
import_op = idx.describe_import("import-123") print(import_op.status, import_op.percent_complete)
See also
list_imports()— every import on this index, without knowing an ID.
- cancel_import(id)[source]¶
Cancel a running bulk import operation by ID.
- Parameters:
id (str | int) – ID of the import to cancel, as returned by
start_import(). Integers are converted to strings silently.- Returns:
None — a successful cancellation returns no payload.
- Raises:
PineconeValueError – If the ID is empty or exceeds 1000 characters.
- Return type:
None
Examples
idx.cancel_import("import-123")
See also
describe_import()— poll it afterwards to confirm the import reached"Cancelled".
- list_imports(*, limit=None, pagination_token=None)[source]¶
List bulk import operations, automatically following pagination.
Yields individual
ImportModelobjects, fetching additional pages transparently until all results have been returned. Preferlist_imports_paginated()to control pagination yourself.- Parameters:
- Yields:
ImportModelfor each import operation.- Return type:
Examples
for imp in idx.list_imports(): print(imp.id, imp.status)
See also
list_imports_paginated()— one page at a time, when you need to persist a token between calls. See Pagination.
- list_imports_paginated(*, limit=None, pagination_token=None)[source]¶
Fetch a single page of bulk import operations.
Returns an
ImportListfor one page. The caller is responsible for managing the pagination token. Preferlist_imports()to have pagination handled automatically.- Parameters:
- Returns:
ImportListfor the requested page, iterable over itsImportModelentries. Itspagination.nextfield holds the token for the next page, orNoneonce there are no more.- Return type:
Examples
page = idx.list_imports_paginated(limit=10) for imp in page: print(imp.id, imp.status) next_token = page.pagination.next if page.pagination else None
See also
list_imports()— the same walk with the tokens handled for you. See Pagination.
- close()[source]¶
Close the connection to the index and release background resources.
Waits for any in-flight
*_asyncsubmissions to finish, then closes the network connection. Call this when you are done issuing requests through this client and are not using it as a context manager.Examples
idx = pc.index(name="articles-en", grpc=True) idx.upsert(vectors=all_vectors, namespace="published") idx.close()
See also
__enter__()— using the client as a context manager closes it for you, including on the way out of an exception.- Return type:
None
PineconeFuture¶
*_async() methods on GrpcIndex return a
PineconeFuture which is fully compatible with
concurrent.futures.as_completed() and concurrent.futures.wait().
- class pinecone.grpc.future.PineconeFuture(underlying)[source]¶
Bases:
Future[_T]A handle on a
GrpcIndex.*_async()call that is already in flight.The call was handed to a background thread and the method returned immediately. Issue as many as you want, then collect them: call
result()to block for one, or pass the whole batch toconcurrent.futures.as_completed()orconcurrent.futures.wait(), both of which this class supports. Nothing is cancelled if you never collect a future — the request still reaches the server.This is threads, not
await. Nothing here is awaitable, and the surrounding function does not need to beasync. If your code is already running under asyncio,AsyncIndexis the client you want instead: its methods are coroutines, so a pending request yields to the event loop rather than parking a worker thread.result()andexception()default to a 5 second wait, short enough that an unfinished call raises rather than hanging; pass an explicittimeout=for anything slower, ortimeout=Noneto block until the call settles.Examples
from pinecone.grpc import GrpcIndex idx = GrpcIndex(host="article-search-abc123.svc.pinecone.io", api_key="...") future = idx.upsert_async(vectors=[("article-101", [0.012, -0.087, 0.153])]) print(future.result().upserted_count)
Issuing several at once is the reason to prefer these over the blocking methods — the requests overlap instead of queueing:
from concurrent.futures import as_completed futures = [ idx.upsert_async(vectors=[("article-101", [0.012, -0.087, 0.153])]), idx.upsert_async(vectors=[("article-102", [0.045, 0.021, -0.064])]), ] for future in as_completed(futures): print(future.result().upserted_count)
See also
AsyncIndex— the asyncio client, for code that awaits rather than joining threads. See Sync vs Async Clients.- Parameters:
underlying (Future[_T])
- __init__(underlying)[source]¶
Initializes the future. Should not be called by clients.
- Parameters:
underlying (Future[_T])
- Return type:
None
- result(timeout=5.0)[source]¶
Block until the call settles, then return what it returned.
- Parameters:
timeout (float | None) – Maximum seconds to wait, defaulting to 5.0. Pass
Noneto block until the call settles, however long that takes.- Returns:
Whatever the underlying
GrpcIndexmethod would have returned had you called it directly — anUpsertResponsefromupsert_async, aQueryResponsefromquery_async, and so on.- Raises:
PineconeTimeoutError – If timeout elapses first. The call is still in flight and may yet reach the server; call
result()again to keep waiting.- Return type:
_T
Examples
future = idx.upsert_async(vectors=[("article-101", [0.012, -0.087, 0.153])]) print(future.result().upserted_count)
A large batch usually needs more than the 5-second default:
future = idx.upsert_async(vectors=large_batch) result = future.result(timeout=30.0)
- exception(timeout=5.0)[source]¶
Block until the call settles, then return how it failed, or
None.Use this to inspect a failure without it propagating, where
result()would re-raise it.- Parameters:
timeout (float | None) – Maximum seconds to wait, defaulting to 5.0. Pass
Noneto block until the call settles.- Returns:
The exception the call raised, or
Noneif it succeeded.- Raises:
PineconeTimeoutError – If timeout elapses before the call settles. This is the wait timing out, not the call failing.
- Return type:
BaseException | None
Examples
future = idx.upsert_async(vectors=[("article-101", [0.012, -0.087, 0.153])]) error = future.exception(timeout=30.0) if error is not None: print("upsert failed:", error)
- cancel()[source]¶
Try to cancel the call before a worker thread picks it up.
Returns
Trueonly if the call had not started yet. Once it is running there is no way to recall it — you getFalseand the request still reaches the server, so treat aFalsehere as “the write may land” rather than “nothing happened”.Examples
future = idx.upsert_async(vectors=[("article-101", [0.012, -0.087, 0.153])]) if not future.cancel(): future.result(timeout=30.0)
- Return type:
- add_done_callback(fn)[source]¶
Run fn once the call settles, instead of blocking on it.
fn receives this future as its only argument, and runs on the worker thread that finished the call — so keep it short, and do not call
result()on a different pending future from inside it. Adding a callback to a future that has already settled runs fn immediately, on the calling thread.Examples
def log_result(future): print("upserted", future.result().upserted_count) idx.upsert_async( vectors=[("article-101", [0.012, -0.087, 0.153])] ).add_done_callback(log_result)