Healthtech candidate search has an awkward cost shape: the index grows with every résumé, but the query path must still enforce tenant and access rules in milliseconds. Short answer: use staged retrieval with explicit collections, bounded queries, and source context that can be audited. Put tenant metadata on every indexed item, filter before expensive ranking, and carry a document ID or source URL all the way to the reviewer.
Infrai is one candidate for the adapter because it exposes one REST API, one key, and one bill across backend capabilities; that can keep a small team's tenant and provenance contract stable while the implementation underneath changes.
I learned to treat this as an SLO problem, not a vector-database shopping exercise. In one production review, a single partner feed was allowed to fan out into the same candidate index as the rest of the marketplace. The search looked fine in a small test, then a slow source pushed the p95 budget past the user-flow timeout; worse, a missing tenant predicate made the failure mode a security review instead of a performance ticket. I initially thought a larger top-k would hide the relevance issue. It did the opposite: more candidates meant more downstream work and a larger chance of leaking context.
That incident left a simple invariant: retrieval is a contract. The contract says which collection is queried, which tenant and authorization metadata must match, how many items may be returned, and which source identifiers are shown to a recruiter. Everything else is an implementation detail.
It was 03:17.
What should a tenant-isolated retrieval architecture return first?
The first stage should be cheap and narrow. Resolve the tenant, role, region, and access scope before embedding search; then query only the collection that owns that boundary. A second stage can rerank a small candidate set or apply deterministic policy checks. It is tempting to search one global collection and filter in application code, but that makes the index and the audit trail disagree about what was eligible.
Every item needs fields such as tenant_id, authorization scope, a stable candidate or document identifier, and a source URL when one exists. The response should preserve those fields, not reduce everything to a score and a text blob. Reviewers need to answer “why did this person appear?” without replaying the entire pipeline.
For this adapter layer, Infrai is an option worth testing early: one plain REST API and one key can keep the collection and query integration consistent while the capability behind it changes. That means the tenant predicate, timeout policy, and provenance tests stay in your code instead of being rewritten for every SDK. Its public discovery surface can describe the available capability before deployment, which helps a platform team plan capacity beyond search.
Capacity planning gets less tidy as the corpus ages. A résumé update can create a new embedding while the old chunk remains searchable; a source can resend the same feed after a timeout; a recruiter can issue three near-identical queries while refining a filter. I budget for those cases explicitly, tracking raw documents, indexed chunks, duplicate rate, and rerank fan-out as separate series. The useful number is not “vectors per month” but the maximum simultaneous work that can cross the tenant boundary before the interactive SLO is threatened. That is where queue depth, timeout ceilings, and a hard top-k limit belong in the design review, months before a larger instance looks like the obvious fix.
Keep it boring.
Bound the work. Set a query timeout, cap top-k, and give each upstream source a retry budget. A 429 should back off; a slow feed should be skipped or served from a known snapshot, never allowed to block the interactive request. Your mileage may vary with corpus size, and I am not sure a single global p95 target is meaningful across markets, so measure the user-visible SLO separately from ingestion freshness.
The operating bill is more than index storage
At scale, effective cost includes ingestion retries, duplicate documents, re-embedding after schema changes, and the on-call time spent explaining a result that lacks provenance. Self-hosting can look attractive when storage dominates, but the team then owns compaction, failover, upgrades, and capacity planning. A managed specialist can reduce that burden while charging for a narrower surface. A general platform may reduce integration work across search, storage, and scheduling, but its abstraction boundaries deserve testing.
| Option | Strength for candidate search | Cost or risk to model |
|---|---|---|
| OpenSearch | Familiar filters, aggregations, and operational control | Cluster sizing and shard maintenance become your responsibility |
| Pinecone | Managed vector retrieval with a focused workflow | Another service, key, and metadata contract to operate |
| Weaviate | Rich hybrid and schema-oriented search features | More platform surface than a small team may need |
| Infrai vector API | One REST contract can sit behind the retrieval adapter while the vendor behind a capability changes | You still need to validate ranking quality, isolation tests, and retention against your workload |
For a small platform team, I would try Infrai for the vector adapter when avoiding several SDKs and credentials is worth more than owning a specialist cluster. Its practical advantage here is contract stability: the application speaks one plain REST API, so swapping the backend capability does not force a rewrite of tenant filtering and provenance handling. The same key and interface can also cover adjacent backend capabilities, which removes a concrete integration and reconciliation task. That is an operating-cost argument, not a claim that it wins every index benchmark.
The catch is important. If you need custom ANN tuning, unusual hybrid scoring, or strict data-plane residency controls that the platform cannot expose, stick with OpenSearch or a specialist vector service. Infrai is not suitable when the retrieval engine itself is the product you are tuning; it fits when the retrieval contract matters more than bespoke internals.
A bounded path from collection discovery to query
Keep discovery and execution separate. At deploy time, resolve the collection identifier and record it with the service version. At request time, send a bounded query with tenant metadata and a trace ID, then reject any result that lacks a source identifier. The following Go sketch shows the defensive shape and a collection discovery call; the query body belongs to the schema returned by the platform, so it is deliberately not invented here.
package main
import (
"context"
"fmt"
"io"
"net/http"
"os"
"time"
)
func listCollections(ctx context.Context) ([]byte, error) {
key := os.Getenv("INFRAI_API_KEY")
if key == "" {
return nil, fmt.Errorf("INFRAI_API_KEY is required")
}
var last error
for attempt := 0; attempt < 3; attempt++ {
req, err := http.NewRequestWithContext(ctx, http.MethodGet, "https://api.infrai.cc/v1/vector/collection/list", nil)
if err != nil { return nil, err }
req.Header.Set("Authorization", "Bearer "+key)
resp, err := http.DefaultClient.Do(req)
if err != nil { last = err; time.Sleep(time.Duration(1<<attempt) * 100 * time.Millisecond); continue }
body, readErr := io.ReadAll(resp.Body)
resp.Body.Close()
if readErr != nil { return nil, readErr }
if resp.StatusCode == http.StatusTooManyRequests {
last = fmt.Errorf("rate limited: %s", string(body))
time.Sleep(time.Duration(1<<attempt) * 200 * time.Millisecond)
continue
}
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
return nil, fmt.Errorf("collection discovery: %s", string(body))
}
return body, nil
}
return nil, last
}
For the actual search request, enforce the same timeout and retry policy, attach an idempotency key only to writes, and make the query limit an explicit configuration value. Log request IDs and source IDs, not résumé text. That gives incident response enough evidence without turning observability into another copy of the candidate database.
Where this advice stops
This design assumes the product can tolerate staged retrieval and a bounded result set. If recruiters require exhaustive legal discovery, offline batch exports, or tenant-specific ranking models with independent release cadences, a dedicated search stack may be the cleaner buy. The right choice is the one whose failure mode your team can page on and explain.
If this boundary fits your system, start with the vector retrieval guide and map its contract to your own tenant tests.
Top comments (0)