Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
42 commits
Select commit Hold shift + click to select a range
c10fd76
Add HNSW scalar quantized bfloat16 implementation
thecoop Oct 15, 2025
3a6f7fc
Add flat format
thecoop Oct 15, 2025
a85b7ca
Add int8 implementation
thecoop Oct 16, 2025
a638b59
Rename class
thecoop Oct 20, 2025
419032d
Improve tests
thecoop Oct 20, 2025
038db83
Merge branch 'main' into int-hnsw-bfloat16
thecoop Oct 20, 2025
1287a0b
Fix module reference
thecoop Oct 20, 2025
bd55e05
Merge branch 'lucene_snapshot' into int-hnsw-bfloat16
thecoop Oct 23, 2025
7c343c5
Update to use new Lucene104 format
thecoop Oct 23, 2025
4fa4338
Update more tests
thecoop Oct 23, 2025
84f5bf4
Merge branch 'lucene_snapshot' into int-hnsw-bfloat16
thecoop Oct 23, 2025
4815bc2
Class renames
thecoop Oct 23, 2025
94ef4f1
[CI] Auto commit changes from spotless
Oct 23, 2025
61de804
Merge branch 'main' into int-hnsw-bfloat16
thecoop Oct 23, 2025
6720384
Update for ElementType change
thecoop Oct 23, 2025
5c0e171
Merge branch 'lucene_snapshot' into int-hnsw-bfloat16
thecoop Oct 23, 2025
115507a
Revert "Use the reader in Lucene BWC"
thecoop Oct 24, 2025
44ecd39
Remove intermediate class
thecoop Oct 24, 2025
cbba58b
Merge branch 'lucene_snapshot' into int-hnsw-bfloat16
thecoop Oct 24, 2025
f989a30
Merge branch 'lucene_snapshot' into int-hnsw-bfloat16
thecoop Oct 30, 2025
33fe50d
Merge branch 'lucene_snapshot' into int-hnsw-bfloat16
thecoop Oct 31, 2025
f6ee769
Use public constructor
thecoop Oct 31, 2025
3017e33
Mute org.elasticsearch.index.mapper.vectors.DenseVectorFieldMapperTes…
elasticsearchmachine Nov 3, 2025
70507a6
Verify execution info in remote index resolution tests (#137361)
idegtiarenko Nov 3, 2025
0b8a37a
Handle ._original and._ignore_malformed stored fields correctly with …
martijnvg Nov 3, 2025
18e27e2
Merge branch 'lucene_snapshot' into int-hnsw-bfloat16
thecoop Nov 3, 2025
ec0efaf
Support choosing the downsampling method in data stream lifecycle (#1…
gmarouli Nov 3, 2025
60b89a8
Increase timeout for searchable snapshots in ILM tests (#137514)
nielsbauman Nov 3, 2025
ebca69f
Revert "Re-enable some performance updates to ES|QL" (#136781) (#137520)
craigtaverner Nov 3, 2025
846593c
DiskBBQ - Panama support for 4 bits symmetric quantization (#137510)
tteofili Nov 3, 2025
da8b9c6
[ML] Skip dataframes when disabled (#137220)
prwhelan Nov 3, 2025
b54cd8e
Mute org.elasticsearch.xpack.ilm.CCRIndexLifecycleIT testBasicCCRAndI…
elasticsearchmachine Nov 3, 2025
b29af0f
Mute org.elasticsearch.xpack.ilm.CCRIndexLifecycleIT testCcrAndIlmWit…
elasticsearchmachine Nov 3, 2025
4f3ff81
Fix the test dimensions for bit element_type (#137523)
thecoop Nov 3, 2025
1b74ec0
Add competitive sort tests to MapperTestCase (#137437)
romseygeek Nov 3, 2025
9795d0f
We don't need a separate search impl here
thecoop Nov 3, 2025
9473216
Field caps transport changes to return for each original expression w…
piergm Nov 3, 2025
490a2d5
Copy ES819TSDBDocValuesConsumer into tests for version 0 bwc tests (#…
parkertimmins Nov 3, 2025
2047c9a
ESQL: Add support for exponential_histogram in code generation (#137459)
JonasKunz Nov 3, 2025
20ce72d
Unmute FullClusterRestartIT tests (#137254)
ldematte Nov 3, 2025
c925aa0
Clean up `TransportResizeAction` (#137471)
DaveCTurner Nov 3, 2025
e330b42
Merge branch 'main' into int-hnsw-bfloat16
thecoop Nov 3, 2025
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
6 changes: 6 additions & 0 deletions docs/changelog/136632.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pr: 136632
summary: Field caps transport changes to return for each original expression what
it was resolved to
area: Search
type: enhancement
issues: []
5 changes: 5 additions & 0 deletions docs/changelog/137023.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 137023
summary: Support choosing the downsampling method in data stream lifecycle
area: "Data streams"
type: enhancement
issues: []
5 changes: 5 additions & 0 deletions docs/changelog/137220.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 137220
summary: Skip dataframes when disabled
area: Machine Learning
type: bug
issues: []
5 changes: 5 additions & 0 deletions docs/changelog/137442.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
pr: 137442
summary: Handle ._original stored fields with fls
area: "Authorization"
type: bug
issues: []
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import jdk.incubator.vector.LongVector;
import jdk.incubator.vector.ShortVector;
import jdk.incubator.vector.VectorOperators;
import jdk.incubator.vector.VectorSpecies;

import org.apache.lucene.index.VectorSimilarityFunction;
import org.apache.lucene.store.IndexInput;
Expand All @@ -31,23 +30,6 @@
/** Panamized scorer for quantized vectors stored as a {@link MemorySegment}. */
final class MSBitToInt4ESNextOSQVectorsScorer extends MemorySegmentESNextOSQVectorsScorer.MemorySegmentScorer {

private static final int BULK_SIZE = MemorySegmentESNextOSQVectorsScorer.BULK_SIZE;
private static final float FOUR_BIT_SCALE = 1f / ((1 << 4) - 1);

private static final VectorSpecies<Integer> INT_SPECIES_128 = IntVector.SPECIES_128;

private static final VectorSpecies<Long> LONG_SPECIES_128 = LongVector.SPECIES_128;
private static final VectorSpecies<Long> LONG_SPECIES_256 = LongVector.SPECIES_256;

private static final VectorSpecies<Byte> BYTE_SPECIES_128 = ByteVector.SPECIES_128;
private static final VectorSpecies<Byte> BYTE_SPECIES_256 = ByteVector.SPECIES_256;

private static final VectorSpecies<Short> SHORT_SPECIES_128 = ShortVector.SPECIES_128;
private static final VectorSpecies<Short> SHORT_SPECIES_256 = ShortVector.SPECIES_256;

private static final VectorSpecies<Float> FLOAT_SPECIES_128 = FloatVector.SPECIES_128;
private static final VectorSpecies<Float> FLOAT_SPECIES_256 = FloatVector.SPECIES_256;

MSBitToInt4ESNextOSQVectorsScorer(IndexInput in, int dimensions, int dataLength, MemorySegment memorySegment) {
super(in, dimensions, dataLength, memorySegment);
}
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -25,20 +25,6 @@
/** Panamized scorer for quantized vectors stored as a {@link MemorySegment}. */
public final class MemorySegmentESNextOSQVectorsScorer extends ESNextOSQVectorsScorer {

private static final VectorSpecies<Integer> INT_SPECIES_128 = IntVector.SPECIES_128;

private static final VectorSpecies<Long> LONG_SPECIES_128 = LongVector.SPECIES_128;
private static final VectorSpecies<Long> LONG_SPECIES_256 = LongVector.SPECIES_256;

private static final VectorSpecies<Byte> BYTE_SPECIES_128 = ByteVector.SPECIES_128;
private static final VectorSpecies<Byte> BYTE_SPECIES_256 = ByteVector.SPECIES_256;

private static final VectorSpecies<Short> SHORT_SPECIES_128 = ShortVector.SPECIES_128;
private static final VectorSpecies<Short> SHORT_SPECIES_256 = ShortVector.SPECIES_256;

private static final VectorSpecies<Float> FLOAT_SPECIES_128 = FloatVector.SPECIES_128;
private static final VectorSpecies<Float> FLOAT_SPECIES_256 = FloatVector.SPECIES_256;

private final MemorySegment memorySegment;
private final MemorySegmentScorer scorer;

Expand All @@ -54,6 +40,10 @@ public MemorySegmentESNextOSQVectorsScorer(
this.memorySegment = memorySegment;
if (queryBits == 4 && indexBits == 1) {
this.scorer = new MSBitToInt4ESNextOSQVectorsScorer(in, dimensions, dataLength, memorySegment);
} else if (queryBits == 4 && indexBits == 4) {
this.scorer = new MSInt4SymmetricESNextOSQVectorsScorer(in, dimensions, dataLength, memorySegment);
} else if (queryBits == 4 && indexBits == 2) {
throw new IllegalArgumentException("Only symmetric 4-bit query and 1-bit index supported");
} else {
throw new IllegalArgumentException("Only asymmetric 4-bit query and 1-bit index supported");
}
Expand Down Expand Up @@ -112,7 +102,24 @@ public float scoreBulk(
);
}

abstract static sealed class MemorySegmentScorer permits MSBitToInt4ESNextOSQVectorsScorer {
abstract static sealed class MemorySegmentScorer permits MSBitToInt4ESNextOSQVectorsScorer, MSInt4SymmetricESNextOSQVectorsScorer {

static final int BULK_SIZE = MemorySegmentESNextOSQVectorsScorer.BULK_SIZE;
static final float FOUR_BIT_SCALE = 1f / ((1 << 4) - 1);
static final VectorSpecies<Integer> INT_SPECIES_128 = IntVector.SPECIES_128;

static final VectorSpecies<Long> LONG_SPECIES_128 = LongVector.SPECIES_128;
static final VectorSpecies<Long> LONG_SPECIES_256 = LongVector.SPECIES_256;

static final VectorSpecies<Byte> BYTE_SPECIES_128 = ByteVector.SPECIES_128;
static final VectorSpecies<Byte> BYTE_SPECIES_256 = ByteVector.SPECIES_256;

static final VectorSpecies<Short> SHORT_SPECIES_128 = ShortVector.SPECIES_128;
static final VectorSpecies<Short> SHORT_SPECIES_256 = ShortVector.SPECIES_256;

static final VectorSpecies<Float> FLOAT_SPECIES_128 = FloatVector.SPECIES_128;
static final VectorSpecies<Float> FLOAT_SPECIES_256 = FloatVector.SPECIES_256;

protected final MemorySegment memorySegment;
protected final IndexInput in;
protected final int length;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ public ESNextOSQVectorsScorer newESNextOSQVectorsScorer(IndexInput input, byte q
if (PanamaESVectorUtilSupport.HAS_FAST_INTEGER_VECTORS
&& input instanceof MemorySegmentAccessInput msai
&& queryBits == 4
&& indexBits == 1) {
&& (indexBits == 1 || indexBits == 4)) {
MemorySegment ms = msai.segmentSliceOrNull(0, input.length());
if (ms != null) {
return new MemorySegmentESNextOSQVectorsScorer(input, queryBits, indexBits, dimension, dataLength, ms);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
import org.elasticsearch.action.admin.indices.rollover.RolloverRequest;
import org.elasticsearch.action.admin.indices.settings.put.UpdateSettingsRequest;
import org.elasticsearch.action.admin.indices.shrink.ResizeType;
import org.elasticsearch.action.admin.indices.shrink.TransportResizeAction;
import org.elasticsearch.action.admin.indices.template.put.TransportPutComposableIndexTemplateAction;
import org.elasticsearch.action.bulk.BulkRequest;
import org.elasticsearch.action.delete.DeleteRequest;
Expand Down Expand Up @@ -44,6 +45,7 @@
import java.util.List;
import java.util.Map;

import static org.elasticsearch.action.admin.indices.ResizeIndexTestUtils.resizeRequest;
import static org.elasticsearch.test.MapMatcher.assertMap;
import static org.elasticsearch.test.MapMatcher.matchesMap;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
Expand Down Expand Up @@ -267,12 +269,10 @@ public void testIndexingGettingAndSearchingShrunkIndex() throws Exception {
assertThat(updateSettingsResponse.isAcknowledged(), is(true));

String shrunkenTarget = "k8s-shrunken";
var shrinkIndexResponse = client().admin()
.indices()
.prepareResizeIndex(sourceIndex, shrunkenTarget)
.setResizeType(ResizeType.SHRINK)
.setSettings(indexSettings(2, 0).build())
.get();
final var shrinkIndexResponse = client().execute(
TransportResizeAction.TYPE,
resizeRequest(ResizeType.SHRINK, sourceIndex, shrunkenTarget, indexSettings(2, 0))
).actionGet();
assertThat(shrinkIndexResponse.isAcknowledged(), is(true));
assertThat(shrinkIndexResponse.index(), equalTo(shrunkenTarget));

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -524,7 +524,10 @@ Set<Index> maybeExecuteDownsampling(ProjectState projectState, DataStream dataSt
// - has matching downsample rounds
// - is read-only
// So let's wait for an in-progress downsampling operation to succeed or trigger the last matching round
affectedIndices.addAll(waitForInProgressOrTriggerDownsampling(dataStream, backingIndexMeta, downsamplingRounds, project));
var downsamplingMethod = dataStream.getDataLifecycle().downsamplingMethod();
affectedIndices.addAll(
waitForInProgressOrTriggerDownsampling(dataStream, backingIndexMeta, downsamplingRounds, downsamplingMethod, project)
);
}
}

Expand All @@ -541,6 +544,7 @@ private Set<Index> waitForInProgressOrTriggerDownsampling(
DataStream dataStream,
IndexMetadata backingIndex,
List<DataStreamLifecycle.DownsamplingRound> downsamplingRounds,
DownsampleConfig.SamplingMethod downsamplingMethod,
ProjectMetadata project
) {
assert dataStream.getIndices().contains(backingIndex.getIndex())
Expand All @@ -556,7 +560,7 @@ private Set<Index> waitForInProgressOrTriggerDownsampling(
String downsampleIndexName = DownsampleConfig.generateDownsampleIndexName(
DOWNSAMPLED_INDEX_PREFIX,
backingIndex,
round.config().getFixedInterval()
round.fixedInterval()
);
IndexMetadata targetDownsampleIndexMeta = project.index(downsampleIndexName);
boolean targetDownsampleIndexExists = targetDownsampleIndexMeta != null;
Expand All @@ -568,7 +572,8 @@ private Set<Index> waitForInProgressOrTriggerDownsampling(
INDEX_DOWNSAMPLE_STATUS.get(targetDownsampleIndexMeta.getSettings()),
round,
lastRound,
index,
downsamplingMethod,
backingIndex,
targetDownsampleIndexMeta.getIndex()
);
if (downsamplingNotComplete.isEmpty() == false) {
Expand All @@ -580,7 +585,7 @@ private Set<Index> waitForInProgressOrTriggerDownsampling(
// no maintenance needed for previously started downsampling actions and we are on the last matching round so it's time
// to kick off downsampling
affectedIndices.add(index);
downsampleIndexOnce(round, project.id(), indexName, downsampleIndexName);
downsampleIndexOnce(round, downsamplingMethod, project.id(), backingIndex, downsampleIndexName);
}
}
}
Expand All @@ -592,16 +597,30 @@ private Set<Index> waitForInProgressOrTriggerDownsampling(
*/
private void downsampleIndexOnce(
DataStreamLifecycle.DownsamplingRound round,
DownsampleConfig.SamplingMethod requestedDownsamplingMethod,
ProjectId projectId,
String sourceIndex,
IndexMetadata sourceIndexMetadata,
String downsampleIndexName
) {
// When an index is already downsampled with a method, we require all later downsampling rounds to use the same method.
// This is necessary to preserve the relation of the downsampled index to the raw data. For example, if an index is already
// downsampled and downsampled it again to 1 hour; we know that a document represents either the aggregated raw data of an hour
// or the last value of the raw data within this hour. If we mix the methods, we cannot derive any meaning from them.
// Furthermore, data stream lifecycle is configured on the data stream level and not on the individual index level, meaning that
// when a user changes downsampling method, some indices would not be able to be downsampled anymore.
// For this reason, when we encounter an already downsampled index, we use the source downsampling method which might be different
// from the requested one.
var sourceIndexSamplingMethod = DownsampleConfig.SamplingMethod.fromIndexMetadata(sourceIndexMetadata);
String sourceIndex = sourceIndexMetadata.getIndex().getName();
DownsampleAction.Request request = new DownsampleAction.Request(
TimeValue.THIRTY_SECONDS /* TODO should this be longer/configurable? */,
sourceIndex,
downsampleIndexName,
null,
round.config()
new DownsampleConfig(
round.fixedInterval(),
sourceIndexSamplingMethod == null ? requestedDownsamplingMethod : sourceIndexSamplingMethod
)
);
transportActionsDeduplicator.executeOnce(
Tuple.tuple(projectId, request),
Expand Down Expand Up @@ -632,11 +651,12 @@ private Set<Index> evaluateDownsampleStatus(
IndexMetadata.DownsampleTaskStatus downsampleStatus,
DataStreamLifecycle.DownsamplingRound currentRound,
DataStreamLifecycle.DownsamplingRound lastRound,
Index backingIndex,
DownsampleConfig.SamplingMethod downsamplingMethod,
IndexMetadata backingIndex,
Index downsampleIndex
) {
Set<Index> affectedIndices = new HashSet<>();
String indexName = backingIndex.getName();
String indexName = backingIndex.getIndex().getName();
String downsampleIndexName = downsampleIndex.getName();
return switch (downsampleStatus) {
case UNKNOWN -> {
Expand Down Expand Up @@ -683,15 +703,15 @@ private Set<Index> evaluateDownsampleStatus(
// NOTE that the downsample request is made through the deduplicator so it will only really be executed if
// there isn't one already in-flight. This can happen if a previous request timed-out, failed, or there was a
// master failover and data stream lifecycle needed to restart
downsampleIndexOnce(currentRound, projectId, indexName, downsampleIndexName);
affectedIndices.add(backingIndex);
downsampleIndexOnce(currentRound, downsamplingMethod, projectId, backingIndex, downsampleIndexName);
affectedIndices.add(backingIndex.getIndex());
yield affectedIndices;
}
case SUCCESS -> {
if (dataStream.getIndices().contains(downsampleIndex) == false) {
// at this point the source index is part of the data stream and the downsample index is complete but not
// part of the data stream. we need to replace the source index with the downsample index in the data stream
affectedIndices.add(backingIndex);
affectedIndices.add(backingIndex.getIndex());
replaceBackingIndexWithDownsampleIndexOnce(projectId, dataStream, indexName, downsampleIndexName);
}
yield affectedIndices;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import java.io.IOException;
import java.util.List;
import java.util.Set;

import static org.elasticsearch.rest.RestRequest.Method.PUT;
import static org.elasticsearch.rest.RestUtils.getAckTimeout;
Expand All @@ -29,6 +30,9 @@
@ServerlessScope(Scope.PUBLIC)
public class RestPutDataStreamLifecycleAction extends BaseRestHandler {

private static final String SUPPORTS_DOWNSAMPLING_METHOD = "dlm.downsampling_method";
private static final Set<String> CAPABILITIES = Set.of(SUPPORTS_DOWNSAMPLING_METHOD);

@Override
public String getName() {
return "put_data_lifecycles_action";
Expand All @@ -44,13 +48,14 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
try (XContentParser parser = request.contentParser()) {
PutDataStreamLifecycleAction.Request putLifecycleRequest = PutDataStreamLifecycleAction.Request.parseRequest(
parser,
(dataRetention, enabled, downsampling) -> new PutDataStreamLifecycleAction.Request(
(dataRetention, enabled, downsamplingRounds, downsamplingMethod) -> new PutDataStreamLifecycleAction.Request(
getMasterNodeTimeout(request),
getAckTimeout(request),
Strings.splitStringByCommaToArray(request.param("name")),
dataRetention,
enabled,
downsampling
downsamplingRounds,
downsamplingMethod
)
);
putLifecycleRequest.indicesOptions(IndicesOptions.fromRequest(request, putLifecycleRequest.indicesOptions()));
Expand All @@ -61,4 +66,9 @@ protected RestChannelConsumer prepareRequest(RestRequest request, NodeClient cli
);
}
}

@Override
public Set<String> supportedCapabilities() {
return CAPABILITIES;
}
}
Loading