Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
8c42e95
Use searchable snapshot in vector jmh
ChrisHegarty Jan 30, 2026
c938f1a
itr
ChrisHegarty Feb 3, 2026
0b80022
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 3, 2026
0828cd2
itr
ChrisHegarty Feb 3, 2026
9a97011
itr
ChrisHegarty Feb 3, 2026
fc23dee
typo
ChrisHegarty Feb 3, 2026
bc4bbf5
itr
ChrisHegarty Feb 3, 2026
8056dc2
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 6, 2026
a15dc37
revert
ChrisHegarty Feb 6, 2026
b620ca7
revert
ChrisHegarty Feb 6, 2026
d1ad5fd
[CI] Auto commit changes from spotless
Feb 6, 2026
1d10b8b
itr
ChrisHegarty Feb 9, 2026
e776c72
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 9, 2026
f63bbb1
fix bench
ChrisHegarty Feb 9, 2026
04ae17d
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 9, 2026
f92e1ce
Bump the default BlobCacheBufferIndexInput buffer from 1k to 4k for s…
ChrisHegarty Feb 9, 2026
41d72f3
Merge branch 'main' into default_blob_cache_input_buffer_size
ChrisHegarty Feb 9, 2026
a81bd5d
Merge branch 'main' into default_blob_cache_input_buffer_size
ChrisHegarty Feb 9, 2026
7dd999e
refactor
ChrisHegarty Feb 9, 2026
7afec0e
itr
ChrisHegarty Feb 10, 2026
21d1116
itr
ChrisHegarty Feb 10, 2026
4bf0c59
Enable searchable snapshot directory in vector tests and benchmarks
ChrisHegarty Feb 10, 2026
54c8583
Merge branch 'main' into ss_in_vec_tests
ChrisHegarty Feb 10, 2026
9efc9a5
Merge branch 'main' into ss_in_vec_tests
ChrisHegarty Feb 10, 2026
246506b
itr
ChrisHegarty Feb 10, 2026
fc14459
Merge remote-tracking branch 'chegar/default_blob_cache_input_buffer_…
ChrisHegarty Feb 10, 2026
177fa8e
Merge branch 'main' into default_blob_cache_input_buffer_size
ChrisHegarty Feb 10, 2026
9faef6b
itr
ChrisHegarty Feb 10, 2026
7e6971e
Merge remote-tracking branch 'chegar/default_blob_cache_input_buffer_…
ChrisHegarty Feb 10, 2026
50a4b37
itr
ChrisHegarty Feb 10, 2026
7166bdb
Merge remote-tracking branch 'chegar/ss_in_vec_tests' into bbq_vec_ops
ChrisHegarty Feb 10, 2026
703dea5
Merge branch 'default_blob_cache_input_buffer_size' into bbq_vec_ops
ChrisHegarty Feb 10, 2026
2323933
[CI] Auto commit changes from spotless
Feb 10, 2026
39c35ec
itr
ChrisHegarty Feb 11, 2026
1a95e35
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 11, 2026
93f3af2
reverts
ChrisHegarty Feb 11, 2026
15ea286
itr
ChrisHegarty Feb 11, 2026
d1c5873
Merge remote-tracking branch 'chegar/ss_in_vec_tests' into ss_in_vec_…
ChrisHegarty Feb 11, 2026
55f4e2c
itr
ChrisHegarty Feb 11, 2026
8c773a5
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 11, 2026
96d956b
Merge branch 'main' into ss_in_vec_tests
ChrisHegarty Feb 11, 2026
d01df59
ref count
ChrisHegarty Feb 11, 2026
43c9f25
eager close
ChrisHegarty Feb 11, 2026
f539831
private memory segment
ChrisHegarty Feb 11, 2026
4187028
[CI] Auto commit changes from spotless
Feb 11, 2026
a0873b9
export
ChrisHegarty Feb 11, 2026
f663a8e
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 11, 2026
5b9603e
typo
ChrisHegarty Feb 11, 2026
3a4b50f
use temp files in SearchableSnapshotDirectoryFactory
ChrisHegarty Feb 12, 2026
e4c4e0a
final
ChrisHegarty Feb 12, 2026
6adff83
use snap in knnIndexTester
ChrisHegarty Feb 12, 2026
7688d5d
Merge branch 'main' into ss_in_vec_tests
ChrisHegarty Feb 13, 2026
d574423
revert
ChrisHegarty Feb 13, 2026
04fa7e8
fix file length
ChrisHegarty Feb 13, 2026
0205c44
use a fs blob container
ChrisHegarty Feb 13, 2026
29a35d5
Merge branch 'main' into ss_in_vec_tests
ChrisHegarty Feb 13, 2026
5ce73a9
fix shared bytes leak
ChrisHegarty Feb 13, 2026
5d01670
Merge branch 'main' into ss_in_vec_tests
ChrisHegarty Feb 13, 2026
37b1787
Merge branch 'main' into ss_in_vec_tests
ChrisHegarty Feb 13, 2026
6ca3230
Merge branch 'ss_in_vec_tests' into bbq_vec_ops
ChrisHegarty Feb 13, 2026
c1f9a19
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 13, 2026
25c99db
Merge remote-tracking branch 'upstream/main' into bbq_vec_ops
ChrisHegarty Feb 17, 2026
44fb563
[CI] Auto commit changes from spotless
Feb 17, 2026
3639bab
revert
ChrisHegarty Feb 17, 2026
cd16719
revert
ChrisHegarty Feb 17, 2026
d218432
revert
ChrisHegarty Feb 17, 2026
8c8e5dd
[CI] Auto commit changes from spotless
Feb 17, 2026
0ff7d47
update int7 for centroid sccoring and knn index tester
ChrisHegarty Feb 17, 2026
51c8472
wither
ChrisHegarty Feb 17, 2026
d3ac439
add missing file
ChrisHegarty Feb 18, 2026
ee06e44
Merge remote-tracking branch 'upstream/main' into bbq_vec_ops
ChrisHegarty Feb 18, 2026
5363ee7
move to core
ChrisHegarty Feb 18, 2026
a0367eb
[CI] Auto commit changes from spotless
Feb 18, 2026
8c93a25
itr
ChrisHegarty Feb 18, 2026
1296a72
itr
ChrisHegarty Feb 18, 2026
019f57e
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 18, 2026
c0cbf45
remove transitive
ChrisHegarty Feb 18, 2026
3b2546b
more tests
ChrisHegarty Feb 18, 2026
efd8169
itr
ChrisHegarty Feb 18, 2026
cefd951
more bits
ChrisHegarty Feb 18, 2026
21854dc
remove memorysegment
ChrisHegarty Feb 18, 2026
b42db0c
itr
ChrisHegarty Feb 18, 2026
4399355
itr
ChrisHegarty Feb 18, 2026
cf6bdc1
itr
ChrisHegarty Feb 18, 2026
822f9fd
stored metrics
ChrisHegarty Feb 18, 2026
1c8314c
itr
ChrisHegarty Feb 18, 2026
efd70d2
some reverts
ChrisHegarty Feb 18, 2026
07c8069
more reverts
ChrisHegarty Feb 18, 2026
95b65d1
more reverts
ChrisHegarty Feb 18, 2026
48c18c7
itr
ChrisHegarty Feb 18, 2026
62b5095
itr
ChrisHegarty Feb 18, 2026
926dbcb
minor
ChrisHegarty Feb 18, 2026
e5a5598
itr
ChrisHegarty Feb 18, 2026
58ecaa4
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 18, 2026
2f87d0e
extensible knnindextester
ChrisHegarty Feb 19, 2026
17c7541
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 19, 2026
3ce2f87
fix acceptable input types
ChrisHegarty Feb 19, 2026
7ddbfa1
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 19, 2026
6e1c7ec
fix
ChrisHegarty Feb 19, 2026
8968d7c
Merge remote-tracking branch 'upstream/main' into bbq_vec_ops
ChrisHegarty Feb 19, 2026
c98c67a
[CI] Auto commit changes from spotless
Feb 19, 2026
39b6cf0
fix
ChrisHegarty Feb 19, 2026
7afcd16
fix
ChrisHegarty Feb 19, 2026
9ac050a
javadoc
ChrisHegarty Feb 19, 2026
c2bf25c
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 19, 2026
588463d
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 19, 2026
748f491
Merge remote-tracking branch 'upstream/main' into bbq_vec_ops
ChrisHegarty Feb 23, 2026
927afb3
fix :qa:vector:checkVec
ChrisHegarty Feb 23, 2026
432aac5
fix :qa:vector:checkVec
ChrisHegarty Feb 23, 2026
a8f056f
Merge branch 'main' into fix_qa_vector_checkVec
ChrisHegarty Feb 23, 2026
718ea9d
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 23, 2026
a183a74
[CI] Auto commit changes from spotless
Feb 23, 2026
02467a6
itr
ChrisHegarty Feb 23, 2026
a372af9
Merge remote-tracking branch 'chegar/fix_qa_vector_checkVec' into bbq…
ChrisHegarty Feb 23, 2026
79f69ec
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 23, 2026
9462242
Move DirectAccessInput interface from BlobCacheBufferedIndexInput t…
ChrisHegarty Feb 23, 2026
0342b44
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 23, 2026
91d7b54
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Feb 23, 2026
7b90c4c
remove atomic
ChrisHegarty Feb 23, 2026
cf65b22
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 23, 2026
75c3ba6
rename and check input type in more places
ChrisHegarty Feb 23, 2026
fc4eca5
Update docs/changelog/141718.yaml
ChrisHegarty Feb 23, 2026
c37998f
update MemorySegmentES91OSQVectorsScorer
ChrisHegarty Feb 24, 2026
57c8469
Merge remote-tracking branch 'chegar/bbq_vec_ops' into bbq_vec_ops
ChrisHegarty Feb 25, 2026
59208b8
Merge remote-tracking branch 'upstream/main' into bbq_vec_ops
ChrisHegarty Feb 26, 2026
e03e5fd
use a scratch buffer for on-heap
ChrisHegarty Feb 27, 2026
7f67f81
Merge branch 'main' into bbq_vec_ops
ChrisHegarty Mar 2, 2026
7407119
fix
ChrisHegarty Mar 2, 2026
d2ced8b
revert
ChrisHegarty Mar 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions docs/changelog/141718.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
area: Vector Search
issues: []
pr: 141718
summary: Enable zero-copy SIMD vector scoring on searchable snapshots (frozen tier)
type: enhancement
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.core;

import java.io.IOException;
import java.nio.ByteBuffer;

/**
* An optional interface that an IndexInput can implement to provide direct
* access to the underlying data as a {@link ByteBuffer}. This enables
* zero-copy access to memory-mapped data for SIMD-accelerated vector scoring.
*
* <p> The byte buffer is passed to the caller's action and is only valid for
* the duration of that call. All ref-counting and resource releases, if any,
* is handled internally.
*/
public interface DirectAccessInput {

/**
* If a direct byte buffer view is available for the given range, passes it
* to {@code action} and returns {@code true}. Otherwise returns
* {@code false} without invoking the action.
*
* <p>The byte buffer is read-only and valid only for the duration of the
* action. Callers must not retain references to it after the action returns.
*
* @param offset the byte offset within the input
* @param length the number of bytes requested
* @param action the action to perform with the byte buffer
* @return {@code true} if a buffer was available and the action was invoked
*/
boolean withByteBufferSlice(long offset, long length, CheckedConsumer<ByteBuffer, IOException> action) throws IOException;
Comment thread
ChrisHegarty marked this conversation as resolved.
}
4 changes: 3 additions & 1 deletion libs/native/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@
to
org.elasticsearch.server,
org.elasticsearch.blobcache,
org.elasticsearch.searchablesnapshots,
org.elasticsearch.simdvec,
org.elasticsearch.systemd;
org.elasticsearch.systemd,
org.elasticsearch.xpack.stateless;

uses NativeLibraryProvider;

Expand Down
3 changes: 2 additions & 1 deletion libs/simdvec/src/main/java/module-info.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@
* at runtime is selected by the multi-release classloader.
*/
module org.elasticsearch.simdvec {
requires org.elasticsearch.base;
requires org.elasticsearch.logging;
requires org.elasticsearch.nativeaccess;
requires org.apache.lucene.core;
requires org.elasticsearch.logging;

exports org.elasticsearch.simdvec to org.elasticsearch.server;
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,10 @@
import java.util.Objects;

public interface MemorySegmentAccessInputAccess {
Comment thread
ChrisHegarty marked this conversation as resolved.
/** Returns the underlying {@link MemorySegmentAccessInput}, or {@code null} if not available. */
MemorySegmentAccessInput get();

/** Unwraps to the underlying {@link MemorySegmentAccessInput} if available, otherwise returns the input unchanged. */
static IndexInput unwrap(IndexInput input) {
MemorySegmentAccessInput memorySeg = input instanceof MemorySegmentAccessInputAccess msaia ? msaia.get() : null;
return Objects.requireNonNullElse((IndexInput) memorySeg, input);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,14 @@ public static ESVectorizationProvider getInstance() {
/** Create a new {@link ES91OSQVectorsScorer} for the given {@link IndexInput}. */
public abstract ES91OSQVectorsScorer newES91OSQVectorsScorer(IndexInput input, int dimension, int bulkSize) throws IOException;

/**
* Create a new {@link ESNextOSQVectorsScorer} for the given {@link IndexInput}.
* The input should be unwrapped before calling this method. If the input is
* still a {@code FilterIndexInput} that does not implement
* {@code MemorySegmentAccessInput} or {@code DirectAccessInput}, an
* {@link IllegalArgumentException} is thrown. Non-wrapper inputs (e.g.
* {@code ByteBuffersIndexInput}) are accepted and use a heap-copy fallback.
*/
public abstract ESNextOSQVectorsScorer newESNextOSQVectorsScorer(
IndexInput input,
byte queryBits,
Expand All @@ -42,7 +50,10 @@ public abstract ESNextOSQVectorsScorer newESNextOSQVectorsScorer(
int bulkSize
) throws IOException;

/** Create a new {@link ES92Int7VectorsScorer} for the given {@link IndexInput}. */
/**
* Create a new {@link ES92Int7VectorsScorer} for the given {@link IndexInput}.
* See {@link #newESNextOSQVectorsScorer} for input type requirements.
*/
public abstract ES92Int7VectorsScorer newES92Int7VectorsScorer(IndexInput input, int dimension, int bulkSize) throws IOException;

// visible for tests
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
package org.elasticsearch.simdvec.internal;

import org.apache.lucene.store.FilterIndexInput;
import org.apache.lucene.store.IndexInput;
import org.apache.lucene.store.MemorySegmentAccessInput;
import org.elasticsearch.core.CheckedFunction;
import org.elasticsearch.core.DirectAccessInput;

import java.io.IOException;
import java.lang.foreign.MemorySegment;
import java.util.function.IntFunction;

/**
* Utility for obtaining a {@link MemorySegment} view of data in an
* {@link IndexInput} and passing it to a caller-supplied action. The
* segment may come from a {@link MemorySegmentAccessInput} (mmap),
* a direct {@link java.nio.ByteBuffer} view (e.g. blob-cache), or a
* heap copy as a last resort.
*
* <p>All resource management (ref-counting, buffer release) is handled
* internally — callers never see a closeable resource.
*/
public final class IndexInputUtils {

private IndexInputUtils() {}

/**
* Obtains a memory segment for the next {@code length} bytes of the
* index input, passes it to {@code action}, and returns the result.
* The position of the index input is advanced by {@code length}.
*
* <p> This method first tries to obtain a slice via
* {@link MemorySegmentAccessInput#segmentSliceOrNull}. If that
* returns {@code null}, it tries a direct {@link java.nio.ByteBuffer}
* view via {@link DirectAccessInput}. As a last resort it copies the
* data onto the heap using a byte array obtained from
* {@code scratchSupplier}.
*
* <p> The memory segment passed to {@code action} is valid only for
* the duration of the call. Callers must not retain references to it.
*
* @param in the index input positioned at the data to read
* @param length the number of bytes to read
* @param scratchSupplier supplies a byte array of at least the requested
* length, used only on the heap-copy fallback path
* @param action the function to apply to the memory segment
* @return the result of applying {@code action}
*/
public static <R> R withSlice(
IndexInput in,
long length,
IntFunction<byte[]> scratchSupplier,
CheckedFunction<MemorySegment, R, IOException> action
) throws IOException {
checkInputType(in);
if (in instanceof MemorySegmentAccessInput msai) {
Comment thread
ChrisHegarty marked this conversation as resolved.
long offset = in.getFilePointer();
MemorySegment slice = msai.segmentSliceOrNull(offset, length);
if (slice != null) {
in.skipBytes(length);
return action.apply(slice);
}
}
if (in instanceof DirectAccessInput dai) {
long offset = in.getFilePointer();
@SuppressWarnings("unchecked")
R[] result = (R[]) new Object[1];
Comment thread
ChrisHegarty marked this conversation as resolved.
boolean available = dai.withByteBufferSlice(offset, length, bb -> {
in.skipBytes(length);
result[0] = action.apply(MemorySegment.ofBuffer(bb));
});
if (available) {
return result[0];
}
}
return action.apply(copyOnHeap(in, Math.toIntExact(length), scratchSupplier));
}

/**
* Checks that a {@link FilterIndexInput} wrapper also implements
* {@link MemorySegmentAccessInput} or {@link DirectAccessInput},
* so that zero-copy access is preserved through the wrapper chain.
*/
public static void checkInputType(IndexInput in) {
if (in instanceof FilterIndexInput && (in instanceof MemorySegmentAccessInput || in instanceof DirectAccessInput) == false) {
throw new IllegalArgumentException(
"IndexInput is a FilterIndexInput ("
+ in.getClass().getName()
+ ") that does not implement MemorySegmentAccessInput or DirectAccessInput. "
+ "Ensure the wrapper implements DirectAccessInput or is unwrapped before constructing the scorer."
);
}
}

/**
* Reads the given number of bytes from the current position of the
* given IndexInput into a heap-backed memory segment. The returned
* segment is sliced to exactly {@code bytesToRead} bytes, even if
* the underlying array is larger.
*/
private static MemorySegment copyOnHeap(IndexInput in, int bytesToRead, IntFunction<byte[]> scratchSupplier) throws IOException {
byte[] buf = scratchSupplier.apply(bytesToRead);
in.readBytes(buf, 0, bytesToRead);
return MemorySegment.ofArray(buf).asSlice(0, bytesToRead);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,12 @@
import org.apache.lucene.store.IndexInput;

import java.io.IOException;
import java.lang.foreign.MemorySegment;

/** Panamized scorer for 7-bit quantized vectors stored as an {@link IndexInput}. **/
public final class MemorySegmentES92Int7VectorsScorer extends MemorySegmentES92PanamaInt7VectorsScorer {

public MemorySegmentES92Int7VectorsScorer(IndexInput in, int dimensions, int bulkSize, MemorySegment memorySegment) {
super(in, dimensions, bulkSize, memorySegment);
public MemorySegmentES92Int7VectorsScorer(IndexInput in, int dimensions, int bulkSize) {
super(in, dimensions, bulkSize);
}

@Override
Expand Down
Loading