Add a "verbose" option to the data frame analytics stats endpoint (#59589) (#59621)

This commit is contained in:
Przemysław Witek 2020-07-16 09:51:31 +02:00 committed by GitHub
parent 6db481f49e
commit df4fea79cb
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 213 additions and 20 deletions

View File

@ -57,6 +57,10 @@ include::{es-repo-dir}/ml/ml-shared.asciidoc[tag=from]
(Optional, integer) (Optional, integer)
include::{es-repo-dir}/ml/ml-shared.asciidoc[tag=size] include::{es-repo-dir}/ml/ml-shared.asciidoc[tag=size]
`verbose`::
(Optional, boolean)
include::{es-repo-dir}/ml/ml-shared.asciidoc[tag=verbose]
[role="child_attributes"] [role="child_attributes"]
[[ml-get-dfanalytics-stats-response-body]] [[ml-get-dfanalytics-stats-response-body]]
==== {api-response-body-title} ==== {api-response-body-title}

View File

@ -1384,3 +1384,7 @@ tag::use-null[]
Defines whether a new series is used as the null series when there is no value Defines whether a new series is used as the null series when there is no value
for the by or partition fields. The default value is `false`. for the by or partition fields. The default value is `false`.
end::use-null[] end::use-null[]
tag::verbose[]
Defines whether the stats response should be verbose. The default value is `false`.
end::verbose[]

View File

@ -761,6 +761,16 @@ public class Strings {
return toString(toXContent, false, false); return toString(toXContent, false, false);
} }
/**
* Return a {@link String} that is the json representation of the provided {@link ToXContent}.
* Wraps the output into an anonymous object if needed.
* Allows to configure the params.
* The content is not pretty-printed nor human readable.
*/
public static String toString(ToXContent toXContent, ToXContent.Params params) {
return toString(toXContent, params, false, false);
}
/** /**
* Returns a string representation of the builder (only applicable for text based xcontent). * Returns a string representation of the builder (only applicable for text based xcontent).
* @param xContentBuilder builder containing an object to converted to a string * @param xContentBuilder builder containing an object to converted to a string
@ -776,12 +786,22 @@ public class Strings {
* *
*/ */
public static String toString(ToXContent toXContent, boolean pretty, boolean human) { public static String toString(ToXContent toXContent, boolean pretty, boolean human) {
return toString(toXContent, ToXContent.EMPTY_PARAMS, pretty, human);
}
/**
* Return a {@link String} that is the json representation of the provided {@link ToXContent}.
* Wraps the output into an anonymous object if needed.
* Allows to configure the params.
* Allows to control whether the outputted json needs to be pretty printed and human readable.
*/
private static String toString(ToXContent toXContent, ToXContent.Params params, boolean pretty, boolean human) {
try { try {
XContentBuilder builder = createBuilder(pretty, human); XContentBuilder builder = createBuilder(pretty, human);
if (toXContent.isFragment()) { if (toXContent.isFragment()) {
builder.startObject(); builder.startObject();
} }
toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS); toXContent.toXContent(builder, params);
if (toXContent.isFragment()) { if (toXContent.isFragment()) {
builder.endObject(); builder.endObject();
} }

View File

@ -24,6 +24,8 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.ToXContentObject; import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import java.util.Collections;
import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
@ -98,6 +100,16 @@ public class StringsTests extends ESTestCase {
} }
} }
public void testToStringToXContentWithOrWithoutParams() {
ToXContent toXContent = (builder, params) -> builder.field("color_from_param", params.param("color", "red"));
// Rely on the default value of "color" param when params are not passed
assertThat(Strings.toString(toXContent), containsString("\"color_from_param\":\"red\""));
// Pass "color" param explicitly
assertThat(
Strings.toString(toXContent, new ToXContent.MapParams(Collections.singletonMap("color", "blue"))),
containsString("\"color_from_param\":\"blue\""));
}
public void testSplitStringToSet() { public void testSplitStringToSet() {
assertEquals(Strings.tokenizeByCommaToSet(null), Sets.newHashSet()); assertEquals(Strings.tokenizeByCommaToSet(null), Sets.newHashSet());
assertEquals(Strings.tokenizeByCommaToSet(""), Sets.newHashSet()); assertEquals(Strings.tokenizeByCommaToSet(""), Sets.newHashSet());

View File

@ -33,6 +33,7 @@ import org.elasticsearch.xpack.core.ml.dataframe.stats.common.MemoryUsage;
import org.elasticsearch.xpack.core.ml.dataframe.stats.common.DataCounts; import org.elasticsearch.xpack.core.ml.dataframe.stats.common.DataCounts;
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper; import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
import org.elasticsearch.xpack.core.ml.utils.PhaseProgress; import org.elasticsearch.xpack.core.ml.utils.PhaseProgress;
import org.elasticsearch.xpack.core.ml.utils.ToXContentParams;
import java.io.IOException; import java.io.IOException;
import java.util.Arrays; import java.util.Arrays;
@ -141,7 +142,9 @@ public class GetDataFrameAnalyticsStatsAction extends ActionType<GetDataFrameAna
return false; return false;
} }
Request other = (Request) obj; Request other = (Request) obj;
return Objects.equals(id, other.id) && allowNoMatch == other.allowNoMatch && Objects.equals(pageParams, other.pageParams); return Objects.equals(id, other.id)
&& allowNoMatch == other.allowNoMatch
&& Objects.equals(pageParams, other.pageParams);
} }
} }
@ -154,6 +157,9 @@ public class GetDataFrameAnalyticsStatsAction extends ActionType<GetDataFrameAna
public static class Response extends BaseTasksResponse implements ToXContentObject { public static class Response extends BaseTasksResponse implements ToXContentObject {
/** Name of the response's REST param which is used to determine whether this response should be verbose. */
public static final String VERBOSE = "verbose";
public static class Stats implements ToXContentObject, Writeable { public static class Stats implements ToXContentObject, Writeable {
private final String id; private final String id;
@ -295,12 +301,12 @@ public class GetDataFrameAnalyticsStatsAction extends ActionType<GetDataFrameAna
// TODO: Have callers wrap the content with an object as they choose rather than forcing it upon them // TODO: Have callers wrap the content with an object as they choose rather than forcing it upon them
builder.startObject(); builder.startObject();
{ {
toUnwrappedXContent(builder); toUnwrappedXContent(builder, params);
} }
return builder.endObject(); return builder.endObject();
} }
public XContentBuilder toUnwrappedXContent(XContentBuilder builder) throws IOException { private XContentBuilder toUnwrappedXContent(XContentBuilder builder, Params params) throws IOException {
builder.field(DataFrameAnalyticsConfig.ID.getPreferredName(), id); builder.field(DataFrameAnalyticsConfig.ID.getPreferredName(), id);
builder.field("state", state.toString()); builder.field("state", state.toString());
if (failureReason != null) { if (failureReason != null) {
@ -313,7 +319,12 @@ public class GetDataFrameAnalyticsStatsAction extends ActionType<GetDataFrameAna
builder.field("memory_usage", memoryUsage); builder.field("memory_usage", memoryUsage);
if (analysisStats != null) { if (analysisStats != null) {
builder.startObject("analysis_stats"); builder.startObject("analysis_stats");
builder.field(analysisStats.getWriteableName(), analysisStats); builder.field(
analysisStats.getWriteableName(),
analysisStats,
new MapParams(
Collections.singletonMap(
ToXContentParams.FOR_INTERNAL_STORAGE, Boolean.toString(params.paramAsBoolean(VERBOSE, false)))));
builder.endObject(); builder.endObject();
} }
if (node != null) { if (node != null) {

View File

@ -115,7 +115,7 @@ public class ClassificationStats implements AnalysisStats {
builder.field(ITERATION.getPreferredName(), iteration); builder.field(ITERATION.getPreferredName(), iteration);
builder.field(HYPERPARAMETERS.getPreferredName(), hyperparameters); builder.field(HYPERPARAMETERS.getPreferredName(), hyperparameters);
builder.field(TIMING_STATS.getPreferredName(), timingStats); builder.field(TIMING_STATS.getPreferredName(), timingStats);
builder.field(VALIDATION_LOSS.getPreferredName(), validationLoss); builder.field(VALIDATION_LOSS.getPreferredName(), validationLoss, params);
builder.endObject(); builder.endObject();
return builder; return builder;
} }

View File

@ -14,6 +14,7 @@ import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValues; import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValues;
import org.elasticsearch.xpack.core.ml.utils.ToXContentParams;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -62,7 +63,9 @@ public class ValidationLoss implements ToXContentObject, Writeable {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
builder.field(LOSS_TYPE.getPreferredName(), lossType); builder.field(LOSS_TYPE.getPreferredName(), lossType);
builder.field(FOLD_VALUES.getPreferredName(), foldValues); if (params.paramAsBoolean(ToXContentParams.FOR_INTERNAL_STORAGE, false)) {
builder.field(FOLD_VALUES.getPreferredName(), foldValues);
}
builder.endObject(); builder.endObject();
return builder; return builder;
} }

View File

@ -115,7 +115,7 @@ public class RegressionStats implements AnalysisStats {
builder.field(ITERATION.getPreferredName(), iteration); builder.field(ITERATION.getPreferredName(), iteration);
builder.field(HYPERPARAMETERS.getPreferredName(), hyperparameters); builder.field(HYPERPARAMETERS.getPreferredName(), hyperparameters);
builder.field(TIMING_STATS.getPreferredName(), timingStats); builder.field(TIMING_STATS.getPreferredName(), timingStats);
builder.field(VALIDATION_LOSS.getPreferredName(), validationLoss); builder.field(VALIDATION_LOSS.getPreferredName(), validationLoss, params);
builder.endObject(); builder.endObject();
return builder; return builder;
} }

View File

@ -14,6 +14,7 @@ import org.elasticsearch.common.xcontent.ToXContentObject;
import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValues; import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValues;
import org.elasticsearch.xpack.core.ml.utils.ToXContentParams;
import java.io.IOException; import java.io.IOException;
import java.util.List; import java.util.List;
@ -62,7 +63,9 @@ public class ValidationLoss implements ToXContentObject, Writeable {
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException { public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(); builder.startObject();
builder.field(LOSS_TYPE.getPreferredName(), lossType); builder.field(LOSS_TYPE.getPreferredName(), lossType);
builder.field(FOLD_VALUES.getPreferredName(), foldValues); if (params.paramAsBoolean(ToXContentParams.FOR_INTERNAL_STORAGE, false)) {
builder.field(FOLD_VALUES.getPreferredName(), foldValues);
}
builder.endObject(); builder.endObject();
return builder; return builder;
} }

View File

@ -9,6 +9,7 @@ package org.elasticsearch.xpack.core.ml.action;
import org.elasticsearch.test.ESTestCase; import org.elasticsearch.test.ESTestCase;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.notNullValue;
public class GetDataFrameAnalyticsStatsActionRequestTests extends ESTestCase { public class GetDataFrameAnalyticsStatsActionRequestTests extends ESTestCase {
@ -31,4 +32,11 @@ public class GetDataFrameAnalyticsStatsActionRequestTests extends ESTestCase {
assertThat(request.getId(), equalTo("foo")); assertThat(request.getId(), equalTo("foo"));
} }
public void testSetAllowNoMatch() {
GetDataFrameAnalyticsStatsAction.Request request = new GetDataFrameAnalyticsStatsAction.Request();
assertThat(request.isAllowNoMatch(), is(true));
request.setAllowNoMatch(false);
assertThat(request.isAllowNoMatch(), is(false));
}
} }

View File

@ -5,8 +5,10 @@
*/ */
package org.elasticsearch.xpack.core.ml.action; package org.elasticsearch.xpack.core.ml.action;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.NamedWriteableRegistry; import org.elasticsearch.common.io.stream.NamedWriteableRegistry;
import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.test.AbstractWireSerializingTestCase; import org.elasticsearch.test.AbstractWireSerializingTestCase;
import org.elasticsearch.xpack.core.action.util.QueryPage; import org.elasticsearch.xpack.core.action.util.QueryPage;
import org.elasticsearch.xpack.core.ml.action.GetDataFrameAnalyticsStatsAction.Response; import org.elasticsearch.xpack.core.ml.action.GetDataFrameAnalyticsStatsAction.Response;
@ -14,6 +16,7 @@ import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsConfigTests;
import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsState; import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsState;
import org.elasticsearch.xpack.core.ml.dataframe.stats.AnalysisStats; import org.elasticsearch.xpack.core.ml.dataframe.stats.AnalysisStats;
import org.elasticsearch.xpack.core.ml.dataframe.stats.AnalysisStatsNamedWriteablesProvider; import org.elasticsearch.xpack.core.ml.dataframe.stats.AnalysisStatsNamedWriteablesProvider;
import org.elasticsearch.xpack.core.ml.dataframe.stats.classification.ValidationLoss;
import org.elasticsearch.xpack.core.ml.dataframe.stats.common.MemoryUsage; import org.elasticsearch.xpack.core.ml.dataframe.stats.common.MemoryUsage;
import org.elasticsearch.xpack.core.ml.dataframe.stats.common.MemoryUsageTests; import org.elasticsearch.xpack.core.ml.dataframe.stats.common.MemoryUsageTests;
import org.elasticsearch.xpack.core.ml.dataframe.stats.classification.ClassificationStatsTests; import org.elasticsearch.xpack.core.ml.dataframe.stats.classification.ClassificationStatsTests;
@ -26,9 +29,12 @@ import org.elasticsearch.xpack.core.ml.utils.PhaseProgress;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.function.Supplier;
import java.util.stream.IntStream; import java.util.stream.IntStream;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.not;
public class GetDataFrameAnalyticsStatsActionResponseTests extends AbstractWireSerializingTestCase<Response> { public class GetDataFrameAnalyticsStatsActionResponseTests extends AbstractWireSerializingTestCase<Response> {
@ -40,6 +46,17 @@ public class GetDataFrameAnalyticsStatsActionResponseTests extends AbstractWireS
} }
public static Response randomResponse(int listSize) { public static Response randomResponse(int listSize) {
return randomResponse(
listSize,
() -> randomBoolean()
? null
: randomFrom(
ClassificationStatsTests.createRandom(),
OutlierDetectionStatsTests.createRandom(),
RegressionStatsTests.createRandom()));
}
private static Response randomResponse(int listSize, Supplier<AnalysisStats> analysisStatsSupplier) {
List<Response.Stats> analytics = new ArrayList<>(listSize); List<Response.Stats> analytics = new ArrayList<>(listSize);
for (int j = 0; j < listSize; j++) { for (int j = 0; j < listSize; j++) {
String failureReason = randomBoolean() ? null : randomAlphaOfLength(10); String failureReason = randomBoolean() ? null : randomAlphaOfLength(10);
@ -49,12 +66,7 @@ public class GetDataFrameAnalyticsStatsActionResponseTests extends AbstractWireS
new PhaseProgress(randomAlphaOfLength(10), randomIntBetween(0, 100)))); new PhaseProgress(randomAlphaOfLength(10), randomIntBetween(0, 100))));
DataCounts dataCounts = randomBoolean() ? null : DataCountsTests.createRandom(); DataCounts dataCounts = randomBoolean() ? null : DataCountsTests.createRandom();
MemoryUsage memoryUsage = randomBoolean() ? null : MemoryUsageTests.createRandom(); MemoryUsage memoryUsage = randomBoolean() ? null : MemoryUsageTests.createRandom();
AnalysisStats analysisStats = randomBoolean() ? null : AnalysisStats analysisStats = analysisStatsSupplier.get();
randomFrom(
ClassificationStatsTests.createRandom(),
OutlierDetectionStatsTests.createRandom(),
RegressionStatsTests.createRandom()
);
Response.Stats stats = new Response.Stats(DataFrameAnalyticsConfigTests.randomValidId(), Response.Stats stats = new Response.Stats(DataFrameAnalyticsConfigTests.randomValidId(),
randomFrom(DataFrameAnalyticsState.values()), failureReason, progress, dataCounts, memoryUsage, analysisStats, null, randomFrom(DataFrameAnalyticsState.values()), failureReason, progress, dataCounts, memoryUsage, analysisStats, null,
randomAlphaOfLength(20)); randomAlphaOfLength(20));
@ -88,4 +100,24 @@ public class GetDataFrameAnalyticsStatsActionResponseTests extends AbstractWireS
assertThat(stats.getDataCounts(), equalTo(new DataCounts(stats.getId()))); assertThat(stats.getDataCounts(), equalTo(new DataCounts(stats.getId())));
assertThat(stats.getMemoryUsage(), equalTo(new MemoryUsage(stats.getId()))); assertThat(stats.getMemoryUsage(), equalTo(new MemoryUsage(stats.getId())));
} }
public void testVerbose() {
String foldValuesFieldName = ValidationLoss.FOLD_VALUES.getPreferredName();
// Create response for supervised analysis that is certain to contain fold_values field
Response response =
randomResponse(1, () -> randomFrom(ClassificationStatsTests.createRandom(), RegressionStatsTests.createRandom()));
// VERBOSE param defaults to "false", fold values *not* outputted
assertThat(Strings.toString(response), not(containsString(foldValuesFieldName)));
// VERBOSE param explicitly set to "false", fold values *not* outputted
assertThat(
Strings.toString(response, new ToXContent.MapParams(Collections.singletonMap(Response.VERBOSE, "false"))),
not(containsString(foldValuesFieldName)));
// VERBOSE param explicitly set to "true", fold values outputted
assertThat(
Strings.toString(response, new ToXContent.MapParams(Collections.singletonMap(Response.VERBOSE, "true"))),
containsString(foldValuesFieldName));
}
} }

View File

@ -6,13 +6,20 @@
package org.elasticsearch.xpack.core.ml.dataframe.stats.classification; package org.elasticsearch.xpack.core.ml.dataframe.stats.classification;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase;
import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValuesTests; import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValuesTests;
import org.elasticsearch.xpack.core.ml.utils.ToXContentParams;
import org.junit.Before; import org.junit.Before;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
public class ValidationLossTests extends AbstractBWCSerializationTestCase<ValidationLoss> { public class ValidationLossTests extends AbstractBWCSerializationTestCase<ValidationLoss> {
@ -28,6 +35,11 @@ public class ValidationLossTests extends AbstractBWCSerializationTestCase<Valida
return ValidationLoss.fromXContent(parser, lenient); return ValidationLoss.fromXContent(parser, lenient);
} }
@Override
protected ToXContent.Params getToXContentParams() {
return new ToXContent.MapParams(Collections.singletonMap(ToXContentParams.FOR_INTERNAL_STORAGE, "true"));
}
@Override @Override
protected Writeable.Reader<ValidationLoss> instanceReader() { protected Writeable.Reader<ValidationLoss> instanceReader() {
return ValidationLoss::new; return ValidationLoss::new;
@ -41,7 +53,7 @@ public class ValidationLossTests extends AbstractBWCSerializationTestCase<Valida
public static ValidationLoss createRandom() { public static ValidationLoss createRandom() {
return new ValidationLoss( return new ValidationLoss(
randomAlphaOfLength(10), randomAlphaOfLength(10),
randomList(5, () -> FoldValuesTests.createRandom()) randomList(5, FoldValuesTests::createRandom)
); );
} }
@ -49,4 +61,26 @@ public class ValidationLossTests extends AbstractBWCSerializationTestCase<Valida
protected ValidationLoss mutateInstanceForVersion(ValidationLoss instance, Version version) { protected ValidationLoss mutateInstanceForVersion(ValidationLoss instance, Version version) {
return instance; return instance;
} }
public void testValidationLossForStats() {
String foldValuesFieldName = ValidationLoss.FOLD_VALUES.getPreferredName();
ValidationLoss validationLoss = createTestInstance();
// FOR_INTERNAL_STORAGE param defaults to "false", fold values *not* outputted
assertThat(Strings.toString(validationLoss), not(containsString(foldValuesFieldName)));
// FOR_INTERNAL_STORAGE param explicitly set to "false", fold values *not* outputted
assertThat(
Strings.toString(
validationLoss,
new ToXContent.MapParams(Collections.singletonMap(ToXContentParams.FOR_INTERNAL_STORAGE, "false"))),
not(containsString(foldValuesFieldName)));
// FOR_INTERNAL_STORAGE param explicitly set to "true", fold values are outputted
assertThat(
Strings.toString(
validationLoss,
new ToXContent.MapParams(Collections.singletonMap(ToXContentParams.FOR_INTERNAL_STORAGE, "true"))),
containsString(foldValuesFieldName));
}
} }

View File

@ -6,13 +6,20 @@
package org.elasticsearch.xpack.core.ml.dataframe.stats.regression; package org.elasticsearch.xpack.core.ml.dataframe.stats.regression;
import org.elasticsearch.Version; import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentParser; import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase; import org.elasticsearch.xpack.core.ml.AbstractBWCSerializationTestCase;
import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValuesTests; import org.elasticsearch.xpack.core.ml.dataframe.stats.common.FoldValuesTests;
import org.elasticsearch.xpack.core.ml.utils.ToXContentParams;
import org.junit.Before; import org.junit.Before;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.not;
public class ValidationLossTests extends AbstractBWCSerializationTestCase<ValidationLoss> { public class ValidationLossTests extends AbstractBWCSerializationTestCase<ValidationLoss> {
@ -28,6 +35,11 @@ public class ValidationLossTests extends AbstractBWCSerializationTestCase<Valida
return ValidationLoss.fromXContent(parser, lenient); return ValidationLoss.fromXContent(parser, lenient);
} }
@Override
protected ToXContent.Params getToXContentParams() {
return new ToXContent.MapParams(Collections.singletonMap(ToXContentParams.FOR_INTERNAL_STORAGE, "true"));
}
@Override @Override
protected Writeable.Reader<ValidationLoss> instanceReader() { protected Writeable.Reader<ValidationLoss> instanceReader() {
return ValidationLoss::new; return ValidationLoss::new;
@ -41,7 +53,7 @@ public class ValidationLossTests extends AbstractBWCSerializationTestCase<Valida
public static ValidationLoss createRandom() { public static ValidationLoss createRandom() {
return new ValidationLoss( return new ValidationLoss(
randomAlphaOfLength(10), randomAlphaOfLength(10),
randomList(5, () -> FoldValuesTests.createRandom()) randomList(5, FoldValuesTests::createRandom)
); );
} }
@ -49,4 +61,26 @@ public class ValidationLossTests extends AbstractBWCSerializationTestCase<Valida
protected ValidationLoss mutateInstanceForVersion(ValidationLoss instance, Version version) { protected ValidationLoss mutateInstanceForVersion(ValidationLoss instance, Version version) {
return instance; return instance;
} }
public void testValidationLossForStats() {
String foldValuesFieldName = ValidationLoss.FOLD_VALUES.getPreferredName();
ValidationLoss validationLoss = createTestInstance();
// FOR_INTERNAL_STORAGE param defaults to "false", fold values *not* outputted
assertThat(Strings.toString(validationLoss), not(containsString(foldValuesFieldName)));
// FOR_INTERNAL_STORAGE param explicitly set to "false", fold values *not* outputted
assertThat(
Strings.toString(
validationLoss,
new ToXContent.MapParams(Collections.singletonMap(ToXContentParams.FOR_INTERNAL_STORAGE, "false"))),
not(containsString(foldValuesFieldName)));
// FOR_INTERNAL_STORAGE param explicitly set to "true", fold values are outputted
assertThat(
Strings.toString(
validationLoss,
new ToXContent.MapParams(Collections.singletonMap(ToXContentParams.FOR_INTERNAL_STORAGE, "true"))),
containsString(foldValuesFieldName));
}
} }

View File

@ -16,7 +16,9 @@ import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsConfig;
import org.elasticsearch.xpack.ml.MachineLearning; import org.elasticsearch.xpack.ml.MachineLearning;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.List; import java.util.List;
import java.util.Set;
import static java.util.Arrays.asList; import static java.util.Arrays.asList;
import static java.util.Collections.unmodifiableList; import static java.util.Collections.unmodifiableList;
@ -48,9 +50,15 @@ public class RestGetDataFrameAnalyticsStatsAction extends BaseRestHandler {
request.setPageParams(new PageParams(restRequest.paramAsInt(PageParams.FROM.getPreferredName(), PageParams.DEFAULT_FROM), request.setPageParams(new PageParams(restRequest.paramAsInt(PageParams.FROM.getPreferredName(), PageParams.DEFAULT_FROM),
restRequest.paramAsInt(PageParams.SIZE.getPreferredName(), PageParams.DEFAULT_SIZE))); restRequest.paramAsInt(PageParams.SIZE.getPreferredName(), PageParams.DEFAULT_SIZE)));
} }
request.setAllowNoMatch(restRequest.paramAsBoolean(GetDataFrameAnalyticsStatsAction.Request.ALLOW_NO_MATCH.getPreferredName(), request.setAllowNoMatch(
request.isAllowNoMatch())); restRequest.paramAsBoolean(
GetDataFrameAnalyticsStatsAction.Request.ALLOW_NO_MATCH.getPreferredName(), request.isAllowNoMatch()));
return channel -> client.execute(GetDataFrameAnalyticsStatsAction.INSTANCE, request, new RestToXContentListener<>(channel)); return channel -> client.execute(GetDataFrameAnalyticsStatsAction.INSTANCE, request, new RestToXContentListener<>(channel));
} }
@Override
protected Set<String> responseParams() {
return Collections.singleton(GetDataFrameAnalyticsStatsAction.Response.VERBOSE);
}
} }

View File

@ -43,6 +43,12 @@
"type":"int", "type":"int",
"description":"specifies a max number of analytics to get", "description":"specifies a max number of analytics to get",
"default":100 "default":100
},
"verbose":{
"type":"boolean",
"required":false,
"description":"whether the stats response should be verbose",
"default":false
} }
} }
} }

View File

@ -903,7 +903,7 @@ setup:
- match: { data_frame_analytics.0.state: "stopped" } - match: { data_frame_analytics.0.state: "stopped" }
--- ---
"Test get stats on newly created congig": "Test get stats on newly created config":
- do: - do:
ml.put_data_frame_analytics: ml.put_data_frame_analytics:
@ -933,6 +933,20 @@ setup:
- match: { data_frame_analytics.0.memory_usage.peak_usage_bytes: 0 } - match: { data_frame_analytics.0.memory_usage.peak_usage_bytes: 0 }
- match: { data_frame_analytics.0.memory_usage.status: "ok" } - match: { data_frame_analytics.0.memory_usage.status: "ok" }
- do:
ml.get_data_frame_analytics_stats:
id: "foo-1"
verbose: true
- match: { count: 1 }
- length: { data_frame_analytics: 1 }
- match: { data_frame_analytics.0.id: "foo-1" }
- match: { data_frame_analytics.0.state: "stopped" }
- match: { data_frame_analytics.0.data_counts.training_docs_count: 0 }
- match: { data_frame_analytics.0.data_counts.test_docs_count: 0 }
- match: { data_frame_analytics.0.data_counts.skipped_docs_count: 0 }
- match: { data_frame_analytics.0.memory_usage.peak_usage_bytes: 0 }
- match: { data_frame_analytics.0.memory_usage.status: "ok" }
--- ---
"Test delete given stopped config": "Test delete given stopped config":