Переглянути джерело

[HLRC] XPack ML info action (#35777)

Relates to #29827
Vladimir Dolzhenko 6 роки тому
батько
коміт
f0c5f0c099

+ 8 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/MLRequestConverters.java

@@ -53,6 +53,7 @@ import org.elasticsearch.client.ml.GetJobStatsRequest;
 import org.elasticsearch.client.ml.GetModelSnapshotsRequest;
 import org.elasticsearch.client.ml.GetOverallBucketsRequest;
 import org.elasticsearch.client.ml.GetRecordsRequest;
+import org.elasticsearch.client.ml.MlInfoRequest;
 import org.elasticsearch.client.ml.OpenJobRequest;
 import org.elasticsearch.client.ml.PostCalendarEventRequest;
 import org.elasticsearch.client.ml.PostDataRequest;
@@ -663,6 +664,13 @@ final class MLRequestConverters {
         return request;
     }
 
+    static Request mlInfo(MlInfoRequest infoRequest) {
+        String endpoint = new EndpointBuilder()
+            .addPathPartAsIs("_xpack", "ml", "info")
+            .build();
+        return new Request(HttpGet.METHOD_NAME, endpoint);
+    }
+
     static Request findFileStructure(FindFileStructureRequest findFileStructureRequest) {
         String endpoint = new EndpointBuilder()
             .addPathPartAsIs("_xpack")

+ 40 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/MachineLearningClient.java

@@ -65,6 +65,8 @@ import org.elasticsearch.client.ml.GetOverallBucketsRequest;
 import org.elasticsearch.client.ml.GetOverallBucketsResponse;
 import org.elasticsearch.client.ml.GetRecordsRequest;
 import org.elasticsearch.client.ml.GetRecordsResponse;
+import org.elasticsearch.client.ml.MlInfoRequest;
+import org.elasticsearch.client.ml.MlInfoResponse;
 import org.elasticsearch.client.ml.OpenJobRequest;
 import org.elasticsearch.client.ml.OpenJobResponse;
 import org.elasticsearch.client.ml.PostCalendarEventRequest;
@@ -1758,6 +1760,44 @@ public final class MachineLearningClient {
             Collections.emptySet());
     }
 
+    /**
+     * Gets Machine Learning information about default values and limits.
+     * <p>
+     * For additional info
+     * see <a href="http://www.elastic.co/guide/en/elasticsearch/reference/current/get-ml-info.html">Machine Learning info</a>
+     *
+     * @param request The request of Machine Learning info
+     * @param options  Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+     * @return response info about default values and limits
+     * @throws IOException when there is a serialization issue sending the request or receiving the response
+     */
+    public MlInfoResponse getMlInfo(MlInfoRequest request, RequestOptions options) throws IOException {
+        return restHighLevelClient.performRequestAndParseEntity(request,
+            MLRequestConverters::mlInfo,
+            options,
+            MlInfoResponse::fromXContent,
+            Collections.emptySet());
+    }
+
+    /**
+     * Gets Machine Learning information about default values and limits, asynchronously.
+     * <p>
+     * For additional info
+     * see <a href="http://www.elastic.co/guide/en/elasticsearch/reference/current/get-ml-info.html">Machine Learning info</a>
+     *
+     * @param request The request of Machine Learning info
+     * @param options  Additional request options (e.g. headers), use {@link RequestOptions#DEFAULT} if nothing needs to be customized
+     * @param listener Listener to be notified upon request completion
+     */
+    public void getMlInfoAsync(MlInfoRequest request, RequestOptions options, ActionListener<MlInfoResponse> listener) {
+        restHighLevelClient.performRequestAsyncAndParseEntity(request,
+            MLRequestConverters::mlInfo,
+            options,
+            MlInfoResponse::fromXContent,
+            listener,
+            Collections.emptySet());
+    }
+
     /**
      * Finds the structure of a file
      * <p>

+ 25 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/ml/MlInfoRequest.java

@@ -0,0 +1,25 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.ml;
+
+import org.elasticsearch.client.Validatable;
+
+public class MlInfoRequest implements Validatable {
+}

+ 61 - 0
client/rest-high-level/src/main/java/org/elasticsearch/client/ml/MlInfoResponse.java

@@ -0,0 +1,61 @@
+/*
+ * Licensed to Elasticsearch under one or more contributor
+ * license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright
+ * ownership. Elasticsearch licenses this file to you under
+ * the Apache License, Version 2.0 (the "License"); you may
+ * not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.elasticsearch.client.ml;
+
+import org.elasticsearch.client.Validatable;
+import org.elasticsearch.common.xcontent.XContentParser;
+
+import java.io.IOException;
+import java.util.Map;
+import java.util.Objects;
+
+public class MlInfoResponse implements Validatable {
+    private final Map<String, Object> info;
+
+    private MlInfoResponse(Map<String, Object> info) {
+        this.info = info;
+    }
+
+    public Map<String, Object> getInfo() {
+        return info;
+    }
+
+    public static MlInfoResponse fromXContent(XContentParser parser) throws IOException {
+        Map<String, Object> info = parser.map();
+        return new MlInfoResponse(info);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(info);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (obj == null) {
+            return false;
+        }
+        if (getClass() != obj.getClass()) {
+            return false;
+        }
+        MlInfoResponse other = (MlInfoResponse) obj;
+        return Objects.equals(info, other.info);
+    }
+}

+ 11 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/MLRequestConvertersTests.java

@@ -50,6 +50,7 @@ import org.elasticsearch.client.ml.GetJobStatsRequest;
 import org.elasticsearch.client.ml.GetModelSnapshotsRequest;
 import org.elasticsearch.client.ml.GetOverallBucketsRequest;
 import org.elasticsearch.client.ml.GetRecordsRequest;
+import org.elasticsearch.client.ml.MlInfoRequest;
 import org.elasticsearch.client.ml.OpenJobRequest;
 import org.elasticsearch.client.ml.PostCalendarEventRequest;
 import org.elasticsearch.client.ml.PostDataRequest;
@@ -728,6 +729,16 @@ public class MLRequestConvertersTests extends ESTestCase {
         assertNull(request.getEntity());
     }
 
+    public void testMlInfo() {
+        MlInfoRequest infoRequest = new MlInfoRequest();
+
+        Request request = MLRequestConverters.mlInfo(infoRequest);
+
+        assertEquals(HttpGet.METHOD_NAME, request.getMethod());
+        assertThat(request.getEndpoint(), equalTo("/_xpack/ml/info"));
+        assertNull(request.getEntity());
+    }
+
     public void testFindFileStructure() throws Exception {
 
         String sample = randomAlphaOfLength(randomIntBetween(1000, 2000));

+ 13 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/MachineLearningIT.java

@@ -63,6 +63,8 @@ import org.elasticsearch.client.ml.GetJobStatsRequest;
 import org.elasticsearch.client.ml.GetJobStatsResponse;
 import org.elasticsearch.client.ml.GetModelSnapshotsRequest;
 import org.elasticsearch.client.ml.GetModelSnapshotsResponse;
+import org.elasticsearch.client.ml.MlInfoRequest;
+import org.elasticsearch.client.ml.MlInfoResponse;
 import org.elasticsearch.client.ml.OpenJobRequest;
 import org.elasticsearch.client.ml.OpenJobResponse;
 import org.elasticsearch.client.ml.PostCalendarEventRequest;
@@ -137,6 +139,7 @@ import static org.hamcrest.Matchers.containsInAnyOrder;
 import static org.hamcrest.Matchers.greaterThanOrEqualTo;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
 
 public class MachineLearningIT extends ESRestHighLevelClientTestCase {
 
@@ -1282,6 +1285,16 @@ public class MachineLearningIT extends ESRestHighLevelClientTestCase {
         assertThat(exception.status().getStatus(), equalTo(404));
     }
 
+    public void testGetMlInfo() throws Exception {
+        MachineLearningClient machineLearningClient = highLevelClient().machineLearning();
+
+        MlInfoResponse infoResponse = execute(new MlInfoRequest(), machineLearningClient::getMlInfo, machineLearningClient::getMlInfoAsync);
+        Map<String, Object> info = infoResponse.getInfo();
+        assertThat(info, notNullValue());
+        assertTrue(info.containsKey("defaults"));
+        assertTrue(info.containsKey("limits"));
+    }
+
     public static String randomValidJobId() {
         CodepointSetGenerator generator = new CodepointSetGenerator("abcdefghijklmnopqrstuvwxyz0123456789".toCharArray());
         return generator.ofCodePointsLength(random(), 10, 10);

+ 51 - 0
client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/MlClientDocumentationIT.java

@@ -78,6 +78,8 @@ import org.elasticsearch.client.ml.GetOverallBucketsRequest;
 import org.elasticsearch.client.ml.GetOverallBucketsResponse;
 import org.elasticsearch.client.ml.GetRecordsRequest;
 import org.elasticsearch.client.ml.GetRecordsResponse;
+import org.elasticsearch.client.ml.MlInfoRequest;
+import org.elasticsearch.client.ml.MlInfoResponse;
 import org.elasticsearch.client.ml.OpenJobRequest;
 import org.elasticsearch.client.ml.OpenJobResponse;
 import org.elasticsearch.client.ml.PostCalendarEventRequest;
@@ -3003,6 +3005,55 @@ public class MlClientDocumentationIT extends ESRestHighLevelClientTestCase {
         }
     }
 
+    public void testGetMlInfo() throws Exception {
+        RestHighLevelClient client = highLevelClient();
+
+        {
+            // tag::get-ml-info-request
+            MlInfoRequest request = new MlInfoRequest(); // <1>
+            // end::get-ml-info-request
+
+            // tag::get-ml-info-execute
+            MlInfoResponse response = client.machineLearning()
+                .getMlInfo(request, RequestOptions.DEFAULT);
+            // end::get-ml-info-execute
+
+            // tag::get-ml-info-response
+            final Map<String, Object> info = response.getInfo();// <1>
+            // end::get-ml-info-response
+            assertTrue(info.containsKey("defaults"));
+            assertTrue(info.containsKey("limits"));
+        }
+        {
+            MlInfoRequest request = new MlInfoRequest();
+
+            // tag::get-ml-info-execute-listener
+            ActionListener<MlInfoResponse> listener = new ActionListener<MlInfoResponse>() {
+                @Override
+                public void onResponse(MlInfoResponse response) {
+                    // <1>
+                }
+
+                @Override
+                public void onFailure(Exception e) {
+                    // <2>
+                }
+            };
+            // end::get-ml-info-execute-listener
+
+            // Replace the empty listener by a blocking listener in test
+            final CountDownLatch latch = new CountDownLatch(1);
+            listener = new LatchedActionListener<>(listener, latch);
+
+            // tag::get-ml-info-execute-async
+            client.machineLearning()
+                .getMlInfoAsync(request, RequestOptions.DEFAULT, listener); // <1>
+            // end::get-ml-info-execute-async
+
+            assertTrue(latch.await(30L, TimeUnit.SECONDS));
+        }
+    }
+
     private String createFilter(RestHighLevelClient client) throws IOException {
         MlFilter.Builder filterBuilder = MlFilter.builder("my_safe_domains")
             .setDescription("A list of safe domains")

+ 33 - 0
docs/java-rest/high-level/ml/get-info.asciidoc

@@ -0,0 +1,33 @@
+--
+:api: get-ml-info
+:request: MlInfoRequest
+:response: MlInfoResponse
+--
+[id="{upid}-{api}"]
+=== ML Get Info API
+
+The ML Get API provides defaults and limits used internally by {ml}.
+These may be useful to a user interface that needs to interpret machine learning
+configurations where certain fields are missing because the end user was happy with the default value.
+
+It accepts a +{request}+ object and responds with a +{response}+ object.
+
+[id="{upid}-{api}-request"]
+==== Get Info Request
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-request]
+--------------------------------------------------
+<1> Constructing a new request
+
+[id="{upid}-{api}-response"]
+==== ML Get Info Response
+
+["source","java",subs="attributes,callouts,macros"]
+--------------------------------------------------
+include-tagged::{doc-tests-file}[{api}-response]
+--------------------------------------------------
+<1> `info` from the +{response}+ contains ml info details
+
+include::../execution.asciidoc[]

+ 2 - 0
docs/java-rest/high-level/supported-apis.asciidoc

@@ -284,6 +284,7 @@ The Java High Level REST Client supports the following Machine Learning APIs:
 * <<{upid}-delete-model-snapshot>>
 * <<{upid}-revert-model-snapshot>>
 * <<{upid}-update-model-snapshot>>
+* <<{upid}-get-ml-info>>
 * <<{upid}-delete-expired-data>>
 
 include::ml/put-job.asciidoc[]
@@ -326,6 +327,7 @@ include::ml/get-model-snapshots.asciidoc[]
 include::ml/delete-model-snapshot.asciidoc[]
 include::ml/revert-model-snapshot.asciidoc[]
 include::ml/update-model-snapshot.asciidoc[]
+include::ml/get-info.asciidoc[]
 include::ml/delete-expired-data.asciidoc[]
 
 == Migration APIs

+ 22 - 2
x-pack/plugin/core/src/test/java/org/elasticsearch/xpack/core/ml/action/MlInfoActionResponseTests.java

@@ -5,13 +5,33 @@
  */
 package org.elasticsearch.xpack.core.ml.action;
 
-import org.elasticsearch.test.AbstractStreamableTestCase;
+import org.elasticsearch.client.ml.MlInfoResponse;
+import org.elasticsearch.common.xcontent.XContentParser;
+import org.elasticsearch.protocol.AbstractHlrcStreamableXContentTestCase;
 import org.elasticsearch.xpack.core.ml.action.MlInfoAction.Response;
 
+import java.io.IOException;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.function.Predicate;
 
-public class MlInfoActionResponseTests extends AbstractStreamableTestCase<Response> {
+public class MlInfoActionResponseTests extends
+    AbstractHlrcStreamableXContentTestCase<Response, MlInfoResponse> {
+
+    @Override
+    public MlInfoResponse doHlrcParseInstance(XContentParser parser) throws IOException {
+        return MlInfoResponse.fromXContent(parser);
+    }
+
+    @Override
+    public Response convertHlrcToInternal(MlInfoResponse instance) {
+        return new Response(instance.getInfo());
+    }
+
+    @Override
+    protected Predicate<String> getRandomFieldsExcludeFilter() {
+        return p -> true;
+    }
 
     @Override
     protected Response createTestInstance() {