docs: private static int collectGroupUsingSpans(Map<GroupHit, Spans> list,
        List<Integer> docSet, int docBase, int docCounter,
        Map<Integer, List<Match>> matchData, Map<GroupHit, Long> occurencesSum,
        Map<GroupHit, Integer> occurencesN) throws IOException {
      int total = 0;
      if (docCounter + 1 < docSet.size()) {
        // initialize
        int nextDocCounter = docCounter + 1;
        long[] subSum = new long[list.size()];
        int[] subN = new int[list.size()];
        boolean[] newNextDocs = new boolean[list.size()];
        boolean newNextDoc;
        int[] spansNextDoc = new int[list.size()];
        int nextDoc = 0;
        List<Match> matchList;
        GroupHit[] hitList = list.keySet().toArray(new GroupHit[list.size()]);
        Spans[] spansList = new Spans[list.size()];
        boolean[] finishedSpansList = new boolean[list.size()];
        newNextDoc = true;
        // advance spans, find nextDoc
        for (int i = 0; i < hitList.length; i++) {
          newNextDocs[i] = true;
          spansList[i] = list.get(hitList[i]);
          spansNextDoc[i] = spansList[i]
              .advance(docSet.get(nextDocCounter) - docBase);
          nextDoc = (i == 0) ? spansNextDoc[i]
              : Math.min(nextDoc, spansNextDoc[i]);
        }
        // loop over future documents
        while (nextDoc < DocIdSetIterator.NO_MORE_DOCS) {
          // find matches for next document
          while (nextDocCounter < docSet.size()
              && docSet.get(nextDocCounter) < (nextDoc + docBase)) {
            nextDocCounter++;
          }
          // finish, if no more docs in set
          if (nextDocCounter >= docSet.size()) {
            break;
          }
          // go to the matches
          if (docSet.get(nextDocCounter) == nextDoc + docBase) {
            matchList = matchData.get(nextDoc + docBase);
            if (matchList != null && !matchList.isEmpty()) {
              // initialize
              int currentMatchPosition = 0;
              int lastMatchStartPosition = matchList
                  .get(matchList.size() - 1).startPosition;
              ArrayList<Match> newMatchList = new ArrayList<>(matchList.size());
              int currentSpanPosition = Spans.NO_MORE_POSITIONS;
              // check and initialize for each span
              for (int i = 0; i < spansList.length; i++) {
                if (spansList[i].docID() == nextDoc) {
                  int tmpStartPosition = spansList[i].nextStartPosition();
                  if (tmpStartPosition < Spans.NO_MORE_POSITIONS) {
                    finishedSpansList[i] = false;
                  } else {
                    finishedSpansList[i] = true;
                  }
                  // compute position
                  currentSpanPosition = (currentSpanPosition == Spans.NO_MORE_POSITIONS)
                      ? tmpStartPosition
                      : Math.min(currentSpanPosition, tmpStartPosition);
                } else {
                  finishedSpansList[i] = true;
                }
              }
              // loop over matches
              while (currentMatchPosition < matchList.size()
                  && currentSpanPosition < Spans.NO_MORE_POSITIONS) {
  
                if (currentSpanPosition < matchList
                    .get(currentMatchPosition).startPosition) {
                  // do nothing, match not reached
                } else if (currentSpanPosition > lastMatchStartPosition) {
                  // finish, past last match
                  break;
                } else {
                  // advance matches
                  while (currentMatchPosition < matchList.size()
                      && currentSpanPosition > matchList
                          .get(currentMatchPosition).startPosition) {
                    // store current match, not relevant
                    newMatchList.add(matchList.get(currentMatchPosition));
                    currentMatchPosition++;
                  }
                  // equal startPosition
                  while (currentMatchPosition < matchList.size()
                      && currentSpanPosition == matchList
                          .get(currentMatchPosition).startPosition) {
                    // check for each span
                    for (int i = 0; i < spansList.length; i++) {
                      // equal start and end, therefore match
                      if (!finishedSpansList[i] && spansList[i].docID() == nextDoc
                          && spansList[i].startPosition() == matchList
                              .get(currentMatchPosition).startPosition
                          && spansList[i].endPosition() == matchList
                              .get(currentMatchPosition).endPosition) {
                        // administration
                        total++;
                        subSum[i]++;
                        if (newNextDocs[i]) {
                          subN[i]++;
                          newNextDocs[i] = false;
                          newNextDoc = false;
                        }
                      } else if (!finishedSpansList[i]
                          && spansList[i].docID() == nextDoc
                          && spansList[i].startPosition() == matchList
                              .get(currentMatchPosition).startPosition) {
                        // no match, store
                        newMatchList.add(matchList.get(currentMatchPosition));
                      }
                    }
                    currentMatchPosition++;
                  }
                }
  
                // advance spans
                if (currentMatchPosition < matchList.size()) {
                  currentSpanPosition = Spans.NO_MORE_POSITIONS;
                  for (int i = 0; i < spansList.length; i++) {
                    if (!finishedSpansList[i]
                        && (spansList[i].docID() == nextDoc)) {
                      while (!finishedSpansList[i]
                          && spansList[i].startPosition() < matchList
                              .get(currentMatchPosition).startPosition) {
                        int tmpStartPosition = spansList[i].nextStartPosition();
                        if (tmpStartPosition == Spans.NO_MORE_POSITIONS) {
                          finishedSpansList[i] = true;
                        }
                      }
                      if (!finishedSpansList[i]) {
                        currentSpanPosition = (currentSpanPosition == Spans.NO_MORE_POSITIONS)
                            ? spansList[i].startPosition()
                            : Math.min(currentSpanPosition,
                                spansList[i].startPosition());
                      }
                    } else {
                      finishedSpansList[i] = true;
                    }
                  }
                }
              }
              if (!newNextDoc) {
                // add other matches
                while (currentMatchPosition < matchList.size()) {
                  newMatchList.add(matchList.get(currentMatchPosition));
                  currentMatchPosition++;
                }
                // update administration
                if (!newMatchList.isEmpty()) {
                  matchData.put(nextDoc + docBase, newMatchList);
                } else {
                  matchData.put(nextDoc + docBase, null);
                }
              }
            }
          }
          // advance to next document
          nextDocCounter++;
          newNextDoc = true;
          for (int i = 0; i < hitList.length; i++) {
            newNextDocs[i] = true;
          }
          // advance spans
          if (nextDocCounter < docSet.size()) {
            nextDoc = Spans.NO_MORE_DOCS;
            // advance spans
            for (int i = 0; i < hitList.length; i++) {
              if (spansNextDoc[i] < (docSet.get(nextDocCounter) - docBase)) {
                spansNextDoc[i] = spansList[i]
                    .advance(docSet.get(nextDocCounter) - docBase);
              }
              if (spansNextDoc[i] < Spans.NO_MORE_DOCS) {
                nextDoc = (nextDoc == Spans.NO_MORE_DOCS) ? spansNextDoc[i]
                    : Math.min(nextDoc, spansNextDoc[i]);
              }
            }
          }
        }
        // update administration
        for (int i = 0; i < hitList.length; i++) {
          if (subSum[i] > 0 && (occurencesSum.containsKey(hitList[i]))) {
            occurencesSum.put(hitList[i],
                occurencesSum.get(hitList[i]) + subSum[i]);
            occurencesN.put(hitList[i], occurencesN.get(hitList[i]) + subN[i]);
          }
        }
  
      }
      return total;
    }