public List<Reducer> createReducers() throws IOException {
   List<Reducer> reducers = new ArrayList<>();
   for (ReducerFactory factory : this.reducerFactories) {
     reducers.add(factory.create());
   }
   return reducers;
 }
 private List<ReducerFactory> resolveReducerOrder(
     List<ReducerFactory> reducerFactories, List<AggregatorFactory> aggFactories) {
   Map<String, ReducerFactory> reducerFactoriesMap = new HashMap<>();
   for (ReducerFactory factory : reducerFactories) {
     reducerFactoriesMap.put(factory.getName(), factory);
   }
   Set<String> aggFactoryNames = new HashSet<>();
   for (AggregatorFactory aggFactory : aggFactories) {
     aggFactoryNames.add(aggFactory.name);
   }
   List<ReducerFactory> orderedReducers = new LinkedList<>();
   List<ReducerFactory> unmarkedFactories = new ArrayList<ReducerFactory>(reducerFactories);
   Set<ReducerFactory> temporarilyMarked = new HashSet<ReducerFactory>();
   while (!unmarkedFactories.isEmpty()) {
     ReducerFactory factory = unmarkedFactories.get(0);
     resolveReducerOrder(
         aggFactoryNames,
         reducerFactoriesMap,
         orderedReducers,
         unmarkedFactories,
         temporarilyMarked,
         factory);
   }
   return orderedReducers;
 }
 public void validate() {
   for (AggregatorFactory factory : factories) {
     factory.validate();
   }
   for (ReducerFactory factory : reducerFactories) {
     factory.validate(parent, factories, reducerFactories);
   }
 }
 private void resolveReducerOrder(
     Set<String> aggFactoryNames,
     Map<String, ReducerFactory> reducerFactoriesMap,
     List<ReducerFactory> orderedReducers,
     List<ReducerFactory> unmarkedFactories,
     Set<ReducerFactory> temporarilyMarked,
     ReducerFactory factory) {
   if (temporarilyMarked.contains(factory)) {
     throw new IllegalStateException(
         "Cyclical dependancy found with reducer [" + factory.getName() + "]");
   } else if (unmarkedFactories.contains(factory)) {
     temporarilyMarked.add(factory);
     String[] bucketsPaths = factory.getBucketsPaths();
     for (String bucketsPath : bucketsPaths) {
       List<String> bucketsPathElements =
           AggregationPath.parse(bucketsPath).getPathElementsAsStringList();
       String firstAggName = bucketsPathElements.get(0);
       if (bucketsPath.equals("_count")
           || bucketsPath.equals("_key")
           || aggFactoryNames.contains(firstAggName)) {
         continue;
       } else {
         ReducerFactory matchingFactory = reducerFactoriesMap.get(firstAggName);
         if (matchingFactory != null) {
           resolveReducerOrder(
               aggFactoryNames,
               reducerFactoriesMap,
               orderedReducers,
               unmarkedFactories,
               temporarilyMarked,
               matchingFactory);
         } else {
           throw new IllegalStateException(
               "No aggregation found for path [" + bucketsPath + "]");
         }
       }
     }
     unmarkedFactories.remove(factory);
     temporarilyMarked.remove(factory);
     orderedReducers.add(factory);
   }
 }