Search Quality Controls

indexbind exposes a small set of search knobs. The important distinction is where each knob applies:

Recall Controls

mode

const hits = await index.search('rust guide', {
  mode: 'hybrid',
});

mode: 'hybrid' combines vector and lexical retrieval before the final ranked list is built.

Use it when you want a safer default across exact matches and semantic matches.

const hits = await index.search('rust guide', {
  mode: 'vector',
});

mode: 'vector' means vector-only retrieval.

const hits = await index.search('rust guide', {
  mode: 'lexical',
});

mode: 'lexical' means lexical-only retrieval.

relativePathPrefix

const hits = await index.search('rust guide', {
  relativePathPrefix: 'guides/',
});

This limits candidate documents to a path prefix before ranking is finalized.

Use it when your application already knows which subtree should be searched.

metadata

const hits = await index.search('rust guide', {
  metadata: {
    lang: 'rust',
    visibility: 'public',
  },
});

Metadata filtering is exact-match filtering. It narrows the candidate set before the final result list is returned.

Use it when your host application needs product-level filtering such as:

Reranking Controls

reranker.kind

const hits = await index.search('rust guide', {
  reranker: { kind: 'heuristic-v1' },
});

Available kinds:

heuristic-v1 is a lightweight reranker that prefers strong title and heading matches.

embedding-v1 uses the embedding layer to rerank the candidate pool with stronger semantic judgment.

reranker.candidatePoolSize

const hits = await index.search('rust guide', {
  topK: 5,
  reranker: {
    kind: 'embedding-v1',
    candidatePoolSize: 25,
  },
});

This controls how many candidates reach the reranker before the final topK cut.

Increase it when:

Final Ordering Controls

scoreAdjustment.metadataNumericMultiplier

const hits = await index.search('rust guide', {
  scoreAdjustment: {
    metadataNumericMultiplier: 'directory_weight',
  },
});

This multiplies the final score by a numeric metadata field on each hit.

Use it for host-defined ranking priors such as:

This is intentionally generic. indexbind does not define what the metadata field means.

minScore

const hits = await index.search('rust guide', {
  topK: 10,
  minScore: 0.05,
});

This drops low-scoring tail hits after reranking and score adjustment.

Use it when you want:

minScore is most useful when your index, embedding backend, reranker choice, and score-adjustment profile are fixed. Treat it as a profile-tuned tail cutoff, not a universal confidence value across every retrieval configuration.

Recommended Defaults

For many embedded products, a good starting point is:

const hits = await index.search(query, {
  topK: 10,
  mode: 'hybrid',
  reranker: {
    kind: 'embedding-v1',
    candidatePoolSize: 25,
  },
});

Then layer on metadata filters and scoreAdjustment only when your host application has clear product rules that should influence ranking.

Add minScore once you have a stable search profile and want to trim weak tail matches.

What These Knobs Do Not Solve

These controls help retrieval quality, but they do not replace:

Those concerns still belong in the application that embeds indexbind.