public SignificantTermsAggregatorFactory( String name, ValuesSourceConfig valueSourceConfig, TermsAggregator.BucketCountThresholds bucketCountThresholds, IncludeExclude includeExclude, String executionHint, Query filter, SignificanceHeuristic significanceHeuristic) { super(name, SignificantStringTerms.TYPE.name(), valueSourceConfig); this.bucketCountThresholds = bucketCountThresholds; this.includeExclude = includeExclude; this.executionHint = executionHint; this.significanceHeuristic = significanceHeuristic; if (!valueSourceConfig.unmapped()) { this.indexedFieldName = config.fieldContext().field(); fieldType = SearchContext.current().smartNameFieldType(indexedFieldName); } this.filter = filter; }
@Override public AggregatorFactory parse( String aggregationName, XContentParser parser, SearchContext context) throws IOException { ValuesSourceConfig<NumericValuesSource> config = new ValuesSourceConfig<NumericValuesSource>(NumericValuesSource.class); String field = null; List<RangeAggregator.Range> ranges = null; String script = null; String scriptLang = null; Map<String, Object> scriptParams = null; boolean keyed = false; boolean assumeSorted = false; XContentParser.Token token; String currentFieldName = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.VALUE_STRING) { if ("field".equals(currentFieldName)) { field = parser.text(); } else if ("script".equals(currentFieldName)) { script = parser.text(); } else if ("lang".equals(currentFieldName)) { scriptLang = parser.text(); } else { throw new SearchParseException( context, "Unknown key for a " + token + " in [" + aggregationName + "]: [" + currentFieldName + "]."); } } else if (token == XContentParser.Token.START_ARRAY) { if ("ranges".equals(currentFieldName)) { ranges = new ArrayList<RangeAggregator.Range>(); while ((token = parser.nextToken()) != XContentParser.Token.END_ARRAY) { double from = Double.NEGATIVE_INFINITY; String fromAsStr = null; double to = Double.POSITIVE_INFINITY; String toAsStr = null; String key = null; String toOrFromOrKey = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { toOrFromOrKey = parser.currentName(); } else if (token == XContentParser.Token.VALUE_NUMBER) { if ("from".equals(toOrFromOrKey)) { from = parser.doubleValue(); } else if ("to".equals(toOrFromOrKey)) { to = parser.doubleValue(); } } else if (token == XContentParser.Token.VALUE_STRING) { if ("from".equals(toOrFromOrKey)) { fromAsStr = parser.text(); } else if ("to".equals(toOrFromOrKey)) { toAsStr = parser.text(); } else if ("key".equals(toOrFromOrKey)) { key = parser.text(); } } } ranges.add(new RangeAggregator.Range(key, from, fromAsStr, to, toAsStr)); } } else { throw new SearchParseException( context, "Unknown key for a " + token + " in [" + aggregationName + "]: [" + currentFieldName + "]."); } } else if (token == XContentParser.Token.START_OBJECT) { if ("params".equals(currentFieldName)) { scriptParams = parser.map(); } else { throw new SearchParseException( context, "Unknown key for a " + token + " in [" + aggregationName + "]: [" + currentFieldName + "]."); } } else if (token == XContentParser.Token.VALUE_BOOLEAN) { if ("keyed".equals(currentFieldName)) { keyed = parser.booleanValue(); } else if ("script_values_sorted".equals(currentFieldName)) { assumeSorted = parser.booleanValue(); } else { throw new SearchParseException( context, "Unknown key for a " + token + " in [" + aggregationName + "]: [" + currentFieldName + "]."); } } else { throw new SearchParseException( context, "Unexpected token " + token + " in [" + aggregationName + "]."); } } if (ranges == null) { throw new SearchParseException( context, "Missing [ranges] in ranges aggregator [" + aggregationName + "]"); } if (script != null) { config.script( context.scriptService().search(context.lookup(), scriptLang, script, scriptParams)); } if (!assumeSorted) { // we need values to be sorted and unique for efficiency config.ensureSorted(true); } if (field == null) { return new RangeAggregator.Factory( aggregationName, config, InternalRange.FACTORY, ranges, keyed); } FieldMapper<?> mapper = context.smartNameFieldMapper(field); if (mapper == null) { config.unmapped(true); return new RangeAggregator.Factory( aggregationName, config, InternalRange.FACTORY, ranges, keyed); } IndexFieldData<?> indexFieldData = context.fieldData().getForField(mapper); config.fieldContext(new FieldContext(field, indexFieldData)); return new RangeAggregator.Factory( aggregationName, config, InternalRange.FACTORY, ranges, keyed); }
@Override public AggregatorFactory parse( String aggregationName, XContentParser parser, SearchContext context) throws IOException { String childType = null; XContentParser.Token token; String currentFieldName = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.VALUE_STRING) { if ("type".equals(currentFieldName)) { childType = parser.text(); } else { throw new SearchParseException( context, "Unknown key for a " + token + " in [" + aggregationName + "]: [" + currentFieldName + "]."); } } else { throw new SearchParseException( context, "Unexpected token " + token + " in [" + aggregationName + "]."); } } if (childType == null) { throw new SearchParseException( context, "Missing [child_type] field for children aggregation [" + aggregationName + "]"); } DocumentMapper childDocMapper = context.mapperService().documentMapper(childType); if (childDocMapper == null) { throw new SearchParseException( context, "[children] No mapping for for type [" + childType + "]"); } ParentFieldMapper parentFieldMapper = childDocMapper.parentFieldMapper(); if (!parentFieldMapper.active()) { throw new SearchParseException(context, "[children] _parent field not configured"); } String parentType = parentFieldMapper.type(); DocumentMapper parentDocMapper = context.mapperService().documentMapper(parentType); if (parentDocMapper == null) { throw new SearchParseException( context, "[children] Type [" + childType + "] points to a non existent parent type [" + parentType + "]"); } Filter parentFilter = context.filterCache().cache(parentDocMapper.typeFilter()); Filter childFilter = context.filterCache().cache(childDocMapper.typeFilter()); ParentChildIndexFieldData parentChildIndexFieldData = context.fieldData().getForField(parentFieldMapper); ValuesSourceConfig<ValuesSource.Bytes.WithOrdinals.ParentChild> config = new ValuesSourceConfig<>(ValuesSource.Bytes.WithOrdinals.ParentChild.class); config.fieldContext( new FieldContext( parentFieldMapper.names().indexName(), parentChildIndexFieldData, parentFieldMapper)); return new ParentToChildrenAggregator.Factory( aggregationName, config, parentType, parentFilter, childFilter); }
@Override public AggregatorFactory parse( String aggregationName, XContentParser parser, SearchContext context) throws IOException { String field = null; String script = null; String scriptLang = null; Map<String, Object> scriptParams = null; Terms.ValueType valueType = null; int requiredSize = 10; String orderKey = "_count"; boolean orderAsc = false; String format = null; boolean assumeUnique = false; XContentParser.Token token; String currentFieldName = null; while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { currentFieldName = parser.currentName(); } else if (token == XContentParser.Token.VALUE_STRING) { if ("field".equals(currentFieldName)) { field = parser.text(); } else if ("script".equals(currentFieldName)) { script = parser.text(); } else if ("script_lang".equals(currentFieldName) || "scriptLang".equals(currentFieldName)) { scriptLang = parser.text(); } else if ("value_type".equals(currentFieldName) || "valueType".equals(currentFieldName)) { valueType = Terms.ValueType.resolveType(parser.text()); } else if ("format".equals(currentFieldName)) { format = parser.text(); } } else if (token == XContentParser.Token.VALUE_BOOLEAN) { if ("script_values_unique".equals(currentFieldName)) { assumeUnique = parser.booleanValue(); } } else if (token == XContentParser.Token.VALUE_NUMBER) { if ("size".equals(currentFieldName)) { requiredSize = parser.intValue(); } } else if (token == XContentParser.Token.START_OBJECT) { if ("params".equals(currentFieldName)) { scriptParams = parser.map(); } else if ("order".equals(currentFieldName)) { while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) { if (token == XContentParser.Token.FIELD_NAME) { orderKey = parser.currentName(); } else if (token == XContentParser.Token.VALUE_STRING) { String dir = parser.text(); orderAsc = "asc".equalsIgnoreCase(dir); // TODO: do we want to throw a parse error if the alternative is not "desc"??? } } } } } InternalOrder order = resolveOrder(orderKey, orderAsc); SearchScript searchScript = null; if (script != null) { searchScript = context.scriptService().search(context.lookup(), scriptLang, script, scriptParams); } if (field == null) { Class<? extends ValuesSource> valueSourceType = script == null ? ValuesSource.class : // unknown, will inherit whatever is in the context valueType != null ? valueType.scriptValueType.getValuesSourceType() : // the user explicitly defined a value type BytesValuesSource.class; // defaulting to bytes ValuesSourceConfig<?> config = new ValuesSourceConfig(valueSourceType); if (valueType != null) { config.scriptValueType(valueType.scriptValueType); } config.script(searchScript); if (!assumeUnique) { config.ensureUnique(true); } return new TermsAggregatorFactory(aggregationName, config, order, requiredSize); } FieldMapper<?> mapper = context.smartNameFieldMapper(field); if (mapper == null) { ValuesSourceConfig<?> config = new ValuesSourceConfig<BytesValuesSource>(BytesValuesSource.class); config.unmapped(true); return new TermsAggregatorFactory(aggregationName, config, order, requiredSize); } IndexFieldData<?> indexFieldData = context.fieldData().getForField(mapper); ValuesSourceConfig<?> config; if (mapper instanceof DateFieldMapper) { DateFieldMapper dateMapper = (DateFieldMapper) mapper; ValueFormatter formatter = format == null ? new ValueFormatter.DateTime(dateMapper.dateTimeFormatter()) : new ValueFormatter.DateTime(format); config = new ValuesSourceConfig<NumericValuesSource>(NumericValuesSource.class) .formatter(formatter) .parser(new ValueParser.DateMath(dateMapper.dateMathParser())); } else if (mapper instanceof IpFieldMapper) { config = new ValuesSourceConfig<NumericValuesSource>(NumericValuesSource.class) .formatter(ValueFormatter.IPv4) .parser(ValueParser.IPv4); } else if (indexFieldData instanceof IndexNumericFieldData) { config = new ValuesSourceConfig<NumericValuesSource>(NumericValuesSource.class); if (format != null) { config.formatter(new ValueFormatter.Number.Pattern(format)); } } else { config = new ValuesSourceConfig<BytesValuesSource>(BytesValuesSource.class); // TODO: it will make sense to set false instead here if the aggregator factory uses // ordinals instead of hash tables config.needsHashes(true); } config.script(searchScript); config.fieldContext(new FieldContext(field, indexFieldData)); // We need values to be unique to be able to run terms aggs efficiently if (!assumeUnique) { config.ensureUnique(true); } return new TermsAggregatorFactory(aggregationName, config, order, requiredSize); }