meilisearch / meilisearch/arroy

Proposal: Use a bounded top-K heap in nns_by_leaf instead of full sort

Open
#156 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Rust
Stars
311
Forks
17
PR merge metrics
No merged PRs in 30d

Description

🧩 Proposal: Use a bounded top-K heap in nns_by_leaf instead of full sort
Why

nns_by_leaf currently collects all candidate neighbors, computes their distances, and performs a full sort_unstable_by() before truncating to the requested count.
This is O(N log N), even though we only need the top-K results.
For large searches (e.g. 100 K+ candidates, K ≈ 100), this adds unnecessary latency and allocations.

What

Replace the final “collect + sort + truncate” logic with a bounded max-heap that only keeps the best K elements as we iterate.
This reduces complexity to O(N log K) and limits allocations to count.

Expected impact
  • ~20 – 40 % faster query times on large datasets
  • Lower peak memory usage
  • Smaller CPU and cache footprint
How

Example sketch (~20 lines):

use std::collections::BinaryHeap;

fn nns_by_leaf(&self, query: &[f32], count: usize) -> Vec<(f32, usize)> {
    let mut heap = BinaryHeap::with_capacity(count);

    for candidate_id in self.collect_candidates(query) {
        let vector = self.database.get_vector(candidate_id);
        let dist = self.distance(query, &vector);

        if heap.len() < count {
            heap.push((dist, candidate_id));
        } else if dist < heap.peek().unwrap().0 {
            heap.pop();
            heap.push((dist, candidate_id));
        }
    }

    let mut results: Vec<_> = heap.into_vec();
    results.sort_unstable_by(|a, b| a.0.partial_cmp(&b.0).unwrap());
    results
}
Notes
  • Drop-in replacement; preserves existing behavior.
  • No dependency changes.
  • Optional future improvement: use select_nth_unstable_by() for large K.

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the nns_by_leaf entry point and inspect its current candidate collection, distance calculation, full sort, and truncation flow. Replace only that selection logic while preserving result ordering and behavior; done means the existing search behavior remains correct and the top-K path avoids sorting all candidates.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
performance
Issue type
Refactor
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.