Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
c0a7dd4
Expose agg usage in Feature Usage API
imotov Apr 24, 2020
1cc437c
Refactor to include non value sources aggregations
imotov Apr 24, 2020
9c8510a
Fix reported values source type for parent and children aggs
imotov Apr 27, 2020
f4ab1e7
Merge remote-tracking branch 'elastic/master' into issue-53746-aggs-u…
imotov Apr 27, 2020
6207497
Refactor SearchModule constructor
imotov Apr 27, 2020
b8e7051
Fix subtype in TTest and IPRanges
imotov Apr 27, 2020
530a5dd
Fix more subtypes in aggs that don't register themselves
imotov Apr 27, 2020
39a9bb3
Fix doc tests
imotov Apr 27, 2020
980ca33
Fix docs
imotov Apr 27, 2020
2eae809
Fix ScriptedMetricAggregatorTests
imotov Apr 27, 2020
5c0393a
Merge remote-tracking branch 'elastic/master' into issue-53746-aggs-u…
imotov Apr 28, 2020
4c6b4dd
Fix compilation issues after merge
imotov Apr 28, 2020
4a76f01
Fix merge fallout
imotov Apr 28, 2020
2d0e952
Merge remote-tracking branch 'elastic/master' into issue-53746-aggs-u…
imotov Apr 28, 2020
424884a
This gets stale quickly...
imotov Apr 28, 2020
ca2fb25
Address review comments
imotov Apr 28, 2020
68a2eb5
Fix tests that were missing proper agg registration in the search module
imotov Apr 28, 2020
c9bed39
Fix ScriptedMetricAggregatorTests
imotov Apr 28, 2020
6f0c4fd
Address review comments
imotov Apr 29, 2020
439aada
Merge remote-tracking branch 'elastic/master' into issue-53746-aggs-u…
imotov Apr 29, 2020
b169633
Merge branch 'master' into issue-53746-aggs-usage
elasticmachine Apr 30, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ public static TransformConfig randomTransformConfig() {
randomSourceConfig(),
randomDestConfig(),
randomBoolean() ? null : TimeValue.timeValueMillis(randomIntBetween(1000, 1000000)),
randomBoolean() ? null : randomSyncConfig(),
randomBoolean() ? null : randomSyncConfig(),
PivotConfigTests.randomPivotConfig(),
randomBoolean() ? null : randomAlphaOfLengthBetween(1, 100),
randomBoolean() ? null : Instant.now(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,15 @@

package org.elasticsearch.test.rest;

import org.elasticsearch.client.Request;
import org.elasticsearch.client.Response;
import org.elasticsearch.client.ResponseException;
import org.elasticsearch.client.Request;
import org.elasticsearch.common.Strings;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;

import java.io.IOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;

Expand All @@ -41,14 +45,7 @@ public void testWithRestUsage() throws IOException {
Response beforeResponse = client().performRequest(new Request("GET", path));
Map<String, Object> beforeResponseBodyMap = entityAsMap(beforeResponse);
assertThat(beforeResponseBodyMap, notNullValue());
Map<String, Object> before_nodesMap = (Map<String, Object>) beforeResponseBodyMap.get("_nodes");
assertThat(before_nodesMap, notNullValue());
Integer beforeTotal = (Integer) before_nodesMap.get("total");
Integer beforeSuccessful = (Integer) before_nodesMap.get("successful");
Integer beforeFailed = (Integer) before_nodesMap.get("failed");
assertThat(beforeTotal, greaterThan(0));
assertThat(beforeSuccessful, equalTo(beforeTotal));
assertThat(beforeFailed, equalTo(0));
int beforeSuccessful = assertSuccess(beforeResponseBodyMap);

Map<String, Object> beforeNodesMap = (Map<String, Object>) beforeResponseBodyMap.get("nodes");
assertThat(beforeNodesMap, notNullValue());
Expand Down Expand Up @@ -98,14 +95,7 @@ public void testWithRestUsage() throws IOException {
Response response = client().performRequest(new Request("GET", "_nodes/usage"));
Map<String, Object> responseBodyMap = entityAsMap(response);
assertThat(responseBodyMap, notNullValue());
Map<String, Object> _nodesMap = (Map<String, Object>) responseBodyMap.get("_nodes");
assertThat(_nodesMap, notNullValue());
Integer total = (Integer) _nodesMap.get("total");
Integer successful = (Integer) _nodesMap.get("successful");
Integer failed = (Integer) _nodesMap.get("failed");
assertThat(total, greaterThan(0));
assertThat(successful, equalTo(total));
assertThat(failed, equalTo(0));
int successful = assertSuccess(responseBodyMap);

Map<String, Object> nodesMap = (Map<String, Object>) responseBodyMap.get("nodes");
assertThat(nodesMap, notNullValue());
Expand Down Expand Up @@ -143,4 +133,97 @@ public void testMetricsWithAll() throws IOException {
+ "\"reason\":\"request [_nodes/usage/_all,rest_actions] contains _all and individual metrics [_all,rest_actions]\""));
}

@SuppressWarnings("unchecked")
public void testAggregationUsage() throws IOException {
// First get the current usage figures
String path = randomFrom("_nodes/usage", "_nodes/usage/aggregations", "_nodes/usage/_all");
Response beforeResponse = client().performRequest(new Request("GET", path));
Map<String, Object> beforeResponseBodyMap = entityAsMap(beforeResponse);
assertThat(beforeResponseBodyMap, notNullValue());
int beforeSuccessful = assertSuccess(beforeResponseBodyMap);

Map<String, Object> beforeNodesMap = (Map<String, Object>) beforeResponseBodyMap.get("nodes");
assertThat(beforeNodesMap, notNullValue());
assertThat(beforeNodesMap.size(), equalTo(beforeSuccessful));

Map<String, Map<String, Long>> beforeCombinedAggsUsage = getTotalUsage(beforeNodesMap);
// Do some requests to get some rest usage stats
Request create = new Request("PUT", "/test");
create.setJsonEntity("{\"mappings\": {\"properties\": { \"str\": {\"type\": \"keyword\"}, " +
"\"foo\": {\"type\": \"keyword\"}, \"num\": {\"type\": \"long\"}, \"start\": {\"type\": \"date\"} } }}");
client().performRequest(create);

Request searchRequest = new Request("GET", "/test/_search");
SearchSourceBuilder searchSource = new SearchSourceBuilder()
.aggregation(AggregationBuilders.terms("str_terms").field("str.keyword"))
.aggregation(AggregationBuilders.terms("num_terms").field("num"))
.aggregation(AggregationBuilders.avg("num_avg").field("num"));
searchRequest.setJsonEntity(Strings.toString(searchSource));
searchRequest.setJsonEntity(Strings.toString(searchSource));
client().performRequest(searchRequest);

searchRequest = new Request("GET", "/test/_search");
searchSource = new SearchSourceBuilder()
.aggregation(AggregationBuilders.terms("start").field("start"))
.aggregation(AggregationBuilders.avg("num1").field("num"))
.aggregation(AggregationBuilders.avg("num2").field("num"))
.aggregation(AggregationBuilders.terms("foo").field("foo.keyword"));
String r = Strings.toString(searchSource);
searchRequest.setJsonEntity(Strings.toString(searchSource));
client().performRequest(searchRequest);

Response response = client().performRequest(new Request("GET", "_nodes/usage"));
Map<String, Object> responseBodyMap = entityAsMap(response);
assertThat(responseBodyMap, notNullValue());
int successful = assertSuccess(responseBodyMap);

Map<String, Object> nodesMap = (Map<String, Object>) responseBodyMap.get("nodes");
assertThat(nodesMap, notNullValue());
assertThat(nodesMap.size(), equalTo(successful));

Map<String, Map<String, Long>> afterCombinedAggsUsage = getTotalUsage(nodesMap);

assertDiff(beforeCombinedAggsUsage, afterCombinedAggsUsage, "terms", "numeric", 1L);
assertDiff(beforeCombinedAggsUsage, afterCombinedAggsUsage, "terms", "date", 1L);
assertDiff(beforeCombinedAggsUsage, afterCombinedAggsUsage, "terms", "bytes", 2L);
assertDiff(beforeCombinedAggsUsage, afterCombinedAggsUsage, "avg", "numeric", 3L);
}

private void assertDiff(Map<String, Map<String, Long>> before, Map<String, Map<String, Long>> after, String agg, String vst,
long diff) {
Long valBefore = before.getOrDefault(agg, Collections.emptyMap()).getOrDefault(vst, 0L);
Long valAfter = after.getOrDefault(agg, Collections.emptyMap()).getOrDefault(vst, 0L);
assertThat(agg + "." + vst, valAfter - valBefore, equalTo(diff) );
}

private Map<String, Map<String, Long>> getTotalUsage(Map<String, Object> nodeUsage) {
Map<String, Map<String, Long>> combined = new HashMap<>();
for (Map.Entry<String, Object> nodeEntry : nodeUsage.entrySet()) {
@SuppressWarnings("unchecked")
Map<String, Object> beforeAggsUsage = (Map<String, Object>) ((Map<String, Object>) nodeEntry.getValue()).get("aggregations");
assertThat(beforeAggsUsage, notNullValue());
for (Map.Entry<String, Object> aggEntry : beforeAggsUsage.entrySet()) {
@SuppressWarnings("unchecked") Map<String, Object> aggMap = (Map<String, Object>) aggEntry.getValue();
Map<String, Long> combinedAggMap = combined.computeIfAbsent(aggEntry.getKey(), k -> new HashMap<>());
for (Map.Entry<String, Object> valSourceEntry : aggMap.entrySet()) {
combinedAggMap.put(valSourceEntry.getKey(),
combinedAggMap.getOrDefault(valSourceEntry.getKey(), 0L) + ((Number) valSourceEntry.getValue()).longValue());
}
}
}
return combined;
}

private int assertSuccess(Map<String, Object> responseBodyMap) {
@SuppressWarnings("unchecked") Map<String, Object> nodesResultMap = (Map<String, Object>) responseBodyMap.get("_nodes");
assertThat(nodesResultMap, notNullValue());
Integer total = (Integer) nodesResultMap.get("total");
Integer successful = (Integer) nodesResultMap.get("successful");
Integer failed = (Integer) nodesResultMap.get("failed");
assertThat(total, greaterThan(0));
assertThat(successful, equalTo(total));
assertThat(failed, equalTo(0));
return successful;
}

}
23 changes: 14 additions & 9 deletions docs/reference/cluster/nodes-usage.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,15 @@ of features for each node. All the nodes selective options are explained
==== {api-path-parms-title}

`<metric>`::
(Optional, string) Limits the information returned to the specific metrics.
A comma-separated list of the following options:
(Optional, string) Limits the information returned to the specific metrics.
A comma-separated list of the following options:
+
--
`_all`::
Returns all stats.

`rest_actions`::
Returns the REST actions classname with a count of the number of times
Returns the REST actions classname with a count of the number of times
that action has been called on the node.
--

Expand Down Expand Up @@ -79,11 +79,14 @@ The API returns the following response:
"timestamp": 1492553961812, <1>
"since": 1492553906606, <2>
"rest_actions": {
"org.elasticsearch.rest.action.admin.cluster.RestNodesUsageAction": 1,
"org.elasticsearch.rest.action.admin.indices.RestCreateIndexAction": 1,
"org.elasticsearch.rest.action.document.RestGetAction": 1,
"org.elasticsearch.rest.action.search.RestSearchAction": 19, <3>
"org.elasticsearch.rest.action.admin.cluster.RestNodesInfoAction": 36
"nodes_usage_action": 1,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this name change due to the PR, or were the docs always incorrect?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we ignore this section. So when it was refactored in May 2017 we didn't update the docs.

"create_index_action": 1,
"document_get_action": 1,
"search_action": 19, <3>
"nodes_info_action": 36
},
"aggregations": {
...
}
}
}
Expand All @@ -94,7 +97,9 @@ The API returns the following response:
// TESTRESPONSE[s/1492553961812/$body.$_path/]
// TESTRESPONSE[s/1492553906606/$body.$_path/]
// TESTRESPONSE[s/"rest_actions": [^}]+}/"rest_actions": $body.$_path/]
// TESTRESPONSE[s/"aggregations": [^}]+}/"aggregations": $body.$_path/]
<1> Timestamp for when this nodes usage request was performed.
<2> Timestamp for when the usage information recording was started. This is
equivalent to the time that the node was started.
<3> Search action has been called 19 times for this node.

Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@
import org.apache.lucene.util.NumericUtils;
import org.elasticsearch.index.mapper.MappedFieldType;
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.search.aggregations.AggregatorTestCase;
import org.elasticsearch.search.aggregations.matrix.MatrixAggregationPlugin;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;

public class MatrixStatsAggregatorTests extends AggregatorTestCase {

Expand Down Expand Up @@ -136,4 +139,8 @@ public void testTwoFieldsReduce() throws Exception {
}
}

@Override
protected List<SearchPlugin> getSearchPlugins() {
return Collections.singletonList(new MatrixAggregationPlugin());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,8 @@ public final void testFromXContent() throws Exception {

@Override
protected NamedWriteableRegistry getNamedWriteableRegistry() {
return new NamedWriteableRegistry(new SearchModule(Settings.EMPTY, Collections.emptyList()).getNamedWriteables());
return new NamedWriteableRegistry(new SearchModule(Settings.EMPTY, Collections.emptyList()
).getNamedWriteables());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import java.io.IOException;
import java.util.Map;

import static org.elasticsearch.search.aggregations.support.AggregationUsageService.OTHER_SUBTYPE;

public class ChildrenAggregatorFactory extends ValuesSourceAggregatorFactory {

private final Query parentFilter;
Expand Down Expand Up @@ -84,4 +86,10 @@ protected Aggregator doCreateInternal(ValuesSource rawValuesSource,
return asMultiBucketAggregator(this, searchContext, parent);
}
}

@Override
public String getStatsSubtype() {
// Child Aggregation is registered in non-standard way, so it might return child's values type
return OTHER_SUBTYPE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@
import java.io.IOException;
import java.util.Map;

import static org.elasticsearch.search.aggregations.support.AggregationUsageService.OTHER_SUBTYPE;

public class ParentAggregatorFactory extends ValuesSourceAggregatorFactory {

private final Query parentFilter;
Expand Down Expand Up @@ -85,4 +87,10 @@ protected Aggregator doCreateInternal(ValuesSource rawValuesSource,
return asMultiBucketAggregator(this, searchContext, children);
}
}

@Override
public String getStatsSubtype() {
// Parent Aggregation is registered in non-standard way
return OTHER_SUBTYPE;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.join.mapper.MetaJoinFieldMapper;
import org.elasticsearch.join.mapper.ParentJoinFieldMapper;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilder;
import org.elasticsearch.search.aggregations.AggregatorTestCase;
Expand Down Expand Up @@ -328,4 +330,9 @@ private void testCaseTermsParentTerms(Query query, IndexSearcher indexSearcher,
LongTerms result = search(indexSearcher, query, aggregationBuilder, fieldType, subFieldType);
verify.accept(result);
}

@Override
protected List<SearchPlugin> getSearchPlugins() {
return Collections.singletonList(new ParentJoinPlugin());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,10 @@
import org.elasticsearch.index.mapper.NumberFieldMapper;
import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.join.mapper.MetaJoinFieldMapper;
import org.elasticsearch.join.mapper.ParentJoinFieldMapper;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.search.aggregations.AggregatorTestCase;
import org.elasticsearch.search.aggregations.metrics.InternalMin;
import org.elasticsearch.search.aggregations.metrics.MinAggregationBuilder;
Expand Down Expand Up @@ -187,4 +189,9 @@ private void testCase(Query query, IndexSearcher indexSearcher, Consumer<Interna
InternalChildren result = search(indexSearcher, query, aggregationBuilder, fieldType);
verify.accept(result);
}

@Override
protected List<SearchPlugin> getSearchPlugins() {
return Collections.singletonList(new ParentJoinPlugin());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,8 +64,8 @@ public class RatedRequestsTests extends ESTestCase {
@BeforeClass
public static void init() {
xContentRegistry = new NamedXContentRegistry(
Stream.of(new SearchModule(Settings.EMPTY, emptyList()).getNamedXContents().stream()).flatMap(Function.identity())
.collect(toList()));
Stream.of(new SearchModule(Settings.EMPTY, emptyList()).getNamedXContents().stream())
.flatMap(Function.identity()).collect(toList()));
}

@AfterClass
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,3 +67,9 @@
- match: { hits.total: 1 }
- match: { hits.hits.0._id: q3 }

---
"Verify nodes usage works":
- do:
nodes.usage: {}
- is_true: nodes
- match: { _nodes.failed: 0 }
Loading