Skip to content

Commit 828cbe5

Browse files
committed
Merge remote-tracking branch 'origin/main' into write_coordination_pool
2 parents ad5d0ed + 2ae8ec1 commit 828cbe5

File tree

7 files changed

+135
-37
lines changed

7 files changed

+135
-37
lines changed

docs/changelog/129161.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 129161
2+
summary: Add Telemetry for models without adaptive allocations
3+
area: Machine Learning
4+
type: enhancement
5+
issues: []

muted-tests.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -532,6 +532,12 @@ tests:
532532
- class: org.elasticsearch.xpack.esql.qa.single_node.PushQueriesIT
533533
method: testCaseInsensitiveEquality {KEYWORD}
534534
issue: https://github.com/elastic/elasticsearch/issues/129422
535+
- class: org.elasticsearch.xpack.esql.qa.multi_node.EsqlSpecIT
536+
method: test {knn-function.KnnSearchWithKOption ASYNC}
537+
issue: https://github.com/elastic/elasticsearch/issues/129447
538+
- class: org.elasticsearch.xpack.esql.qa.single_node.GenerativeIT
539+
method: test
540+
issue: https://github.com/elastic/elasticsearch/issues/129453
535541

536542
# Examples:
537543
#

x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/mapper/SemanticTextFieldMapper.java

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -212,7 +212,6 @@ public static class Builder extends FieldMapper.Builder {
212212

213213
private final Parameter<Map<String, String>> meta = Parameter.metaParam();
214214

215-
private MinimalServiceSettings resolvedModelSettings;
216215
private Function<MapperBuilderContext, ObjectMapper> inferenceFieldBuilder;
217216

218217
public static Builder from(SemanticTextFieldMapper mapper) {
@@ -235,14 +234,18 @@ public Builder(
235234
super(name);
236235
this.modelRegistry = modelRegistry;
237236
this.useLegacyFormat = InferenceMetadataFieldsMapper.isEnabled(indexSettings.getSettings()) == false;
238-
this.inferenceFieldBuilder = c -> createInferenceField(
239-
c,
240-
indexSettings.getIndexVersionCreated(),
241-
useLegacyFormat,
242-
resolvedModelSettings,
243-
bitSetProducer,
244-
indexSettings
245-
);
237+
this.inferenceFieldBuilder = c -> {
238+
// Resolve the model setting from the registry if it has not been set yet.
239+
var resolvedModelSettings = modelSettings.get() != null ? modelSettings.get() : getResolvedModelSettings(c, false);
240+
return createInferenceField(
241+
c,
242+
indexSettings.getIndexVersionCreated(),
243+
useLegacyFormat,
244+
resolvedModelSettings,
245+
bitSetProducer,
246+
indexSettings
247+
);
248+
};
246249
}
247250

248251
public Builder setInferenceId(String id) {
@@ -283,26 +286,26 @@ protected void merge(FieldMapper mergeWith, Conflicts conflicts, MapperMergeCont
283286
inferenceFieldBuilder = c -> mergedInferenceField;
284287
}
285288

286-
@Override
287-
public SemanticTextFieldMapper build(MapperBuilderContext context) {
288-
if (useLegacyFormat && copyTo.copyToFields().isEmpty() == false) {
289-
throw new IllegalArgumentException(CONTENT_TYPE + " field [" + leafName() + "] does not support [copy_to]");
290-
}
291-
if (useLegacyFormat && multiFieldsBuilder.hasMultiFields()) {
292-
throw new IllegalArgumentException(CONTENT_TYPE + " field [" + leafName() + "] does not support multi-fields");
289+
/**
290+
* Returns the {@link MinimalServiceSettings} defined in this builder if set;
291+
* otherwise, resolves and returns the settings from the registry.
292+
*/
293+
private MinimalServiceSettings getResolvedModelSettings(MapperBuilderContext context, boolean logWarning) {
294+
if (context.getMergeReason() == MapperService.MergeReason.MAPPING_RECOVERY) {
295+
// the model registry is not available yet
296+
return null;
293297
}
294-
295-
if (context.getMergeReason() != MapperService.MergeReason.MAPPING_RECOVERY && modelSettings.get() == null) {
296-
try {
297-
/*
298-
* If the model is not already set and we are not in a recovery scenario, resolve it using the registry.
299-
* Note: We do not set the model in the mapping at this stage. Instead, the model will be added through
300-
* a mapping update during the first ingestion.
301-
* This approach allows mappings to reference inference endpoints that may not yet exist.
302-
* The only requirement is that the referenced inference endpoint must be available at the time of ingestion.
303-
*/
304-
resolvedModelSettings = modelRegistry.getMinimalServiceSettings(inferenceId.get());
305-
} catch (ResourceNotFoundException exc) {
298+
try {
299+
/*
300+
* If the model is not already set and we are not in a recovery scenario, resolve it using the registry.
301+
* Note: We do not set the model in the mapping at this stage. Instead, the model will be added through
302+
* a mapping update during the first ingestion.
303+
* This approach allows mappings to reference inference endpoints that may not yet exist.
304+
* The only requirement is that the referenced inference endpoint must be available at the time of ingestion.
305+
*/
306+
return modelRegistry.getMinimalServiceSettings(inferenceId.get());
307+
} catch (ResourceNotFoundException exc) {
308+
if (logWarning) {
306309
/* We allow the inference ID to be unregistered at this point.
307310
* This will delay the creation of sub-fields, so indexing and querying for this field won't work
308311
* until the corresponding inference endpoint is created.
@@ -315,8 +318,22 @@ public SemanticTextFieldMapper build(MapperBuilderContext context) {
315318
inferenceId.get()
316319
);
317320
}
318-
} else {
319-
resolvedModelSettings = modelSettings.get();
321+
return null;
322+
}
323+
}
324+
325+
@Override
326+
public SemanticTextFieldMapper build(MapperBuilderContext context) {
327+
if (useLegacyFormat && copyTo.copyToFields().isEmpty() == false) {
328+
throw new IllegalArgumentException(CONTENT_TYPE + " field [" + leafName() + "] does not support [copy_to]");
329+
}
330+
if (useLegacyFormat && multiFieldsBuilder.hasMultiFields()) {
331+
throw new IllegalArgumentException(CONTENT_TYPE + " field [" + leafName() + "] does not support multi-fields");
332+
}
333+
334+
var resolvedModelSettings = modelSettings.get();
335+
if (modelSettings.get() == null) {
336+
resolvedModelSettings = getResolvedModelSettings(context, true);
320337
}
321338

322339
if (modelSettings.get() != null) {

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/MlMetrics.java

Lines changed: 36 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,25 @@ private void registerMasterNodeMetrics(MeterRegistry meterRegistry) {
272272
() -> new LongWithAttributes(trainedModelAllocationCounts.trainedModelsFailedAllocations, isMasterMap)
273273
)
274274
);
275+
metrics.add(
276+
meterRegistry.registerLongGauge(
277+
"es.ml.trained_models.deployment.fixed_allocations.current",
278+
"Sum of current trained model allocations that do not use adaptive allocations (either enabled or disabled)",
279+
"allocations",
280+
() -> new LongWithAttributes(trainedModelAllocationCounts.deploymentsWithFixedAllocations, isMasterMap)
281+
)
282+
);
283+
/*
284+
* AdaptiveAllocationsScalerService tracks the number of allocations with adaptive allocations enabled.
285+
*/
286+
metrics.add(
287+
meterRegistry.registerLongGauge(
288+
"es.ml.trained_models.deployment.disabled_adaptive_allocations.current",
289+
"Sum of current trained model allocations that have adaptive allocations disabled",
290+
"allocations",
291+
() -> new LongWithAttributes(trainedModelAllocationCounts.deploymentsWithDisabledAdaptiveAllocations, isMasterMap)
292+
)
293+
);
275294
}
276295

277296
@Override
@@ -484,17 +503,28 @@ static TrainedModelAllocationCounts findTrainedModelAllocationCounts(TrainedMode
484503
int trainedModelsTargetAllocations = 0;
485504
int trainedModelsCurrentAllocations = 0;
486505
int trainedModelsFailedAllocations = 0;
506+
int deploymentsWithFixedAllocations = 0;
507+
int deploymentsWithDisabledAdaptiveAllocations = 0;
487508

488509
for (TrainedModelAssignment trainedModelAssignment : metadata.allAssignments().values()) {
489510
trainedModelsTargetAllocations += trainedModelAssignment.totalTargetAllocations();
490-
trainedModelsCurrentAllocations += trainedModelAssignment.totalCurrentAllocations();
491511
trainedModelsFailedAllocations += trainedModelAssignment.totalFailedAllocations();
512+
trainedModelsCurrentAllocations += trainedModelAssignment.totalCurrentAllocations();
513+
514+
if (trainedModelAssignment.getAdaptiveAllocationsSettings() == null) {
515+
deploymentsWithFixedAllocations += 1;
516+
} else if ((trainedModelAssignment.getAdaptiveAllocationsSettings().getEnabled() == null)
517+
|| (trainedModelAssignment.getAdaptiveAllocationsSettings().getEnabled() == false)) {
518+
deploymentsWithDisabledAdaptiveAllocations += 1;
519+
}
492520
}
493521

494522
return new TrainedModelAllocationCounts(
495523
trainedModelsTargetAllocations,
496524
trainedModelsCurrentAllocations,
497-
trainedModelsFailedAllocations
525+
trainedModelsFailedAllocations,
526+
deploymentsWithFixedAllocations,
527+
deploymentsWithDisabledAdaptiveAllocations
498528
);
499529
}
500530

@@ -556,8 +586,10 @@ record MlTaskStatusCounts(
556586
record TrainedModelAllocationCounts(
557587
int trainedModelsTargetAllocations,
558588
int trainedModelsCurrentAllocations,
559-
int trainedModelsFailedAllocations
589+
int trainedModelsFailedAllocations,
590+
int deploymentsWithFixedAllocations,
591+
int deploymentsWithDisabledAdaptiveAllocations
560592
) {
561-
static final TrainedModelAllocationCounts EMPTY = new TrainedModelAllocationCounts(0, 0, 0);
593+
static final TrainedModelAllocationCounts EMPTY = new TrainedModelAllocationCounts(0, 0, 0, 0, 0);
562594
}
563595
}

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/adaptiveallocations/AdaptiveAllocationsScaler.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,4 +239,12 @@ public Double getLastMeasuredInferenceTime() {
239239
public Long getLastMeasuredQueueSize() {
240240
return lastMeasuredQueueSize;
241241
}
242+
243+
public Integer getMinNumberOfAllocations() {
244+
return minNumberOfAllocations;
245+
}
246+
247+
public Integer getMaxNumberOfAllocations() {
248+
return maxNumberOfAllocations;
249+
}
242250
}

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/adaptiveallocations/AdaptiveAllocationsScalerService.java

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ void init() {
105105
"es.ml.trained_models.adaptive_allocations.actual_number_of_allocations.current",
106106
"the actual number of allocations",
107107
"",
108-
() -> observeLong(AdaptiveAllocationsScaler::getNumberOfAllocations)
108+
this::observeAllocationCount
109109
)
110110
);
111111
metrics.add(
@@ -179,6 +179,19 @@ Collection<DoubleWithAttributes> observeDouble(Function<AdaptiveAllocationsScale
179179
}
180180
return observations;
181181
}
182+
183+
Collection<LongWithAttributes> observeAllocationCount() {
184+
return scalers.values().stream().map(scaler -> {
185+
var value = scaler.getNumberOfAllocations();
186+
var min = scaler.getMinNumberOfAllocations();
187+
var scalesToZero = min == null || min == 0;
188+
189+
return new LongWithAttributes(
190+
value,
191+
Map.ofEntries(Map.entry("deployment_id", scaler.getDeploymentId()), Map.entry("scales_to_zero", scalesToZero))
192+
);
193+
}).toList();
194+
}
182195
}
183196

184197
/**

x-pack/plugin/ml/src/test/java/org/elasticsearch/xpack/ml/MlMetricsTests.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import org.elasticsearch.xpack.core.ml.datafeed.DatafeedState;
2222
import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsConfig;
2323
import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsState;
24+
import org.elasticsearch.xpack.core.ml.inference.assignment.AdaptiveAllocationsSettings;
2425
import org.elasticsearch.xpack.core.ml.inference.assignment.RoutingInfo;
2526
import org.elasticsearch.xpack.core.ml.inference.assignment.RoutingState;
2627
import org.elasticsearch.xpack.core.ml.inference.assignment.TrainedModelAssignment;
@@ -146,11 +147,27 @@ public void testFindTrainedModelAllocationCounts() {
146147
TrainedModelAssignment.Builder.empty(mock(StartTrainedModelDeploymentAction.TaskParams.class), null)
147148
.addRoutingEntry("node2", new RoutingInfo(0, 1, RoutingState.STARTING, ""))
148149
);
150+
metadataBuilder.addNewAssignment(
151+
"model4",
152+
TrainedModelAssignment.Builder.empty(
153+
mock(StartTrainedModelDeploymentAction.TaskParams.class),
154+
new AdaptiveAllocationsSettings(true, 0, 1)
155+
).addRoutingEntry("node1", new RoutingInfo(0, 0, RoutingState.STARTING, ""))
156+
);
157+
metadataBuilder.addNewAssignment(
158+
"model5",
159+
TrainedModelAssignment.Builder.empty(
160+
mock(StartTrainedModelDeploymentAction.TaskParams.class),
161+
new AdaptiveAllocationsSettings(false, 1, 1)
162+
).addRoutingEntry("node1", new RoutingInfo(1, 1, RoutingState.STARTING, ""))
163+
);
149164

150165
MlMetrics.TrainedModelAllocationCounts counts = MlMetrics.findTrainedModelAllocationCounts(metadataBuilder.build());
151-
assertThat(counts.trainedModelsTargetAllocations(), is(5));
152-
assertThat(counts.trainedModelsCurrentAllocations(), is(3));
166+
assertThat(counts.trainedModelsTargetAllocations(), is(6));
167+
assertThat(counts.trainedModelsCurrentAllocations(), is(4));
153168
assertThat(counts.trainedModelsFailedAllocations(), is(1));
169+
assertThat(counts.deploymentsWithFixedAllocations(), is(3));
170+
assertThat(counts.deploymentsWithDisabledAdaptiveAllocations(), is(1));
154171
}
155172

156173
public void testFindNativeMemoryFree() {

0 commit comments

Comments
 (0)