3939import org .elasticsearch .index .query .QueryBuilder ;
4040import org .elasticsearch .index .query .RangeQueryBuilder ;
4141import org .elasticsearch .index .query .TermQueryBuilder ;
42+ import org .elasticsearch .index .query .TermsQueryBuilder ;
4243import org .elasticsearch .script .ScriptService ;
4344import org .elasticsearch .search .aggregations .AggregationBuilder ;
4445import org .elasticsearch .search .aggregations .AggregatorFactories ;
6667import java .io .IOException ;
6768import java .util .ArrayList ;
6869import java .util .Arrays ;
70+ import java .util .Collections ;
6971import java .util .HashSet ;
7072import java .util .List ;
7173import java .util .Objects ;
@@ -276,91 +278,38 @@ static QueryBuilder rewriteQuery(QueryBuilder builder, Set<RollupJobCaps> jobCap
276278 rewriteQuery (((BoostingQueryBuilder )builder ).positiveQuery (), jobCaps ));
277279 } else if (builder .getWriteableName ().equals (DisMaxQueryBuilder .NAME )) {
278280 DisMaxQueryBuilder rewritten = new DisMaxQueryBuilder ();
279- ((DisMaxQueryBuilder )builder ).innerQueries ().forEach (query -> rewritten .add (rewriteQuery (query , jobCaps )));
281+ ((DisMaxQueryBuilder ) builder ).innerQueries ().forEach (query -> rewritten .add (rewriteQuery (query , jobCaps )));
280282 return rewritten ;
281- } else if (builder .getWriteableName ().equals (RangeQueryBuilder .NAME ) || builder .getWriteableName ().equals (TermQueryBuilder .NAME )) {
282-
283- String fieldName = builder .getWriteableName ().equals (RangeQueryBuilder .NAME )
284- ? ((RangeQueryBuilder )builder ).fieldName ()
285- : ((TermQueryBuilder )builder ).fieldName ();
286-
287- List <String > incorrectTimeZones = new ArrayList <>();
288- List <String > rewrittenFieldName = jobCaps .stream ()
289- // We only care about job caps that have the query's target field
290- .filter (caps -> caps .getFieldCaps ().keySet ().contains (fieldName ))
291- .map (caps -> {
292- RollupJobCaps .RollupFieldCaps fieldCaps = caps .getFieldCaps ().get (fieldName );
293- return fieldCaps .getAggs ().stream ()
294- // For now, we only allow filtering on grouping fields
295- .filter (agg -> {
296- String type = (String )agg .get (RollupField .AGG );
297-
298- // If the cap is for a date_histo, and the query is a range, the timezones need to match
299- if (type .equals (DateHistogramAggregationBuilder .NAME ) && builder instanceof RangeQueryBuilder ) {
300- String timeZone = ((RangeQueryBuilder )builder ).timeZone ();
301-
302- // Many range queries don't include the timezone because the default is UTC, but the query
303- // builder will return null so we need to set it here
304- if (timeZone == null ) {
305- timeZone = DateTimeZone .UTC .toString ();
306- }
307- boolean matchingTZ = ((String )agg .get (DateHistoGroupConfig .TIME_ZONE .getPreferredName ()))
308- .equalsIgnoreCase (timeZone );
309- if (matchingTZ == false ) {
310- incorrectTimeZones .add ((String )agg .get (DateHistoGroupConfig .TIME_ZONE .getPreferredName ()));
311- }
312- return matchingTZ ;
313- }
314- // Otherwise just make sure it's one of the three groups
315- return type .equals (TermsAggregationBuilder .NAME )
316- || type .equals (DateHistogramAggregationBuilder .NAME )
317- || type .equals (HistogramAggregationBuilder .NAME );
318- })
319- // Rewrite the field name to our convention (e.g. "foo" -> "date_histogram.foo.timestamp")
320- .map (agg -> {
321- if (agg .get (RollupField .AGG ).equals (DateHistogramAggregationBuilder .NAME )) {
322- return RollupField .formatFieldName (fieldName , (String )agg .get (RollupField .AGG ), RollupField .TIMESTAMP );
323- } else {
324- return RollupField .formatFieldName (fieldName , (String )agg .get (RollupField .AGG ), RollupField .VALUE );
325- }
326- })
327- .collect (Collectors .toList ());
328- })
329- .distinct ()
330- .collect (ArrayList ::new , List ::addAll , List ::addAll );
331-
332- if (rewrittenFieldName .isEmpty ()) {
333- if (incorrectTimeZones .isEmpty ()) {
334- throw new IllegalArgumentException ("Field [" + fieldName + "] in [" + builder .getWriteableName ()
335- + "] query is not available in selected rollup indices, cannot query." );
336- } else {
337- throw new IllegalArgumentException ("Field [" + fieldName + "] in [" + builder .getWriteableName ()
338- + "] query was found in rollup indices, but requested timezone is not compatible. Options include: "
339- + incorrectTimeZones );
340- }
283+ } else if (builder .getWriteableName ().equals (RangeQueryBuilder .NAME )) {
284+ RangeQueryBuilder range = (RangeQueryBuilder ) builder ;
285+ String fieldName = range .fieldName ();
286+ // Many range queries don't include the timezone because the default is UTC, but the query
287+ // builder will return null so we need to set it here
288+ String timeZone = range .timeZone () == null ? DateTimeZone .UTC .toString () : range .timeZone ();
289+
290+ String rewrittenFieldName = rewriteFieldName (jobCaps , RangeQueryBuilder .NAME , fieldName , timeZone );
291+ RangeQueryBuilder rewritten = new RangeQueryBuilder (rewrittenFieldName )
292+ .from (range .from ())
293+ .to (range .to ())
294+ .includeLower (range .includeLower ())
295+ .includeUpper (range .includeUpper ());
296+ if (range .timeZone () != null ) {
297+ rewritten .timeZone (range .timeZone ());
341298 }
342-
343- if (rewrittenFieldName .size () > 1 ) {
344- throw new IllegalArgumentException ("Ambiguous field name resolution when mapping to rolled fields. Field name [" +
345- fieldName + "] was mapped to: [" + Strings .collectionToDelimitedString (rewrittenFieldName , "," ) + "]." );
299+ if (range .format () != null ) {
300+ rewritten .format (range .format ());
346301 }
347-
348- //Note: instanceof here to make casting checks happier
349- if (builder instanceof RangeQueryBuilder ) {
350- RangeQueryBuilder rewritten = new RangeQueryBuilder (rewrittenFieldName .get (0 ));
351- RangeQueryBuilder original = (RangeQueryBuilder )builder ;
352- rewritten .from (original .from ());
353- rewritten .to (original .to ());
354- if (original .timeZone () != null ) {
355- rewritten .timeZone (original .timeZone ());
356- }
357- rewritten .includeLower (original .includeLower ());
358- rewritten .includeUpper (original .includeUpper ());
359- return rewritten ;
360- } else {
361- return new TermQueryBuilder (rewrittenFieldName .get (0 ), ((TermQueryBuilder )builder ).value ());
362- }
363-
302+ return rewritten ;
303+ } else if (builder .getWriteableName ().equals (TermQueryBuilder .NAME )) {
304+ TermQueryBuilder term = (TermQueryBuilder ) builder ;
305+ String fieldName = term .fieldName ();
306+ String rewrittenFieldName = rewriteFieldName (jobCaps , TermQueryBuilder .NAME , fieldName , null );
307+ return new TermQueryBuilder (rewrittenFieldName , term .value ());
308+ } else if (builder .getWriteableName ().equals (TermsQueryBuilder .NAME )) {
309+ TermsQueryBuilder terms = (TermsQueryBuilder ) builder ;
310+ String fieldName = terms .fieldName ();
311+ String rewrittenFieldName = rewriteFieldName (jobCaps , TermQueryBuilder .NAME , fieldName , null );
312+ return new TermsQueryBuilder (rewrittenFieldName , terms .values ());
364313 } else if (builder .getWriteableName ().equals (MatchAllQueryBuilder .NAME )) {
365314 // no-op
366315 return builder ;
@@ -369,6 +318,64 @@ static QueryBuilder rewriteQuery(QueryBuilder builder, Set<RollupJobCaps> jobCap
369318 }
370319 }
371320
321+ private static String rewriteFieldName (Set <RollupJobCaps > jobCaps ,
322+ String builderName ,
323+ String fieldName ,
324+ String timeZone ) {
325+ List <String > incompatibleTimeZones = timeZone == null ? Collections .emptyList () : new ArrayList <>();
326+ List <String > rewrittenFieldNames = jobCaps .stream ()
327+ // We only care about job caps that have the query's target field
328+ .filter (caps -> caps .getFieldCaps ().keySet ().contains (fieldName ))
329+ .map (caps -> {
330+ RollupJobCaps .RollupFieldCaps fieldCaps = caps .getFieldCaps ().get (fieldName );
331+ return fieldCaps .getAggs ().stream ()
332+ // For now, we only allow filtering on grouping fields
333+ .filter (agg -> {
334+ String type = (String )agg .get (RollupField .AGG );
335+
336+ // If the cap is for a date_histo, and the query is a range, the timezones need to match
337+ if (type .equals (DateHistogramAggregationBuilder .NAME ) && timeZone != null ) {
338+ boolean matchingTZ = ((String )agg .get (DateHistoGroupConfig .TIME_ZONE .getPreferredName ()))
339+ .equalsIgnoreCase (timeZone );
340+ if (matchingTZ == false ) {
341+ incompatibleTimeZones .add ((String )agg .get (DateHistoGroupConfig .TIME_ZONE .getPreferredName ()));
342+ }
343+ return matchingTZ ;
344+ }
345+ // Otherwise just make sure it's one of the three groups
346+ return type .equals (TermsAggregationBuilder .NAME )
347+ || type .equals (DateHistogramAggregationBuilder .NAME )
348+ || type .equals (HistogramAggregationBuilder .NAME );
349+ })
350+ // Rewrite the field name to our convention (e.g. "foo" -> "date_histogram.foo.timestamp")
351+ .map (agg -> {
352+ if (agg .get (RollupField .AGG ).equals (DateHistogramAggregationBuilder .NAME )) {
353+ return RollupField .formatFieldName (fieldName , (String )agg .get (RollupField .AGG ), RollupField .TIMESTAMP );
354+ } else {
355+ return RollupField .formatFieldName (fieldName , (String )agg .get (RollupField .AGG ), RollupField .VALUE );
356+ }
357+ })
358+ .collect (Collectors .toList ());
359+ })
360+ .distinct ()
361+ .collect (ArrayList ::new , List ::addAll , List ::addAll );
362+ if (rewrittenFieldNames .isEmpty ()) {
363+ if (incompatibleTimeZones .isEmpty ()) {
364+ throw new IllegalArgumentException ("Field [" + fieldName + "] in [" + builderName
365+ + "] query is not available in selected rollup indices, cannot query." );
366+ } else {
367+ throw new IllegalArgumentException ("Field [" + fieldName + "] in [" + builderName
368+ + "] query was found in rollup indices, but requested timezone is not compatible. Options include: "
369+ + incompatibleTimeZones );
370+ }
371+ } else if (rewrittenFieldNames .size () > 1 ) {
372+ throw new IllegalArgumentException ("Ambiguous field name resolution when mapping to rolled fields. Field name [" +
373+ fieldName + "] was mapped to: [" + Strings .collectionToDelimitedString (rewrittenFieldNames , "," ) + "]." );
374+ } else {
375+ return rewrittenFieldNames .get (0 );
376+ }
377+ }
378+
372379 static RollupSearchContext separateIndices (String [] indices , ImmutableOpenMap <String , IndexMetaData > indexMetaData ) {
373380
374381 if (indices .length == 0 ) {
0 commit comments