Remove lenient stats parsing

Today when parsing a stats request, Elasticsearch silently ignores
incorrect metrics. This commit removes lenient parsing of stats requests
for the nodes stats and indices stats APIs.

Relates #21417
This commit is contained in:
Jason Tedor 2016-11-15 12:17:26 -05:00 committed by GitHub
parent 568a7ea5f1
commit f5ac0e5076
10 changed files with 472 additions and 86 deletions

View File

@ -71,49 +71,58 @@ public abstract class BaseRestHandler extends AbstractComponent implements RestH
request.unconsumedParams().stream().filter(p -> !responseParams().contains(p)).collect(Collectors.toCollection(TreeSet::new));
// validate the non-response params
if (unconsumedParams.isEmpty() == false) {
String message = String.format(
Locale.ROOT,
"request [%s] contains unrecognized parameter%s: ",
request.path(),
unconsumedParams.size() > 1 ? "s" : "");
boolean first = true;
for (final String unconsumedParam : unconsumedParams) {
final LevensteinDistance ld = new LevensteinDistance();
final List<Tuple<Float, String>> scoredParams = new ArrayList<>();
final Set<String> candidateParams = new HashSet<>();
candidateParams.addAll(request.consumedParams());
candidateParams.addAll(responseParams());
for (final String candidateParam : candidateParams) {
final float distance = ld.getDistance(unconsumedParam, candidateParam);
if (distance > 0.5f) {
scoredParams.add(new Tuple<>(distance, candidateParam));
}
}
CollectionUtil.timSort(scoredParams, (a, b) -> {
// sort by distance in reverse order, then parameter name for equal distances
int compare = a.v1().compareTo(b.v1());
if (compare != 0) return -compare;
else return a.v2().compareTo(b.v2());
});
if (first == false) {
message += ", ";
}
message += "[" + unconsumedParam + "]";
final List<String> keys = scoredParams.stream().map(Tuple::v2).collect(Collectors.toList());
if (keys.isEmpty() == false) {
message += " -> did you mean " + (keys.size() == 1 ? "[" + keys.get(0) + "]": "any of " + keys.toString()) + "?";
}
first = false;
}
throw new IllegalArgumentException(message);
if (!unconsumedParams.isEmpty()) {
final Set<String> candidateParams = new HashSet<>();
candidateParams.addAll(request.consumedParams());
candidateParams.addAll(responseParams());
throw new IllegalArgumentException(unrecognized(request, unconsumedParams, candidateParams, "parameter"));
}
// execute the action
action.accept(channel);
}
protected final String unrecognized(
final RestRequest request,
final Set<String> invalids,
final Set<String> candidates,
final String detail) {
String message = String.format(
Locale.ROOT,
"request [%s] contains unrecognized %s%s: ",
request.path(),
detail,
invalids.size() > 1 ? "s" : "");
boolean first = true;
for (final String invalid : invalids) {
final LevensteinDistance ld = new LevensteinDistance();
final List<Tuple<Float, String>> scoredParams = new ArrayList<>();
for (final String candidate : candidates) {
final float distance = ld.getDistance(invalid, candidate);
if (distance > 0.5f) {
scoredParams.add(new Tuple<>(distance, candidate));
}
}
CollectionUtil.timSort(scoredParams, (a, b) -> {
// sort by distance in reverse order, then parameter name for equal distances
int compare = a.v1().compareTo(b.v1());
if (compare != 0) return -compare;
else return a.v2().compareTo(b.v2());
});
if (first == false) {
message += ", ";
}
message += "[" + invalid + "]";
final List<String> keys = scoredParams.stream().map(Tuple::v2).collect(Collectors.toList());
if (keys.isEmpty() == false) {
message += " -> did you mean " + (keys.size() == 1 ? "[" + keys.get(0) + "]" : "any of " + keys.toString()) + "?";
}
first = false;
}
return message;
}
/**
* REST requests are handled by preparing a channel consumer that represents the execution of
* the request against a channel.

View File

@ -55,7 +55,7 @@ public class RestNodesInfoAction extends BaseRestHandler {
public RestNodesInfoAction(Settings settings, RestController controller, SettingsFilter settingsFilter) {
super(settings);
controller.registerHandler(GET, "/_nodes", this);
// this endpoint is used for metrics, not for nodeIds, like /_nodes/fs
// this endpoint is used for metrics, not for node IDs, like /_nodes/fs
controller.registerHandler(GET, "/_nodes/{nodeId}", this);
controller.registerHandler(GET, "/_nodes/{nodeId}/{metrics}", this);
// added this endpoint to be aligned with stats

View File

@ -33,7 +33,13 @@ import org.elasticsearch.rest.action.RestActions.NodesResponseRestListener;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;
import static org.elasticsearch.rest.RestRequest.Method.GET;
@ -48,9 +54,38 @@ public class RestNodesStatsAction extends BaseRestHandler {
controller.registerHandler(GET, "/_nodes/stats/{metric}", this);
controller.registerHandler(GET, "/_nodes/{nodeId}/stats/{metric}", this);
controller.registerHandler(GET, "/_nodes/stats/{metric}/{indexMetric}", this);
controller.registerHandler(GET, "/_nodes/stats/{metric}/{index_metric}", this);
controller.registerHandler(GET, "/_nodes/{nodeId}/stats/{metric}/{indexMetric}", this);
controller.registerHandler(GET, "/_nodes/{nodeId}/stats/{metric}/{index_metric}", this);
}
static final Map<String, Consumer<NodesStatsRequest>> METRICS;
static {
final Map<String, Consumer<NodesStatsRequest>> metrics = new HashMap<>();
metrics.put("os", r -> r.os(true));
metrics.put("jvm", r -> r.jvm(true));
metrics.put("thread_pool", r -> r.threadPool(true));
metrics.put("fs", r -> r.fs(true));
metrics.put("transport", r -> r.transport(true));
metrics.put("http", r -> r.http(true));
metrics.put("indices", r -> r.indices(true));
metrics.put("process", r -> r.process(true));
metrics.put("breaker", r -> r.breaker(true));
metrics.put("script", r -> r.script(true));
metrics.put("discovery", r -> r.discovery(true));
metrics.put("ingest", r -> r.ingest(true));
METRICS = Collections.unmodifiableMap(metrics);
}
static final Map<String, Consumer<CommonStatsFlags>> FLAGS;
static {
final Map<String, Consumer<CommonStatsFlags>> flags = new HashMap<>();
for (final Flag flag : CommonStatsFlags.Flag.values()) {
flags.put(flag.getRestName(), f -> f.set(flag, true));
}
FLAGS = Collections.unmodifiableMap(flags);
}
@Override
@ -62,35 +97,72 @@ public class RestNodesStatsAction extends BaseRestHandler {
nodesStatsRequest.timeout(request.param("timeout"));
if (metrics.size() == 1 && metrics.contains("_all")) {
if (request.hasParam("index_metric")) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"request [%s] contains index metrics [%s] but all stats requested",
request.path(),
request.param("index_metric")));
}
nodesStatsRequest.all();
nodesStatsRequest.indices(CommonStatsFlags.ALL);
} else if (metrics.contains("_all")) {
throw new IllegalArgumentException(
String.format(Locale.ROOT,
"request [%s] contains _all and individual metrics [%s]",
request.path(),
request.param("metric")));
} else {
nodesStatsRequest.clear();
nodesStatsRequest.os(metrics.contains("os"));
nodesStatsRequest.jvm(metrics.contains("jvm"));
nodesStatsRequest.threadPool(metrics.contains("thread_pool"));
nodesStatsRequest.fs(metrics.contains("fs"));
nodesStatsRequest.transport(metrics.contains("transport"));
nodesStatsRequest.http(metrics.contains("http"));
nodesStatsRequest.indices(metrics.contains("indices"));
nodesStatsRequest.process(metrics.contains("process"));
nodesStatsRequest.breaker(metrics.contains("breaker"));
nodesStatsRequest.script(metrics.contains("script"));
nodesStatsRequest.discovery(metrics.contains("discovery"));
nodesStatsRequest.ingest(metrics.contains("ingest"));
// use a sorted set so the unrecognized parameters appear in a reliable sorted order
final Set<String> invalidMetrics = new TreeSet<>();
for (final String metric : metrics) {
final Consumer<NodesStatsRequest> handler = METRICS.get(metric);
if (handler != null) {
handler.accept(nodesStatsRequest);
} else {
invalidMetrics.add(metric);
}
}
if (!invalidMetrics.isEmpty()) {
throw new IllegalArgumentException(unrecognized(request, invalidMetrics, METRICS.keySet(), "metric"));
}
// check for index specific metrics
if (metrics.contains("indices")) {
Set<String> indexMetrics = Strings.splitStringByCommaToSet(request.param("indexMetric", "_all"));
Set<String> indexMetrics = Strings.splitStringByCommaToSet(request.param("index_metric", "_all"));
if (indexMetrics.size() == 1 && indexMetrics.contains("_all")) {
nodesStatsRequest.indices(CommonStatsFlags.ALL);
} else {
CommonStatsFlags flags = new CommonStatsFlags();
for (Flag flag : CommonStatsFlags.Flag.values()) {
flags.set(flag, indexMetrics.contains(flag.getRestName()));
flags.clear();
// use a sorted set so the unrecognized parameters appear in a reliable sorted order
final Set<String> invalidIndexMetrics = new TreeSet<>();
for (final String indexMetric : indexMetrics) {
final Consumer<CommonStatsFlags> handler = FLAGS.get(indexMetric);
if (handler != null) {
handler.accept(flags);
} else {
invalidIndexMetrics.add(indexMetric);
}
}
if (!invalidIndexMetrics.isEmpty()) {
throw new IllegalArgumentException(unrecognized(request, invalidIndexMetrics, FLAGS.keySet(), "index metric"));
}
nodesStatsRequest.indices(flags);
}
} else if (request.hasParam("index_metric")) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"request [%s] contains index metrics [%s] but indices stats not requested",
request.path(),
request.param("index_metric")));
}
}

View File

@ -36,7 +36,13 @@ import org.elasticsearch.rest.action.RestBuilderListener;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.OK;
@ -49,11 +55,34 @@ public class RestIndicesStatsAction extends BaseRestHandler {
super(settings);
controller.registerHandler(GET, "/_stats", this);
controller.registerHandler(GET, "/_stats/{metric}", this);
controller.registerHandler(GET, "/_stats/{metric}/{indexMetric}", this);
controller.registerHandler(GET, "/{index}/_stats", this);
controller.registerHandler(GET, "/{index}/_stats/{metric}", this);
}
static Map<String, Consumer<IndicesStatsRequest>> METRICS;
static {
final Map<String, Consumer<IndicesStatsRequest>> metrics = new HashMap<>();
metrics.put("docs", r -> r.docs(true));
metrics.put("store", r -> r.store(true));
metrics.put("indexing", r -> r.indexing(true));
metrics.put("search", r -> r.search(true));
metrics.put("suggest", r -> r.search(true));
metrics.put("get", r -> r.get(true));
metrics.put("merge", r -> r.merge(true));
metrics.put("refresh", r -> r.refresh(true));
metrics.put("flush", r -> r.flush(true));
metrics.put("warmer", r -> r.warmer(true));
metrics.put("query_cache", r -> r.queryCache(true));
metrics.put("segments", r -> r.segments(true));
metrics.put("fielddata", r -> r.fieldData(true));
metrics.put("completion", r -> r.completion(true));
metrics.put("request_cache", r -> r.requestCache(true));
metrics.put("recovery", r -> r.recovery(true));
metrics.put("translog", r -> r.translog(true));
METRICS = Collections.unmodifiableMap(metrics);
}
@Override
public RestChannelConsumer prepareRequest(final RestRequest request, final NodeClient client) throws IOException {
IndicesStatsRequest indicesStatsRequest = new IndicesStatsRequest();
@ -65,24 +94,28 @@ public class RestIndicesStatsAction extends BaseRestHandler {
// short cut, if no metrics have been specified in URI
if (metrics.size() == 1 && metrics.contains("_all")) {
indicesStatsRequest.all();
} else if (metrics.contains("_all")) {
throw new IllegalArgumentException(
String.format(Locale.ROOT,
"request [%s] contains _all and individual metrics [%s]",
request.path(),
request.param("metric")));
} else {
indicesStatsRequest.clear();
indicesStatsRequest.docs(metrics.contains("docs"));
indicesStatsRequest.store(metrics.contains("store"));
indicesStatsRequest.indexing(metrics.contains("indexing"));
indicesStatsRequest.search(metrics.contains("search") || metrics.contains("suggest"));
indicesStatsRequest.get(metrics.contains("get"));
indicesStatsRequest.merge(metrics.contains("merge"));
indicesStatsRequest.refresh(metrics.contains("refresh"));
indicesStatsRequest.flush(metrics.contains("flush"));
indicesStatsRequest.warmer(metrics.contains("warmer"));
indicesStatsRequest.queryCache(metrics.contains("query_cache"));
indicesStatsRequest.segments(metrics.contains("segments"));
indicesStatsRequest.fieldData(metrics.contains("fielddata"));
indicesStatsRequest.completion(metrics.contains("completion"));
indicesStatsRequest.requestCache(metrics.contains("request_cache"));
indicesStatsRequest.recovery(metrics.contains("recovery"));
indicesStatsRequest.translog(metrics.contains("translog"));
// use a sorted set so the unrecognized parameters appear in a reliable sorted order
final Set<String> invalidMetrics = new TreeSet<>();
for (final String metric : metrics) {
final Consumer<IndicesStatsRequest> consumer = METRICS.get(metric);
if (consumer != null) {
consumer.accept(indicesStatsRequest);
} else {
invalidMetrics.add(metric);
}
}
if (!invalidMetrics.isEmpty()) {
throw new IllegalArgumentException(unrecognized(request, invalidMetrics, METRICS.keySet(), "metric"));
}
}
if (request.hasParam("groups")) {

View File

@ -0,0 +1,144 @@
/*
* 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.rest.action.admin.cluster;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.rest.FakeRestRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Set;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.object.HasToString.hasToString;
import static org.mockito.Mockito.mock;
public class RestNodesStatsActionTests extends ESTestCase {
private RestNodesStatsAction action;
@Override
public void setUp() throws Exception {
super.setUp();
action = new RestNodesStatsAction(Settings.EMPTY, new RestController(Settings.EMPTY, Collections.emptySet()));
}
public void testUnrecognizedMetric() throws IOException {
final HashMap<String, String> params = new HashMap<>();
final String metric = randomAsciiOfLength(64);
params.put("metric", metric);
final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(e, hasToString(containsString("request [/_nodes/stats] contains unrecognized metric: [" + metric + "]")));
}
public void testUnrecognizedMetricDidYouMean() throws IOException {
final HashMap<String, String> params = new HashMap<>();
params.put("metric", "os,transprot,unrecognized");
final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(
e,
hasToString(
containsString(
"request [/_nodes/stats] contains unrecognized metrics: [transprot] -> did you mean [transport]?, [unrecognized]")));
}
public void testAllRequestWithOtherMetrics() throws IOException {
final HashMap<String, String> params = new HashMap<>();
final String metric = randomSubsetOf(1, RestNodesStatsAction.METRICS.keySet()).get(0);
params.put("metric", "_all," + metric);
final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(e, hasToString(containsString("request [/_nodes/stats] contains _all and individual metrics [_all," + metric + "]")));
}
public void testUnrecognizedIndexMetric() {
final HashMap<String, String> params = new HashMap<>();
params.put("metric", "indices");
final String indexMetric = randomAsciiOfLength(64);
params.put("index_metric", indexMetric);
final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(e, hasToString(containsString("request [/_nodes/stats] contains unrecognized index metric: [" + indexMetric + "]")));
}
public void testUnrecognizedIndexMetricDidYouMean() {
final HashMap<String, String> params = new HashMap<>();
params.put("metric", "indices");
params.put("index_metric", "indexing,stroe,unrecognized");
final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(
e,
hasToString(
containsString(
"request [/_nodes/stats] contains unrecognized index metrics: [stroe] -> did you mean [store]?, [unrecognized]")));
}
public void testIndexMetricsRequestWithoutIndicesMetric() throws IOException {
final HashMap<String, String> params = new HashMap<>();
final Set<String> metrics = new HashSet<>(RestNodesStatsAction.METRICS.keySet());
metrics.remove("indices");
params.put("metric", randomSubsetOf(1, metrics).get(0));
final String indexMetric = randomSubsetOf(1, RestNodesStatsAction.FLAGS.keySet()).get(0);
params.put("index_metric", indexMetric);
final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(
e,
hasToString(
containsString("request [/_nodes/stats] contains index metrics [" + indexMetric + "] but indices stats not requested")));
}
public void testIndexMetricsRequestOnAllRequest() throws IOException {
final HashMap<String, String> params = new HashMap<>();
params.put("metric", "_all");
final String indexMetric = randomSubsetOf(1, RestNodesStatsAction.FLAGS.keySet()).get(0);
params.put("index_metric", indexMetric);
final RestRequest request = new FakeRestRequest.Builder().withPath("/_nodes/stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(
e,
hasToString(
containsString("request [/_nodes/stats] contains index metrics [" + indexMetric + "] but all stats requested")));
}
}

View File

@ -0,0 +1,83 @@
/*
* 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.rest.action.admin.indices;
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.rest.FakeRestRequest;
import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.object.HasToString.hasToString;
import static org.mockito.Mockito.mock;
public class RestIndicesStatsActionTests extends ESTestCase {
private RestIndicesStatsAction action;
@Override
public void setUp() throws Exception {
super.setUp();
action = new RestIndicesStatsAction(Settings.EMPTY, new RestController(Settings.EMPTY, Collections.emptySet()));
}
public void testUnrecognizedMetric() throws IOException {
final HashMap<String, String> params = new HashMap<>();
final String metric = randomAsciiOfLength(64);
params.put("metric", metric);
final RestRequest request = new FakeRestRequest.Builder().withPath("/_stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(e, hasToString(containsString("request [/_stats] contains unrecognized metric: [" + metric + "]")));
}
public void testUnrecognizedMetricDidYouMean() throws IOException {
final HashMap<String, String> params = new HashMap<>();
params.put("metric", "request_cache,fieldata,unrecognized");
final RestRequest request = new FakeRestRequest.Builder().withPath("/_stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(
e,
hasToString(
containsString(
"request [/_stats] contains unrecognized metrics: [fieldata] -> did you mean [fielddata]?, [unrecognized]")));
}
public void testAllRequestWithOtherMetrics() throws IOException {
final HashMap<String, String> params = new HashMap<>();
final String metric = randomSubsetOf(1, RestIndicesStatsAction.METRICS.keySet()).get(0);
params.put("metric", "_all," + metric);
final RestRequest request = new FakeRestRequest.Builder().withPath("/_stats").withParams(params).build();
final IllegalArgumentException e = expectThrows(
IllegalArgumentException.class,
() -> action.prepareRequest(request, mock(NodeClient.class)));
assertThat(e, hasToString(containsString("request [/_stats] contains _all and individual metrics [_all," + metric + "]")));
}
}

View File

@ -65,12 +65,11 @@ of `indices`, `os`, `process`, `jvm`, `transport`, `http`,
[source,js]
--------------------------------------------------
# return indices and os
curl -XGET 'http://localhost:9200/_nodes/stats/os'
# return just indices
curl -XGET 'http://localhost:9200/_nodes/stats/indices'
# return just os and process
curl -XGET 'http://localhost:9200/_nodes/stats/os,process'
# specific type endpoint
curl -XGET 'http://localhost:9200/_nodes/stats/process'
# return just process for node with IP address 10.0.0.1
curl -XGET 'http://localhost:9200/_nodes/10.0.0.1/stats/process'
--------------------------------------------------
@ -280,27 +279,45 @@ the current running process:
`process.mem.total_virtual_in_bytes`::
Size in bytes of virtual memory that is guaranteed to be available to the running process
[float]
[[field-data]]
=== Field data statistics
[[indices-stats]]
=== Indices statistics
You can get information about field data memory usage on node
level or on index level.
You can get information about indices stats on node level or on index level.
[source,js]
--------------------------------------------------
# Node Stats
curl -XGET 'http://localhost:9200/_nodes/stats/indices/?fields=field1,field2&pretty'
# Node level
curl -XGET 'http://localhost:9200/_nodes/stats/indices/fielddata?fields=field1,field2&pretty'
# Indices Stat
# Index level
curl -XGET 'http://localhost:9200/_stats/fielddata/?fields=field1,field2&pretty'
# You can use wildcards for field names
curl -XGET 'http://localhost:9200/_nodes/stats/indices/fielddata?fields=field*&pretty'
curl -XGET 'http://localhost:9200/_stats/fielddata/?fields=field*&pretty'
curl -XGET 'http://localhost:9200/_nodes/stats/indices/?fields=field*&pretty'
--------------------------------------------------
Supported metrics are:
* `completion`
* `docs`
* `fielddata`
* `flush`
* `get`
* `indexing`
* `merge`
* `query_cache`
* `recovery`
* `refresh`
* `request_cache`
* `search`
* `segments`
* `store`
* `suggest`
* `translog`
* `warmer`
[float]
[[search-groups]]
=== Search groups

View File

@ -74,7 +74,7 @@ the <<indices-stats,indices stats>> API:
[source,sh]
--------------------------------------------------
GET twitter/_stats/commit?level=shards
GET twitter/_stats?level=shards
--------------------------------------------------
// CONSOLE
// TEST[s/^/PUT twitter\n/]

View File

@ -100,3 +100,17 @@ setup:
- is_false: indices.test1
- is_true: indices.test2
---
"Indices stats unrecognized parameter":
- skip:
version: " - 5.99.99"
reason: awaits strict stats handling to be backported to 5.x
- do:
indices.stats:
metric: [ fieldata ]
ignore: 400
- match: { status: 400 }
- match: { error.type: illegal_argument_exception }
- match: { error.reason: "request [/_stats/fieldata] contains unrecognized metric: [fieldata] -> did you mean [fielddata]?" }

View File

@ -20,3 +20,17 @@
level: "indices"
- is_true: nodes.$master.indices.indices
---
"Nodes stats unrecognized parameter":
- skip:
version: " - 5.99.99"
reason: awaits strict stats handling to be backported to 5.x
- do:
nodes.stats:
metric: [ transprot ]
ignore: 400
- match: { status: 400 }
- match: { error.type: illegal_argument_exception }
- match: { error.reason: "request [/_nodes/stats/transprot] contains unrecognized metric: [transprot] -> did you mean [transport]?" }