docs: private void distributedProcessMissingTop(ResponseBuilder rb,
        ComponentFields mtasFields) throws IOException {
      // initialise
      Map<String, SortedMap<String, MtasDataItemNumberComparator>> mergedComparatorLists = new HashMap<>();
      Map<String, MtasDataItemNumberComparator> mergedComparatorBoundaryList = new HashMap<>();
      Map<String, MtasDataItemNumberComparator> summedComparatorBoundaryList = new HashMap<>();
      Map<String, Map<String, MtasDataItemNumberComparator>> comparatorBoundariesList = new HashMap<>();
      // check all termvectors, and initialize
      for (String field : mtasFields.list.keySet()) {
        List<ComponentTermVector> tvList = mtasFields.list
            .get(field).termVectorList;
        if (tvList != null) {
          for (ComponentTermVector tv : tvList) {
            if (!tv.subComponentFunction.sortType.equals(CodecUtil.SORT_TERM)) {
              mergedComparatorLists.put(tv.key,
                  new TreeMap<String, MtasDataItemNumberComparator>());
            }
          }
        }
      }
      // compute for each termvector the mergedComparatorList and the
      // summedBoundary
      for (ShardRequest sreq : rb.finished) {
        if (sreq.params.getBool(MtasSolrSearchComponent.PARAM_MTAS, false)
            && sreq.params.getBool(PARAM_MTAS_TERMVECTOR, false)) {
          for (ShardResponse shardResponse : sreq.responses) {
            SortedMap<String, MtasDataItemNumberComparator> mergedComparatorList;
            NamedList<Object> response = shardResponse.getSolrResponse()
                .getResponse();
            String key;
            MtasSolrMtasResult list;
            MtasDataItemNumberComparator comparatorLast;
            Map<String, MtasDataItemNumberComparator> comparatorList;
            try {
              List<NamedList<Object>> data = (List<NamedList<Object>>) response
                  .findRecursive("mtas", NAME);
              if (data != null) {
                for (int i = 0; i < data.size(); i++) {
                  NamedList<Object> dataItem = data.get(i);
                  try {
                    key = (String) dataItem.get("key");
                    list = (MtasSolrMtasResult) dataItem.get("list");
                    if (list != null) {
                      comparatorLast = list.getResult().getLastSortValue();
                      comparatorList = list.getResult().getComparatorList();
                      if (key == null) {
                        dataItem.clear();
                      } else if (comparatorLast == null || comparatorList == null
                          || !mergedComparatorLists.containsKey(key)) {
                        // do nothing
                      } else {
                        mergedComparatorList = mergedComparatorLists.get(key);
                        for (Entry<String, MtasDataItemNumberComparator> entry : comparatorList
                            .entrySet()) {
                          if (mergedComparatorList.containsKey(entry.getKey())) {
                            mergedComparatorList.get(entry.getKey())
                                .add(entry.getValue().getValue());
                          } else {
                            mergedComparatorList.put(entry.getKey(),
                                entry.getValue().clone());
                          }
                        }
                        if (!comparatorBoundariesList.containsKey(key)) {
                          comparatorBoundariesList.put(key,
                              new HashMap<String, MtasDataItemNumberComparator>());
                        }
                        comparatorBoundariesList.get(key)
                            .put(shardResponse.getShardAddress(), comparatorLast);
                        if (summedComparatorBoundaryList.containsKey(key)) {
                          summedComparatorBoundaryList.get(key)
                              .add(comparatorLast.getValue());
                        } else {
                          summedComparatorBoundaryList.put(key,
                              comparatorLast.clone());
                        }
                      }
                    } else {
                      throw new IOException("no data returned");
                    }
                  } catch (ClassCastException e) {
                    log.debug(e);
                    dataItem.clear();
                  }
                }
              }
            } catch (ClassCastException e) {
              log.debug(e);
              // shouldnt happen
            }
            shardResponse.getSolrResponse().setResponse(response);
          }
        }
      }
      // compute for each relevant termvector the mergedComparatorBoundary
      HashMap<String, HashMap<String, HashMap<String, MtasDataItemNumberComparator>>> recomputeFieldList = new HashMap<>();
      for (String field : mtasFields.list.keySet()) {
        List<ComponentTermVector> tvList = mtasFields.list
            .get(field).termVectorList;
        if (tvList != null) {
          for (ComponentTermVector tv : tvList) {
            SortedMap<String, MtasDataItemNumberComparator> mergedComparatorList;
            if (mergedComparatorLists.containsKey(tv.key)) {
              mergedComparatorList = mergedComparatorLists.get(tv.key);
              if (mergedComparatorList.size() < tv.number || tv.number <= 0) {
                // do nothing
              } else {
                final int sortDirection = tv.subComponentFunction.sortDirection
                    .equals(CodecUtil.SORT_DESC) ? -1 : 1;
                SortedSet<Map.Entry<String, MtasDataItemNumberComparator>> sortedSet = new TreeSet<>(
                    (Map.Entry<String, MtasDataItemNumberComparator> e1,
                        Map.Entry<String, MtasDataItemNumberComparator> e2) -> (e1
                            .getValue().compareTo(e2.getValue().getValue()) == 0)
                                ? e1.getKey().compareTo(e2.getKey())
                                : e1.getValue().compareTo(
                                    e2.getValue().getValue()) * sortDirection);
                sortedSet.addAll(mergedComparatorLists.get(tv.key).entrySet());
                Optional<Map.Entry<String, MtasDataItemNumberComparator>> optionalItem = sortedSet
                    .stream().skip(tv.number - 1L).findFirst();
                if (optionalItem.isPresent()) {
                  mergedComparatorBoundaryList.put(tv.key,
                      optionalItem.get().getValue());
                }
              }
            }
          }
        }
        HashMap<String, HashMap<String, MtasDataItemNumberComparator>> recomputeList = new HashMap<>();
        if (tvList != null) {
          for (ComponentTermVector tv : tvList) {
            String key = tv.key;
            if (mergedComparatorBoundaryList.containsKey(key)
                && summedComparatorBoundaryList.containsKey(key)) {
              // set termvector to recompute
              recomputeList.put(key,
                  new HashMap<String, MtasDataItemNumberComparator>());
              // sort
              List<Entry<String, MtasDataItemNumberComparator>> list = new LinkedList<>(
                  comparatorBoundariesList.get(key).entrySet());
              Collections.sort(list,
                  (Entry<String, MtasDataItemNumberComparator> e1,
                      Entry<String, MtasDataItemNumberComparator> e2) -> e1
                          .getValue().compareTo(e2.getValue().getValue()));
              HashMap<String, MtasDataItemNumberComparator> sortedHashMap = new LinkedHashMap<>();
              for (Iterator<Map.Entry<String, MtasDataItemNumberComparator>> it = list
                  .iterator(); it.hasNext();) {
                Map.Entry<String, MtasDataItemNumberComparator> entry = it.next();
                sortedHashMap.put(entry.getKey(), entry.getValue());
              }
  
              MtasDataItemNumberComparator mainNewBoundary = mergedComparatorBoundaryList
                  .get(key).recomputeBoundary(sortedHashMap.size());
              // System.out.println(
              // "MAIN NEW BOUNDARY for '" + key + "' : " + mainNewBoundary);
  
              MtasDataItemNumberComparator sum = null;
              int number = 0;
              for (Entry<String, MtasDataItemNumberComparator> entry : sortedHashMap
                  .entrySet()) {
                MtasDataItemNumberComparator newBoundary = mainNewBoundary
                    .clone();
                MtasDataItemNumberComparator currentBoundary = entry.getValue();
                int compare = currentBoundary.compareTo(newBoundary.getValue());
                if (tv.subComponentFunction.sortDirection
                    .equals(CodecUtil.SORT_DESC)) {
                  compare *= -1;
                }
                if (compare < 0) {
                  HashMap<String, MtasDataItemNumberComparator> recomputeSubList = new HashMap<>();
                  // sum not null if number>0, but do check
                  if (number > 0 && sum != null
                      && tv.subComponentFunction.sortDirection
                          .equals(CodecUtil.SORT_DESC)) {
                    MtasDataItemNumberComparator tmpSumBoundary = mergedComparatorBoundaryList
                        .get(key);
                    tmpSumBoundary.subtract(sum.getValue());
                    MtasDataItemNumberComparator alternativeNewBoundary = tmpSumBoundary
                        .recomputeBoundary(sortedHashMap.size() - number);
                    compare = newBoundary
                        .compareTo(alternativeNewBoundary.getValue());
                    if (compare < 0) {
                      newBoundary = alternativeNewBoundary;
                      compare = currentBoundary.compareTo(newBoundary.getValue());
                      if (tv.subComponentFunction.sortDirection
                          .equals(CodecUtil.SORT_DESC)) {
                        compare *= -1;
                      }
                      if (compare < 0) {
                        recomputeSubList.put(entry.getKey(), newBoundary);
                      }
                    } else {
                      recomputeSubList.put(entry.getKey(), newBoundary);
                    }
                  } else {
                    recomputeSubList.put(entry.getKey(), newBoundary);
                  }
                  if (!recomputeSubList.isEmpty()) {
                    if (!recomputeList.containsKey(key)) {
                      recomputeList.put(key, recomputeSubList);
                    } else {
                      recomputeList.get(key).putAll(recomputeSubList);
                    }
                  }
                } else {
                  newBoundary = currentBoundary.clone();
                }
                if (sum == null) {
                  sum = newBoundary.clone();
                } else {
                  sum.add(newBoundary.getValue());
                }
                number++;
              }
            }
          }
        }
        if (!recomputeList.isEmpty()) {
          recomputeFieldList.put(field, recomputeList);
        }
      }
  
      // finally, recompute
      if (recomputeFieldList.size() > 0) {
  
        // remove output for termvectors in recompute list and get list of shards
        HashSet<String> shards = new HashSet<>();
        for (ShardRequest sreq : rb.finished) {
          if (sreq.params.getBool(MtasSolrSearchComponent.PARAM_MTAS, false)
              && sreq.params.getBool(PARAM_MTAS_TERMVECTOR, false)) {
            for (ShardResponse shardResponse : sreq.responses) {
              NamedList<Object> response = shardResponse.getSolrResponse()
                  .getResponse();
              String key;
              String field;
              String shardAddress = shardResponse.getShardAddress();
              try {
                ArrayList<NamedList<Object>> data = (ArrayList<NamedList<Object>>) response
                    .findRecursive("mtas", NAME);
                shards.add(shardAddress);
                if (data != null) {
                  for (int i = 0; i < data.size(); i++) {
                    NamedList<Object> dataItem = data.get(i);
                    try {
                      key = (String) dataItem.get("key");
                      field = (String) dataItem.get("field");
                      boolean doClear;
                      doClear = field != null && key != null;
                      doClear = doClear ? recomputeFieldList.get(field) != null
                          : false;
                      doClear = doClear
                          ? recomputeFieldList.get(field).containsKey(key)
                          : false;
                      doClear = doClear ? recomputeFieldList.get(field).get(key)
                          .containsKey(shardAddress) : false;
                      if (doClear) {
                        dataItem.clear();
                        dataItem.add("key", key);
                      }
                    } catch (ClassCastException e) {
                      log.debug(e);
                      dataItem.clear();
                    }
                  }
                }
              } catch (ClassCastException e) {
                log.debug(e);
                // shouldnt happen
              }
              shardResponse.getSolrResponse().setResponse(response);
            }
          }
        }
  
        // parameter
        HashMap<String, ModifiableSolrParams> requestParamList = new HashMap<>();
        for (String shardAddress : shards) {
          ModifiableSolrParams paramsNewRequest = new ModifiableSolrParams();
          int termvectorCounter = 0;
          for (String field : mtasFields.list.keySet()) {
            List<ComponentTermVector> tvList = mtasFields.list
                .get(field).termVectorList;
            if (recomputeFieldList.containsKey(field)) {
              HashMap<String, HashMap<String, MtasDataItemNumberComparator>> recomputeList = recomputeFieldList
                  .get(field);
              if (tvList != null) {
                for (ComponentTermVector tv : tvList) {
                  if (recomputeList.containsKey(tv.key)
                      && recomputeList.get(tv.key).containsKey(shardAddress)) {
                    paramsNewRequest.add(
                        PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                            + NAME_MTAS_TERMVECTOR_BOUNDARY,
                        String.valueOf(recomputeList.get(tv.key).get(shardAddress)
                            .getValue()));
                    paramsNewRequest.add(PARAM_MTAS_TERMVECTOR + "."
                        + termvectorCounter + "." + NAME_MTAS_TERMVECTOR_FIELD,
                        field);
                    paramsNewRequest.add(PARAM_MTAS_TERMVECTOR + "."
                        + termvectorCounter + "." + NAME_MTAS_TERMVECTOR_PREFIX,
                        tv.prefix);
                    paramsNewRequest.add(PARAM_MTAS_TERMVECTOR + "."
                        + termvectorCounter + "." + NAME_MTAS_TERMVECTOR_KEY,
                        tv.key);
                    paramsNewRequest.add(
                        PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                            + NAME_MTAS_TERMVECTOR_NUMBER,
                        String.valueOf(tv.number));
                    if (tv.subComponentFunction.sortType != null) {
                      paramsNewRequest.add(
                          PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                              + NAME_MTAS_TERMVECTOR_SORT_TYPE,
                          tv.subComponentFunction.sortType);
                    }
                    if (tv.subComponentFunction.sortDirection != null) {
                      paramsNewRequest.add(
                          PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                              + NAME_MTAS_TERMVECTOR_SORT_DIRECTION,
                          tv.subComponentFunction.sortDirection);
                    }
                    if (tv.subComponentFunction.type != null) {
                      paramsNewRequest.add(
                          PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                              + NAME_MTAS_TERMVECTOR_TYPE,
                          tv.subComponentFunction.type);
                    }
                    if (tv.distances != null) {
                      int distanceCounter = 0;
                      for (SubComponentDistance distance : tv.distances) {
                        paramsNewRequest.add(
                            PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                                + NAME_MTAS_TERMVECTOR_DISTANCE + "."
                                + distanceCounter + "."
                                + NAME_MTAS_TERMVECTOR_DISTANCE_TYPE,
                            distance.type);
                        paramsNewRequest.add(
                            PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                                + NAME_MTAS_TERMVECTOR_DISTANCE + "."
                                + distanceCounter + "."
                                + NAME_MTAS_TERMVECTOR_DISTANCE_BASE,
                            distance.base);
                        if (distance.key != null) {
                          paramsNewRequest.add(
                              PARAM_MTAS_TERMVECTOR + "." + termvectorCounter
                                  + "." + NAME_MTAS_TERMVECTOR_DISTANCE + "."
                                  + distanceCounter + "."
                                  + NAME_MTAS_TERMVECTOR_DISTANCE_KEY,
                              distance.key);
                        }
                        if (distance.minimum != null) {
                          paramsNewRequest.add(
                              PARAM_MTAS_TERMVECTOR + "." + termvectorCounter
                                  + "." + NAME_MTAS_TERMVECTOR_DISTANCE + "."
                                  + distanceCounter + "."
                                  + NAME_MTAS_TERMVECTOR_DISTANCE_MINIMUM,
                              String.valueOf(distance.minimum));
                        }
                        if (distance.maximum != null) {
                          paramsNewRequest.add(
                              PARAM_MTAS_TERMVECTOR + "." + termvectorCounter
                                  + "." + NAME_MTAS_TERMVECTOR_DISTANCE + "."
                                  + distanceCounter + "."
                                  + NAME_MTAS_TERMVECTOR_DISTANCE_MAXIMUM,
                              String.valueOf(distance.maximum));
                        }
                        if (distance.parameters != null) {
                          for (Entry<String, String> parameter : distance.parameters
                              .entrySet()) {
                            paramsNewRequest.add(
                                PARAM_MTAS_TERMVECTOR + "." + termvectorCounter
                                    + "." + NAME_MTAS_TERMVECTOR_DISTANCE + "."
                                    + distanceCounter + "."
                                    + NAME_MTAS_TERMVECTOR_DISTANCE_PARAMETER
                                    + "." + parameter.getKey(),
                                parameter.getValue());
                          }
                        }
                        distanceCounter++;
                      }
                    }
                    if (tv.functions != null) {
                      int functionCounter = 0;
                      for (SubComponentFunction function : tv.functions) {
                        paramsNewRequest.add(
                            PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                                + NAME_MTAS_TERMVECTOR_FUNCTION + "."
                                + functionCounter + "."
                                + NAME_MTAS_TERMVECTOR_FUNCTION_EXPRESSION,
                            function.expression);
                        paramsNewRequest.add(
                            PARAM_MTAS_TERMVECTOR + "." + termvectorCounter + "."
                                + NAME_MTAS_TERMVECTOR_FUNCTION + "."
                                + functionCounter + "."
                                + NAME_MTAS_TERMVECTOR_FUNCTION_KEY,
                            function.key);
                        if (function.type != null) {
                          paramsNewRequest.add(
                              PARAM_MTAS_TERMVECTOR + "." + termvectorCounter
                                  + "." + NAME_MTAS_TERMVECTOR_FUNCTION + "."
                                  + functionCounter + "."
                                  + NAME_MTAS_TERMVECTOR_FUNCTION_TYPE,
                              function.type);
                        }
                        functionCounter++;
                      }
                    }
                    if (tv.regexp != null) {
                      paramsNewRequest.add(PARAM_MTAS_TERMVECTOR + "."
                          + termvectorCounter + "." + NAME_MTAS_TERMVECTOR_REGEXP,
                          tv.regexp);
                    }
                    termvectorCounter++;
                  }
                }
              }
            }
          }
          if (!paramsNewRequest.getParameterNames().isEmpty()) {
            requestParamList.put(shardAddress, paramsNewRequest);
          }
        }
  
        // new requests
        for (Entry<String, ModifiableSolrParams> entry : requestParamList
            .entrySet()) {
          ShardRequest sreq = new ShardRequest();
          sreq.shards = new String[] { entry.getKey() };
          sreq.purpose = ShardRequest.PURPOSE_PRIVATE;
          sreq.params = entry.getValue();
          sreq.params.add(CommonParams.FQ,
              rb.req.getParams().getParams(CommonParams.FQ));
          sreq.params.add(CommonParams.Q,
              rb.req.getParams().getParams(CommonParams.Q));
          sreq.params.add(CommonParams.CACHE,
              rb.req.getParams().getParams(CommonParams.CACHE));
          sreq.params.add(CommonParams.ROWS, "0");
          sreq.params.add(MtasSolrSearchComponent.PARAM_MTAS, rb.req
              .getOriginalParams().getParams(MtasSolrSearchComponent.PARAM_MTAS));
          sreq.params.add(PARAM_MTAS_TERMVECTOR,
              rb.req.getOriginalParams().getParams(PARAM_MTAS_TERMVECTOR));
          rb.addRequest(searchComponent, sreq);
        }
      }
  
    }