Reranking results¶
Reranking reorders a set of candidate documents by relevance to a query. It runs a second, slower model over candidates something else already found — vector search, keyword search, or another system entirely — and usually buys precision at the top of the list at the cost of latency.
Basic usage¶
from pinecone import Pinecone
pc = Pinecone(api_key="your-api-key")
documents = [
{"text": "Apple is a technology company."},
{"text": "The apple is a popular fruit."},
{"text": "Acme Inc. revolutionized enterprise software."},
]
result = pc.inference.rerank(
model="bge-reranker-v2-m3",
query="Tell me about tech companies",
documents=documents,
)
for ranked in result.data:
print(ranked.index, ranked.score, ranked.document)
Pass plain strings and each is wrapped as {"text": ...}, which is what the default
rank_fields scores on:
result = pc.inference.rerank(
model="bge-reranker-v2-m3",
query="machine learning",
documents=["Neural networks are a type of ML model.", "Python is a programming language."],
)
print(result.data[0].index)
index maps a result back onto your list¶
result.data is ordered by descending score, not by the order you passed the
documents in. Each RankedDocument carries the
position it held in your documents argument as .index, and that is the whole point of
the API: it is how you find the record, the ID, or the row that the score belongs to.
In the first example above, the third document is the most relevant, so the first result
has .index == 2 — not 0:
top = result.data[0]
print(top.index) # position in the documents you sent
print(top.score) # relevance, higher is more relevant
print(top.document) # the document as sent, or None with return_documents=False
Reading result.data positionally and ignoring .index silently pairs your scores with
the wrong documents.
The usual way to avoid the bookkeeping is to keep your own identifier on each document.
Every key that is not named in rank_fields rides along untouched and comes back in
.document:
result = pc.inference.rerank(
model="bge-reranker-v2-m3",
query="Tell me about tech companies",
documents=[
{"id": "doc-1", "summary": "Apple is a fruit."},
{"id": "doc-2", "summary": "Acme Inc. revolutionized tech."},
],
rank_fields=["summary"],
)
print(result.data[0].document["id"])
Response: RerankResult¶
rerank returns a RerankResult:
.data— theRankedDocumentlist, ordered by descendingscore..model— the model that served the request. Pinecone may substitute a different model from the one you asked for, so read it here rather than assuming it echoes your argument..usage.rerank_units— rerank units counted for the call.
top_n: return only the best results¶
By default every document you send comes back with a score. Pass top_n to keep only the
best n:
result = pc.inference.rerank(
model="bge-reranker-v2-m3",
query="search query",
documents=documents,
top_n=2,
)
print(len(result.data))
top_n below 1 is rejected client-side, before any request is made.
rank_fields: choose which field to score on¶
The reranker scores the "text" field unless you say otherwise. Name your own fields
with rank_fields:
result = pc.inference.rerank(
model="bge-reranker-v2-m3",
query="quarterly earnings",
documents=[
{"title": "Acme Q4 results", "body": "Revenue grew year over year."},
{"title": "Banana prices rise", "body": "Fruit prices hit new highs."},
],
rank_fields=["title", "body"],
)
print(result.data[0].document)
Not every model accepts more than one rank field. supported_parameters on the model
info says what a given model will take — see
Discover what a model accepts.
Skip the round trip on the documents¶
Set return_documents=False when you already hold the documents in memory and want only
the ordering. .document is then None and you rely on .index:
result = pc.inference.rerank(
model="bge-reranker-v2-m3",
query="search query",
documents=documents,
return_documents=False,
)
print(result.data[0].index, result.data[0].document)
Using the RerankModel enum¶
RerankModel gives you tab-completion and typo safety in
place of a bare string:
from pinecone import Pinecone, RerankModel
pc = Pinecone(api_key="your-api-key")
result = pc.inference.rerank(
model=RerankModel.Bge_Reranker_V2_M3,
query="machine learning",
documents=["Neural networks are a type of ML model."],
)
print(result.model)
A model that is not an enum member is still fine as a string. A name the API does not
serve raises NotFoundError, and a model your project
is not authorized to use — including a deprecated one — raises
ForbiddenError. Check the name before suspecting the
request body.
Reranking in a pipeline¶
Two-stage retrieval: fetch a wide candidate set from Pinecone, then rerank it down.
from pinecone import Pinecone
pc = Pinecone(api_key="your-api-key")
index = pc.index("product-search")
# Stage 1: vector retrieval. Embed the query as a query, not a passage.
query_vector = pc.inference.embed(
model="multilingual-e5-large",
inputs="best noise-cancelling headphones",
parameters={"input_type": "query"},
).data[0].values
response = index.query(vector=query_vector, top_k=20, include_metadata=True)
# Stage 2: rerank. Carry the vector ID through so the scores stay attributable.
candidates = [
{"id": match.id, "text": (match.metadata or {}).get("description", "")}
for match in response.matches
]
reranked = pc.inference.rerank(
model="bge-reranker-v2-m3",
query="best noise-cancelling headphones",
documents=candidates,
rank_fields=["text"],
top_n=5,
)
for ranked in reranked.data:
print(ranked.document["id"], ranked.score)
top_k decides how many candidates stage one retrieves; top_n decides how many survive
stage two. Retrieving more than you intend to keep is the point — reranking can only
reorder what stage one found.
An empty documents list is rejected client-side, so guard the second stage when stage
one can return nothing.
For an index with integrated inference, rerank is an argument to
search() and both stages happen in one request. See
Integrated records. Reach for
pc.inference.rerank when the candidates came from somewhere other than that index.
List available reranking models¶
models = pc.inference.model.list(type="rerank")
print(models.names())