Skip to content

Use bulk scoring in NeighborArray#isWorstNonDiverse#15667

Open
ML-dev-crypto wants to merge 1 commit intoapache:branch_10xfrom
ML-dev-crypto:branch_10x
Open

Use bulk scoring in NeighborArray#isWorstNonDiverse#15667
ML-dev-crypto wants to merge 1 commit intoapache:branch_10xfrom
ML-dev-crypto:branch_10x

Conversation

@ML-dev-crypto
Copy link
Copy Markdown

This change updates NeighborArray#isWorstNonDiverse to use the
RandomVectorScorer#bulkScore API, avoiding repeated per-neighbor
score calls in a hot loop.

The bulkScore method is a default interface method and safely falls
back to per-node scoring when not overridden by a scorer.

Fixes #15606

@benwtrent
Copy link
Copy Markdown
Member

@ML-dev-crypto Could you benchmark with lucene util to validate if this is actually worth it?

Comment on lines +318 to +325
// Allocate a temporary buffer for scores.
// NeighborArray size is typically small (M=16 or 32), so this allocation is acceptable
// and keeps the change localized to this class.
float[] neighborScores = new float[numNodesToCheck];

// Bulk score all neighbors.
// The default implementation in RandomVectorScorer handles the fallback if needed.
scorer.bulkScore(nodes.buffer, neighborScores, numNodesToCheck);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please, delete all the useless LLM-esque comments. We can see what its doing. Comments describing "what" are fairly useless.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. I've removed the verbose comments and kept the documentation focused on the 'why' rather than the 'what'.

}

// Bulk score all unchecked neighbors
scorer.bulkScore(nodesToCheck, neighborScores, numNodesToCheck);
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why can't use use the max score returned from bulk score?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THANKS FOR YOUR GUIDANCE I've updated the logic to capture the return value from bulkScore and use it for an early exit. If the maximum similarity in the batch is worse than the candidate, we can return immediately without iterating.

float minAcceptedSimilarity = scores.get(candidateIndex);
if (candidateIndex == uncheckedIndexes[uncheckedCursor]) {
// the candidate itself is unchecked
for (int i = candidateIndex - 1; i >= 0; i--) {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we have the scratch data passed in here?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should be able to pass in int[] and float[]. I am not sure why you only passed in one.

I suggest maybe using the DocAndFloatFeatureBuffer

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

THANKS FOR YOUR GUIDANCE AND TIME.Right now this PR removes the dominant allocation by reusing the float[] in the hot path. There is still a small int[] allocation when gathering unchecked nodes, which could be avoided by passing both int[] and float[] or by using DocAndFloatFeatureBuffer.
I kept this PR minimal and behavior-preserving, but I’m happy to extend it to reuse both buffers if you’d prefer that in this change.

@github-actions github-actions Bot added this to the 10.5.0 milestone Feb 6, 2026
Reuse a scratch buffer during HNSW diversity checks and use
RandomVectorScorer.bulkScore with early termination to avoid
per-call allocations on the hot path.
@navneet1v
Copy link
Copy Markdown
Contributor

@ML-dev-crypto do we know what is the impact in performance because of this change?

@ML-dev-crypto
Copy link
Copy Markdown
Author

@ML-dev-crypto do we know what is the impact in performance because of this change?

Thanks for the question. Theoretically, this change eliminates array allocations in the hot path of graph construction and utilizes vector API bulk scoring, which should reduce GC pressure and improve throughput.
I am currently setting up the standard luceneutil benchmark to quantify the exact impact. I will post the results here as soon as they are available.

@github-actions
Copy link
Copy Markdown
Contributor

This PR has not had activity in the past 2 weeks, labeling it as stale. If the PR is waiting for review, notify the dev@lucene.apache.org list. Thank you for your contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants