[7.x] [ML] Adding data frame analytics stats to _usage API (#45820) (#45872)

* [ML] Adding data frame analytics stats to _usage API (#45820)

* [ML] Adding data frame analytics stats to _usage API

* making the size of analytics stats 10k

* adjusting backport
This commit is contained in:
Benjamin Trent 2019-08-22 15:15:41 -05:00 committed by GitHub
parent af2df9f221
commit 8e3c54fff7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 21 deletions

View File

@ -13,6 +13,7 @@ import org.elasticsearch.xpack.core.XPackFeatureSet;
import org.elasticsearch.xpack.core.XPackField; import org.elasticsearch.xpack.core.XPackField;
import java.io.IOException; import java.io.IOException;
import java.util.Collections;
import java.util.Map; import java.util.Map;
import java.util.Objects; import java.util.Objects;
@ -27,16 +28,23 @@ public class MachineLearningFeatureSetUsage extends XPackFeatureSet.Usage {
public static final String MODEL_SIZE = "model_size"; public static final String MODEL_SIZE = "model_size";
public static final String CREATED_BY = "created_by"; public static final String CREATED_BY = "created_by";
public static final String NODE_COUNT = "node_count"; public static final String NODE_COUNT = "node_count";
public static final String DATA_FRAME_ANALYTICS_JOBS_FIELD = "data_frame_analytics_jobs";
private final Map<String, Object> jobsUsage; private final Map<String, Object> jobsUsage;
private final Map<String, Object> datafeedsUsage; private final Map<String, Object> datafeedsUsage;
private final Map<String, Object> analyticsUsage;
private final int nodeCount; private final int nodeCount;
public MachineLearningFeatureSetUsage(boolean available, boolean enabled, Map<String, Object> jobsUsage, public MachineLearningFeatureSetUsage(boolean available,
Map<String, Object> datafeedsUsage, int nodeCount) { boolean enabled,
Map<String, Object> jobsUsage,
Map<String, Object> datafeedsUsage,
Map<String, Object> analyticsUsage,
int nodeCount) {
super(XPackField.MACHINE_LEARNING, available, enabled); super(XPackField.MACHINE_LEARNING, available, enabled);
this.jobsUsage = Objects.requireNonNull(jobsUsage); this.jobsUsage = Objects.requireNonNull(jobsUsage);
this.datafeedsUsage = Objects.requireNonNull(datafeedsUsage); this.datafeedsUsage = Objects.requireNonNull(datafeedsUsage);
this.analyticsUsage = Objects.requireNonNull(analyticsUsage);
this.nodeCount = nodeCount; this.nodeCount = nodeCount;
} }
@ -44,6 +52,11 @@ public class MachineLearningFeatureSetUsage extends XPackFeatureSet.Usage {
super(in); super(in);
this.jobsUsage = in.readMap(); this.jobsUsage = in.readMap();
this.datafeedsUsage = in.readMap(); this.datafeedsUsage = in.readMap();
if (in.getVersion().onOrAfter(Version.V_7_4_0)) {
this.analyticsUsage = in.readMap();
} else {
this.analyticsUsage = Collections.emptyMap();
}
if (in.getVersion().onOrAfter(Version.V_6_5_0)) { if (in.getVersion().onOrAfter(Version.V_6_5_0)) {
this.nodeCount = in.readInt(); this.nodeCount = in.readInt();
} else { } else {
@ -56,6 +69,9 @@ public class MachineLearningFeatureSetUsage extends XPackFeatureSet.Usage {
super.writeTo(out); super.writeTo(out);
out.writeMap(jobsUsage); out.writeMap(jobsUsage);
out.writeMap(datafeedsUsage); out.writeMap(datafeedsUsage);
if (out.getVersion().onOrAfter(Version.V_7_4_0)) {
out.writeMap(analyticsUsage);
}
if (out.getVersion().onOrAfter(Version.V_6_5_0)) { if (out.getVersion().onOrAfter(Version.V_6_5_0)) {
out.writeInt(nodeCount); out.writeInt(nodeCount);
} }
@ -64,12 +80,9 @@ public class MachineLearningFeatureSetUsage extends XPackFeatureSet.Usage {
@Override @Override
protected void innerXContent(XContentBuilder builder, Params params) throws IOException { protected void innerXContent(XContentBuilder builder, Params params) throws IOException {
super.innerXContent(builder, params); super.innerXContent(builder, params);
if (jobsUsage != null) {
builder.field(JOBS_FIELD, jobsUsage); builder.field(JOBS_FIELD, jobsUsage);
}
if (datafeedsUsage != null) {
builder.field(DATAFEEDS_FIELD, datafeedsUsage); builder.field(DATAFEEDS_FIELD, datafeedsUsage);
} builder.field(DATA_FRAME_ANALYTICS_JOBS_FIELD, analyticsUsage);
if (nodeCount >= 0) { if (nodeCount >= 0) {
builder.field(NODE_COUNT, nodeCount); builder.field(NODE_COUNT, nodeCount);
} }

View File

@ -24,10 +24,13 @@ import org.elasticsearch.xpack.core.XPackFeatureSet;
import org.elasticsearch.xpack.core.XPackField; import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.XPackPlugin; import org.elasticsearch.xpack.core.XPackPlugin;
import org.elasticsearch.xpack.core.XPackSettings; import org.elasticsearch.xpack.core.XPackSettings;
import org.elasticsearch.xpack.core.action.util.PageParams;
import org.elasticsearch.xpack.core.ml.MachineLearningFeatureSetUsage; import org.elasticsearch.xpack.core.ml.MachineLearningFeatureSetUsage;
import org.elasticsearch.xpack.core.ml.action.GetDataFrameAnalyticsStatsAction;
import org.elasticsearch.xpack.core.ml.action.GetDatafeedsStatsAction; import org.elasticsearch.xpack.core.ml.action.GetDatafeedsStatsAction;
import org.elasticsearch.xpack.core.ml.action.GetJobsStatsAction; import org.elasticsearch.xpack.core.ml.action.GetJobsStatsAction;
import org.elasticsearch.xpack.core.ml.datafeed.DatafeedState; import org.elasticsearch.xpack.core.ml.datafeed.DatafeedState;
import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsState;
import org.elasticsearch.xpack.core.ml.job.config.Job; import org.elasticsearch.xpack.core.ml.job.config.Job;
import org.elasticsearch.xpack.core.ml.job.config.JobState; import org.elasticsearch.xpack.core.ml.job.config.JobState;
import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.ModelSizeStats; import org.elasticsearch.xpack.core.ml.job.process.autodetect.state.ModelSizeStats;
@ -157,6 +160,7 @@ public class MachineLearningFeatureSet implements XPackFeatureSet {
private final boolean enabled; private final boolean enabled;
private Map<String, Object> jobsUsage; private Map<String, Object> jobsUsage;
private Map<String, Object> datafeedsUsage; private Map<String, Object> datafeedsUsage;
private Map<String, Object> analyticsUsage;
private int nodeCount; private int nodeCount;
public Retriever(Client client, JobManagerHolder jobManagerHolder, boolean available, boolean enabled, int nodeCount) { public Retriever(Client client, JobManagerHolder jobManagerHolder, boolean available, boolean enabled, int nodeCount) {
@ -166,6 +170,7 @@ public class MachineLearningFeatureSet implements XPackFeatureSet {
this.enabled = enabled; this.enabled = enabled;
this.jobsUsage = new LinkedHashMap<>(); this.jobsUsage = new LinkedHashMap<>();
this.datafeedsUsage = new LinkedHashMap<>(); this.datafeedsUsage = new LinkedHashMap<>();
this.analyticsUsage = new LinkedHashMap<>();
this.nodeCount = nodeCount; this.nodeCount = nodeCount;
} }
@ -173,19 +178,39 @@ public class MachineLearningFeatureSet implements XPackFeatureSet {
// empty holder means either ML disabled or transport client mode // empty holder means either ML disabled or transport client mode
if (jobManagerHolder.isEmpty()) { if (jobManagerHolder.isEmpty()) {
listener.onResponse( listener.onResponse(
new MachineLearningFeatureSetUsage(available, enabled, Collections.emptyMap(), Collections.emptyMap(), 0)); new MachineLearningFeatureSetUsage(available,
enabled,
Collections.emptyMap(),
Collections.emptyMap(),
Collections.emptyMap(),
0));
return; return;
} }
// Step 3. Extract usage from data frame analytics and return usage response
ActionListener<GetDataFrameAnalyticsStatsAction.Response> dataframeAnalyticsListener = ActionListener.wrap(
response -> {
addDataFrameAnalyticsUsage(response, analyticsUsage);
listener.onResponse(new MachineLearningFeatureSetUsage(available,
enabled,
jobsUsage,
datafeedsUsage,
analyticsUsage,
nodeCount));
},
listener::onFailure
);
// Step 2. Extract usage from datafeeds stats and return usage response // Step 2. Extract usage from datafeeds stats and return usage response
ActionListener<GetDatafeedsStatsAction.Response> datafeedStatsListener = ActionListener<GetDatafeedsStatsAction.Response> datafeedStatsListener =
ActionListener.wrap(response -> { ActionListener.wrap(response -> {
addDatafeedsUsage(response); addDatafeedsUsage(response);
listener.onResponse(new MachineLearningFeatureSetUsage( GetDataFrameAnalyticsStatsAction.Request dataframeAnalyticsStatsRequest =
available, enabled, jobsUsage, datafeedsUsage, nodeCount)); new GetDataFrameAnalyticsStatsAction.Request(GetDatafeedsStatsAction.ALL);
dataframeAnalyticsStatsRequest.setPageParams(new PageParams(0, 10_000));
client.execute(GetDataFrameAnalyticsStatsAction.INSTANCE, dataframeAnalyticsStatsRequest, dataframeAnalyticsListener);
}, },
listener::onFailure listener::onFailure);
);
// Step 1. Extract usage from jobs stats and then request stats for all datafeeds // Step 1. Extract usage from jobs stats and then request stats for all datafeeds
GetJobsStatsAction.Request jobStatsRequest = new GetJobsStatsAction.Request(MetaData.ALL); GetJobsStatsAction.Request jobStatsRequest = new GetJobsStatsAction.Request(MetaData.ALL);
@ -283,17 +308,31 @@ public class MachineLearningFeatureSet implements XPackFeatureSet {
ds -> Counter.newCounter()).addAndGet(1); ds -> Counter.newCounter()).addAndGet(1);
} }
datafeedsUsage.put(MachineLearningFeatureSetUsage.ALL, createDatafeedUsageEntry(response.getResponse().count())); datafeedsUsage.put(MachineLearningFeatureSetUsage.ALL, createCountUsageEntry(response.getResponse().count()));
for (DatafeedState datafeedState : datafeedCountByState.keySet()) { for (DatafeedState datafeedState : datafeedCountByState.keySet()) {
datafeedsUsage.put(datafeedState.name().toLowerCase(Locale.ROOT), datafeedsUsage.put(datafeedState.name().toLowerCase(Locale.ROOT),
createDatafeedUsageEntry(datafeedCountByState.get(datafeedState).get())); createCountUsageEntry(datafeedCountByState.get(datafeedState).get()));
} }
} }
private Map<String, Object> createDatafeedUsageEntry(long count) { private Map<String, Object> createCountUsageEntry(long count) {
Map<String, Object> usage = new HashMap<>(); Map<String, Object> usage = new HashMap<>();
usage.put(MachineLearningFeatureSetUsage.COUNT, count); usage.put(MachineLearningFeatureSetUsage.COUNT, count);
return usage; return usage;
} }
private void addDataFrameAnalyticsUsage(GetDataFrameAnalyticsStatsAction.Response response,
Map<String, Object> dataframeAnalyticsUsage) {
Map<DataFrameAnalyticsState, Counter> dataFrameAnalyticsStateCounterMap = new HashMap<>();
for(GetDataFrameAnalyticsStatsAction.Response.Stats stats : response.getResponse().results()) {
dataFrameAnalyticsStateCounterMap.computeIfAbsent(stats.getState(), ds -> Counter.newCounter()).addAndGet(1);
}
dataframeAnalyticsUsage.put(MachineLearningFeatureSetUsage.ALL, createCountUsageEntry(response.getResponse().count()));
for (DataFrameAnalyticsState state : dataFrameAnalyticsStateCounterMap.keySet()) {
dataframeAnalyticsUsage.put(state.name().toLowerCase(Locale.ROOT),
createCountUsageEntry(dataFrameAnalyticsStateCounterMap.get(state).get()));
}
}
} }
} }

View File

@ -33,10 +33,13 @@ import org.elasticsearch.xpack.core.XPackField;
import org.elasticsearch.xpack.core.action.util.QueryPage; import org.elasticsearch.xpack.core.action.util.QueryPage;
import org.elasticsearch.xpack.core.ml.MachineLearningFeatureSetUsage; import org.elasticsearch.xpack.core.ml.MachineLearningFeatureSetUsage;
import org.elasticsearch.xpack.core.ml.MachineLearningField; import org.elasticsearch.xpack.core.ml.MachineLearningField;
import org.elasticsearch.xpack.core.ml.action.GetDataFrameAnalyticsAction;
import org.elasticsearch.xpack.core.ml.action.GetDataFrameAnalyticsStatsAction;
import org.elasticsearch.xpack.core.ml.action.GetDatafeedsStatsAction; import org.elasticsearch.xpack.core.ml.action.GetDatafeedsStatsAction;
import org.elasticsearch.xpack.core.ml.action.GetJobsStatsAction; import org.elasticsearch.xpack.core.ml.action.GetJobsStatsAction;
import org.elasticsearch.xpack.core.ml.datafeed.DatafeedConfig; import org.elasticsearch.xpack.core.ml.datafeed.DatafeedConfig;
import org.elasticsearch.xpack.core.ml.datafeed.DatafeedState; import org.elasticsearch.xpack.core.ml.datafeed.DatafeedState;
import org.elasticsearch.xpack.core.ml.dataframe.DataFrameAnalyticsState;
import org.elasticsearch.xpack.core.ml.job.config.AnalysisConfig; import org.elasticsearch.xpack.core.ml.job.config.AnalysisConfig;
import org.elasticsearch.xpack.core.ml.job.config.DataDescription; import org.elasticsearch.xpack.core.ml.job.config.DataDescription;
import org.elasticsearch.xpack.core.ml.job.config.Detector; import org.elasticsearch.xpack.core.ml.job.config.Detector;
@ -94,6 +97,7 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
when(clusterService.state()).thenReturn(clusterState); when(clusterService.state()).thenReturn(clusterState);
givenJobs(Collections.emptyList(), Collections.emptyList()); givenJobs(Collections.emptyList(), Collections.emptyList());
givenDatafeeds(Collections.emptyList()); givenDatafeeds(Collections.emptyList());
givenDataFrameAnalytics(Collections.emptyList());
} }
public void testIsRunningOnMlPlatform() { public void testIsRunningOnMlPlatform() {
@ -171,6 +175,11 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
buildDatafeedStats(DatafeedState.STARTED), buildDatafeedStats(DatafeedState.STARTED),
buildDatafeedStats(DatafeedState.STOPPED) buildDatafeedStats(DatafeedState.STOPPED)
)); ));
givenDataFrameAnalytics(Arrays.asList(
buildDataFrameAnalyticsStats(DataFrameAnalyticsState.STOPPED),
buildDataFrameAnalyticsStats(DataFrameAnalyticsState.STOPPED),
buildDataFrameAnalyticsStats(DataFrameAnalyticsState.STARTED)
));
MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(TestEnvironment.newEnvironment(settings.build()), MachineLearningFeatureSet featureSet = new MachineLearningFeatureSet(TestEnvironment.newEnvironment(settings.build()),
clusterService, client, licenseState, jobManagerHolder); clusterService, client, licenseState, jobManagerHolder);
@ -237,6 +246,10 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
assertThat(source.getValue("datafeeds.started.count"), equalTo(2)); assertThat(source.getValue("datafeeds.started.count"), equalTo(2));
assertThat(source.getValue("datafeeds.stopped.count"), equalTo(1)); assertThat(source.getValue("datafeeds.stopped.count"), equalTo(1));
assertThat(source.getValue("data_frame_analytics_jobs._all.count"), equalTo(3));
assertThat(source.getValue("data_frame_analytics_jobs.started.count"), equalTo(1));
assertThat(source.getValue("data_frame_analytics_jobs.stopped.count"), equalTo(2));
assertThat(source.getValue("jobs._all.forecasts.total"), equalTo(11)); assertThat(source.getValue("jobs._all.forecasts.total"), equalTo(11));
assertThat(source.getValue("jobs._all.forecasts.forecasted_jobs"), equalTo(2)); assertThat(source.getValue("jobs._all.forecasts.forecasted_jobs"), equalTo(2));
@ -418,6 +431,19 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
}).when(client).execute(same(GetDatafeedsStatsAction.INSTANCE), any(), any()); }).when(client).execute(same(GetDatafeedsStatsAction.INSTANCE), any(), any());
} }
private void givenDataFrameAnalytics(List<GetDataFrameAnalyticsStatsAction.Response.Stats> dataFrameAnalyticsStats) {
doAnswer(invocationOnMock -> {
@SuppressWarnings("unchecked")
ActionListener<GetDataFrameAnalyticsStatsAction.Response> listener =
(ActionListener<GetDataFrameAnalyticsStatsAction.Response>) invocationOnMock.getArguments()[2];
listener.onResponse(new GetDataFrameAnalyticsStatsAction.Response(
new QueryPage<>(dataFrameAnalyticsStats,
dataFrameAnalyticsStats.size(),
GetDataFrameAnalyticsAction.Response.RESULTS_FIELD)));
return Void.TYPE;
}).when(client).execute(same(GetDataFrameAnalyticsStatsAction.INSTANCE), any(), any());
}
private static Detector buildMinDetector(String fieldName) { private static Detector buildMinDetector(String fieldName) {
Detector.Builder detectorBuilder = new Detector.Builder(); Detector.Builder detectorBuilder = new Detector.Builder();
detectorBuilder.setFunction("min"); detectorBuilder.setFunction("min");
@ -458,6 +484,12 @@ public class MachineLearningFeatureSetTests extends ESTestCase {
return stats; return stats;
} }
private static GetDataFrameAnalyticsStatsAction.Response.Stats buildDataFrameAnalyticsStats(DataFrameAnalyticsState state) {
GetDataFrameAnalyticsStatsAction.Response.Stats stats = mock(GetDataFrameAnalyticsStatsAction.Response.Stats.class);
when(stats.getState()).thenReturn(state);
return stats;
}
private static ForecastStats buildForecastStats(long numberOfForecasts) { private static ForecastStats buildForecastStats(long numberOfForecasts) {
return new ForecastStatsTests().createForecastStats(numberOfForecasts, numberOfForecasts); return new ForecastStatsTests().createForecastStats(numberOfForecasts, numberOfForecasts);
} }