parent
8817281a70
commit
d07c5a5c32
|
@ -79,58 +79,71 @@ public class AggregatorParsers {
|
||||||
|
|
||||||
|
|
||||||
private AggregatorFactories parseAggregators(XContentParser parser, SearchContext context, int level) throws IOException {
|
private AggregatorFactories parseAggregators(XContentParser parser, SearchContext context, int level) throws IOException {
|
||||||
XContentParser.Token token = null;
|
|
||||||
String currentFieldName = null;
|
|
||||||
|
|
||||||
Matcher validAggMatcher = VALID_AGG_NAME.matcher("");
|
Matcher validAggMatcher = VALID_AGG_NAME.matcher("");
|
||||||
|
|
||||||
AggregatorFactories.Builder factories = new AggregatorFactories.Builder();
|
AggregatorFactories.Builder factories = new AggregatorFactories.Builder();
|
||||||
|
|
||||||
String aggregationName = null;
|
XContentParser.Token token = null;
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
if (token != XContentParser.Token.FIELD_NAME) {
|
||||||
aggregationName = parser.currentName();
|
throw new SearchParseException(context, "Unexpected token " + token + " in [aggs]: aggregations definitions must start with the name of the aggregation.");
|
||||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
|
||||||
String aggregatorType = null;
|
|
||||||
AggregatorFactory factory = null;
|
|
||||||
AggregatorFactories subFactories = null;
|
|
||||||
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
|
||||||
if (token == XContentParser.Token.FIELD_NAME) {
|
|
||||||
currentFieldName = parser.currentName();
|
|
||||||
} else if (token == XContentParser.Token.START_OBJECT) {
|
|
||||||
if ("aggregations".equals(currentFieldName) || "aggs".equals(currentFieldName)) {
|
|
||||||
subFactories = parseAggregators(parser, context, level+1);
|
|
||||||
} else if (aggregatorType != null) {
|
|
||||||
throw new SearchParseException(context, "Found two aggregation type definitions in [" + aggregationName + "]: [" + aggregatorType + "] and [" + currentFieldName + "]. Only one type is allowed.");
|
|
||||||
} else {
|
|
||||||
aggregatorType = currentFieldName;
|
|
||||||
Aggregator.Parser aggregatorParser = parser(aggregatorType);
|
|
||||||
if (aggregatorParser == null) {
|
|
||||||
throw new SearchParseException(context, "Could not find aggregator type [" + currentFieldName + "]");
|
|
||||||
}
|
|
||||||
if (!validAggMatcher.reset(aggregationName).matches()) {
|
|
||||||
throw new SearchParseException(context, "Invalid aggregation name [" + aggregationName + "]. Aggregation names must be alpha-numeric and can only contain '_' and '-'");
|
|
||||||
}
|
|
||||||
factory = aggregatorParser.parse(aggregationName, parser, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (factory == null) {
|
|
||||||
// skipping the aggregation
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (subFactories != null) {
|
|
||||||
factory.subFactories(subFactories);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (level == 0) {
|
|
||||||
factory.validate();
|
|
||||||
}
|
|
||||||
|
|
||||||
factories.add(factory);
|
|
||||||
}
|
}
|
||||||
|
final String aggregationName = parser.currentName();
|
||||||
|
if (!validAggMatcher.reset(aggregationName).matches()) {
|
||||||
|
throw new SearchParseException(context, "Invalid aggregation name [" + aggregationName + "]. Aggregation names must be alpha-numeric and can only contain '_' and '-'");
|
||||||
|
}
|
||||||
|
|
||||||
|
token = parser.nextToken();
|
||||||
|
if (token != XContentParser.Token.START_OBJECT) {
|
||||||
|
throw new SearchParseException(context, "Aggregation definition for [" + aggregationName + " starts with a [" + token + "], expected a [" + XContentParser.Token.START_OBJECT + "].");
|
||||||
|
}
|
||||||
|
|
||||||
|
AggregatorFactory factory = null;
|
||||||
|
AggregatorFactories subFactories = null;
|
||||||
|
|
||||||
|
while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
|
||||||
|
if (token != XContentParser.Token.FIELD_NAME) {
|
||||||
|
throw new SearchParseException(context, "Expected [" + XContentParser.Token.FIELD_NAME + "] under a [" + XContentParser.Token.START_OBJECT + "], but got a [" + token + "] in [" + aggregationName + "]");
|
||||||
|
}
|
||||||
|
final String fieldName = parser.currentName();
|
||||||
|
|
||||||
|
token = parser.nextToken();
|
||||||
|
if (token != XContentParser.Token.START_OBJECT) {
|
||||||
|
throw new SearchParseException(context, "Expected [" + XContentParser.Token.START_OBJECT + "] under [" + fieldName + "], but got a [" + token + "] in [" + aggregationName + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (fieldName) {
|
||||||
|
case "aggregations":
|
||||||
|
case "aggs":
|
||||||
|
if (subFactories != null) {
|
||||||
|
throw new SearchParseException(context, "Found two sub aggregation definitions under [" + aggregationName + "]");
|
||||||
|
}
|
||||||
|
subFactories = parseAggregators(parser, context, level+1);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (factory != null) {
|
||||||
|
throw new SearchParseException(context, "Found two aggregation type definitions in [" + aggregationName + "]: [" + factory.type + "] and [" + fieldName + "]");
|
||||||
|
}
|
||||||
|
Aggregator.Parser aggregatorParser = parser(fieldName);
|
||||||
|
if (aggregatorParser == null) {
|
||||||
|
throw new SearchParseException(context, "Could not find aggregator type [" + fieldName + "] in [" + aggregationName + "]");
|
||||||
|
}
|
||||||
|
factory = aggregatorParser.parse(aggregationName, parser, context);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (factory == null) {
|
||||||
|
throw new SearchParseException(context, "Missing definition for aggregation [" + aggregationName + "]");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subFactories != null) {
|
||||||
|
factory.subFactories(subFactories);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (level == 0) {
|
||||||
|
factory.validate();
|
||||||
|
}
|
||||||
|
|
||||||
|
factories.add(factory);
|
||||||
}
|
}
|
||||||
|
|
||||||
return factories.build();
|
return factories.build();
|
||||||
|
|
|
@ -33,6 +33,7 @@ public class ParsingTests extends ElasticsearchIntegrationTest {
|
||||||
@Test(expected=SearchPhaseExecutionException.class)
|
@Test(expected=SearchPhaseExecutionException.class)
|
||||||
public void testTwoTypes() throws Exception {
|
public void testTwoTypes() throws Exception {
|
||||||
createIndex("idx");
|
createIndex("idx");
|
||||||
|
ensureGreen();
|
||||||
client().prepareSearch("idx").setAggregations(JsonXContent.contentBuilder()
|
client().prepareSearch("idx").setAggregations(JsonXContent.contentBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
.startObject("in_stock")
|
.startObject("in_stock")
|
||||||
|
@ -50,6 +51,34 @@ public class ParsingTests extends ElasticsearchIntegrationTest {
|
||||||
.endObject()).execute().actionGet();
|
.endObject()).execute().actionGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=SearchPhaseExecutionException.class)
|
||||||
|
public void testTwoAggs() throws Exception {
|
||||||
|
createIndex("idx");
|
||||||
|
ensureGreen();
|
||||||
|
client().prepareSearch("idx").setAggregations(JsonXContent.contentBuilder()
|
||||||
|
.startObject()
|
||||||
|
.startObject("by_date")
|
||||||
|
.startObject("date_histogram")
|
||||||
|
.field("field", "timestamp")
|
||||||
|
.field("interval", "month")
|
||||||
|
.endObject()
|
||||||
|
.startObject("aggs")
|
||||||
|
.startObject("tag_count")
|
||||||
|
.startObject("cardinality")
|
||||||
|
.field("field", "tag")
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.startObject("aggs") // 2nd "aggs": illegal
|
||||||
|
.startObject("tag_count2")
|
||||||
|
.startObject("cardinality")
|
||||||
|
.field("field", "tag")
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()).execute().actionGet();
|
||||||
|
}
|
||||||
|
|
||||||
@Test(expected=SearchPhaseExecutionException.class)
|
@Test(expected=SearchPhaseExecutionException.class)
|
||||||
public void testInvalidAggregationName() throws Exception {
|
public void testInvalidAggregationName() throws Exception {
|
||||||
|
|
||||||
|
@ -69,6 +98,7 @@ public class ParsingTests extends ElasticsearchIntegrationTest {
|
||||||
}
|
}
|
||||||
|
|
||||||
createIndex("idx");
|
createIndex("idx");
|
||||||
|
ensureGreen();
|
||||||
client().prepareSearch("idx").setAggregations(JsonXContent.contentBuilder()
|
client().prepareSearch("idx").setAggregations(JsonXContent.contentBuilder()
|
||||||
.startObject()
|
.startObject()
|
||||||
.startObject(name)
|
.startObject(name)
|
||||||
|
@ -81,4 +111,49 @@ public class ParsingTests extends ElasticsearchIntegrationTest {
|
||||||
.endObject()
|
.endObject()
|
||||||
.endObject()).execute().actionGet();
|
.endObject()).execute().actionGet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test(expected=SearchPhaseExecutionException.class)
|
||||||
|
public void testMissingName() throws Exception {
|
||||||
|
createIndex("idx");
|
||||||
|
ensureGreen();
|
||||||
|
client().prepareSearch("idx").setAggregations(JsonXContent.contentBuilder()
|
||||||
|
.startObject()
|
||||||
|
.startObject("by_date")
|
||||||
|
.startObject("date_histogram")
|
||||||
|
.field("field", "timestamp")
|
||||||
|
.field("interval", "month")
|
||||||
|
.endObject()
|
||||||
|
.startObject("aggs")
|
||||||
|
// the aggregation name is missing
|
||||||
|
//.startObject("tag_count")
|
||||||
|
.startObject("cardinality")
|
||||||
|
.field("field", "tag")
|
||||||
|
.endObject()
|
||||||
|
//.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()).execute().actionGet();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected=SearchPhaseExecutionException.class)
|
||||||
|
public void testMissingType() throws Exception {
|
||||||
|
createIndex("idx");
|
||||||
|
ensureGreen();
|
||||||
|
client().prepareSearch("idx").setAggregations(JsonXContent.contentBuilder()
|
||||||
|
.startObject()
|
||||||
|
.startObject("by_date")
|
||||||
|
.startObject("date_histogram")
|
||||||
|
.field("field", "timestamp")
|
||||||
|
.field("interval", "month")
|
||||||
|
.endObject()
|
||||||
|
.startObject("aggs")
|
||||||
|
.startObject("tag_count")
|
||||||
|
// the aggregation type is missing
|
||||||
|
//.startObject("cardinality")
|
||||||
|
.field("field", "tag")
|
||||||
|
//.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()).execute().actionGet();
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue