docs: private static void createKwic(List<ComponentKwic> kwicList,
        Map<MtasSpanQuery, Map<Integer, List<Match>>> spansMatchData,
        List<Integer> docList, String field, int docBase, String uniqueKeyField,
        CodecInfo mtasCodecInfo, IndexSearcher searcher) throws IOException {
      if (kwicList != null) {
        for (ComponentKwic kwic : kwicList) {
          Map<Integer, List<Match>> matchData = spansMatchData.get(kwic.query);
          List<Match> matchList;
          if (kwic.output.equals(ComponentKwic.KWIC_OUTPUT_HIT)) {
            for (int docId : docList) {
              if (matchData != null
                  && (matchList = matchData.get(docId)) != null) {
                // get unique id
                Document doc = searcher.doc(docId,
                    new HashSet<String>(Arrays.asList(uniqueKeyField)));
                IndexableField indxfld = doc.getField(uniqueKeyField);
                // get other doc info
                if (indxfld != null) {
                  kwic.uniqueKey.put(docId, indxfld.stringValue());
                }
                kwic.subTotal.put(docId, matchList.size());
                IndexDoc mDoc = mtasCodecInfo.getDoc(field, (docId - docBase));
                if (mDoc != null) {
                  kwic.minPosition.put(docId, mDoc.minPosition);
                  kwic.maxPosition.put(docId, mDoc.maxPosition);
                }
                // kwiclist
                List<KwicHit> kwicItemList = new ArrayList<>();
                int number = 0;
                for (Match m : matchList) {
                  if (kwic.number != null
                      && number >= (kwic.start + kwic.number)) {
                    break;
                  }
                  if (number >= kwic.start) {
                    int startPosition = m.startPosition;
                    int endPosition = m.endPosition - 1;
                    List<MtasTreeHit<String>> terms = mtasCodecInfo
                        .getPositionedTermsByPrefixesAndPositionRange(field,
                            (docId - docBase), kwic.prefixes,
                            Math.max(mDoc.minPosition, startPosition - kwic.left),
                            Math.min(mDoc.maxPosition, endPosition + kwic.right));
                    // construct hit
                    Map<Integer, List<String>> kwicListHits = new HashMap<>();
                    for (int position = Math.max(mDoc.minPosition,
                        startPosition - kwic.left); position <= Math.min(
                            mDoc.maxPosition,
                            endPosition + kwic.right); position++) {
                      kwicListHits.put(position, new ArrayList<String>());
                    }
                    List<String> termList;
                    for (MtasTreeHit<String> term : terms) {
                      for (int position = Math.max((startPosition - kwic.left),
                          term.startPosition); position <= Math.min(
                              (endPosition + kwic.right),
                              term.endPosition); position++) {
                        termList = kwicListHits.get(position);
                        termList.add(term.data);
                      }
                    }
                    kwicItemList.add(new KwicHit(m, kwicListHits));
                  }
                  number++;
                }
                kwic.hits.put(docId, kwicItemList);
              }
            }
          } else if (kwic.output.equals(ComponentKwic.KWIC_OUTPUT_TOKEN)) {
            for (int docId : docList) {
              if (matchData != null
                  && (matchList = matchData.get(docId)) != null) {
                // get unique id
                Document doc = searcher.doc(docId,
                    new HashSet<String>(Arrays.asList(uniqueKeyField)));
                // get other doc info
                IndexableField indxfld = doc.getField(uniqueKeyField);
                if (indxfld != null) {
                  kwic.uniqueKey.put(docId, indxfld.stringValue());
                }
                kwic.subTotal.put(docId, matchList.size());
                IndexDoc mDoc = mtasCodecInfo.getDoc(field, (docId - docBase));
                if (mDoc != null) {
                  kwic.minPosition.put(docId, mDoc.minPosition);
                  kwic.maxPosition.put(docId, mDoc.maxPosition);
                  List<KwicToken> kwicItemList = new ArrayList<>();
                  int number = 0;
                  for (Match m : matchList) {
                    if (kwic.number != null
                        && number >= (kwic.start + kwic.number)) {
                      break;
                    }
                    if (number >= kwic.start) {
                      int startPosition = m.startPosition;
                      int endPosition = m.endPosition - 1;
                      List<MtasTokenString> tokens;
                      tokens = mtasCodecInfo.getPrefixFilteredObjectsByPositions(
                          field, (docId - docBase), kwic.prefixes,
                          Math.max(mDoc.minPosition, startPosition - kwic.left),
                          Math.min(mDoc.maxPosition, endPosition + kwic.right));
                      kwicItemList.add(new KwicToken(m, tokens));
                    }
                    number++;
                  }
                  kwic.tokens.put(docId, kwicItemList);
                }
              }
            }
          }
        }
      }
    }