docs: public void prepare(ResponseBuilder rb, ComponentFields mtasFields)
        throws IOException {
      Set<String> ids = MtasSolrResultUtil
          .getIdsFromParameters(rb.req.getParams(), PARAM_MTAS_FACET);
      if (!ids.isEmpty()) {
        int tmpCounter = 0;
        String tmpValue;
        String[] fields = new String[ids.size()];
        String[] keys = new String[ids.size()];
        String[][] queryTypes = new String[ids.size()][];
        String[][] queryValues = new String[ids.size()][];
        String[][] queryPrefixes = new String[ids.size()][];
        String[][] queryIgnores = new String[ids.size()][];
        String[][] queryMaximumIgnoreLengths = new String[ids.size()][];
        HashMap<String, String[]>[][] queryVariables = new HashMap[ids.size()][];
        String[][] baseFields = new String[ids.size()][];
        String[][] baseFieldTypes = new String[ids.size()][];
        String[][] baseTypes = new String[ids.size()][];
        Double[][] baseRangeSizes = new Double[ids.size()][];
        Double[][] baseRangeBases = new Double[ids.size()][];
        String[][] baseSortTypes = new String[ids.size()][];
        String[][] baseSortDirections = new String[ids.size()][];
        Integer[][] baseNumbers = new Integer[ids.size()][];
        Double[][] baseMinima = new Double[ids.size()][];
        Double[][] baseMaxima = new Double[ids.size()][];
        String[][][] baseFunctionExpressions = new String[ids.size()][][];
        String[][][] baseFunctionKeys = new String[ids.size()][][];
        String[][][] baseFunctionTypes = new String[ids.size()][][];
        for (String id : ids) {
          fields[tmpCounter] = rb.req.getParams().get(
              PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_FIELD, null);
          keys[tmpCounter] = rb.req.getParams()
              .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_KEY,
                  String.valueOf(tmpCounter))
              .trim();
          Set<String> qIds = MtasSolrResultUtil.getIdsFromParameters(
              rb.req.getParams(),
              PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_QUERY);
          if (!qIds.isEmpty()) {
            int tmpQCounter = 0;
            queryTypes[tmpCounter] = new String[qIds.size()];
            queryValues[tmpCounter] = new String[qIds.size()];
            queryPrefixes[tmpCounter] = new String[qIds.size()];
            queryIgnores[tmpCounter] = new String[qIds.size()];
            queryMaximumIgnoreLengths[tmpCounter] = new String[qIds.size()];
            queryVariables[tmpCounter] = new HashMap[qIds.size()];
            for (String qId : qIds) {
              queryTypes[tmpCounter][tmpQCounter] = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_QUERY
                          + "." + qId + "." + SUBNAME_MTAS_FACET_QUERY_TYPE,
                      null);
              queryValues[tmpCounter][tmpQCounter] = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_QUERY
                          + "." + qId + "." + SUBNAME_MTAS_FACET_QUERY_VALUE,
                      null);
              queryPrefixes[tmpCounter][tmpQCounter] = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_QUERY
                          + "." + qId + "." + SUBNAME_MTAS_FACET_QUERY_PREFIX,
                      null);
              queryIgnores[tmpCounter][tmpQCounter] = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_QUERY
                          + "." + qId + "." + SUBNAME_MTAS_FACET_QUERY_IGNORE,
                      null);
              queryMaximumIgnoreLengths[tmpCounter][tmpQCounter] = rb.req
                  .getParams()
                  .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_QUERY
                      + "." + qId + "."
                      + SUBNAME_MTAS_FACET_QUERY_MAXIMUM_IGNORE_LENGTH, null);
              Set<String> vIds = MtasSolrResultUtil.getIdsFromParameters(
                  rb.req.getParams(),
                  PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_QUERY + "."
                      + qId + "." + SUBNAME_MTAS_FACET_QUERY_VARIABLE);
              queryVariables[tmpCounter][tmpQCounter] = new HashMap<>();
              if (!vIds.isEmpty()) {
                HashMap<String, ArrayList<String>> tmpVariables = new HashMap<>();
                for (String vId : vIds) {
                  String name = rb.req.getParams().get(PARAM_MTAS_FACET + "." + id
                      + "." + NAME_MTAS_FACET_QUERY + "." + qId + "."
                      + SUBNAME_MTAS_FACET_QUERY_VARIABLE + "." + vId + "."
                      + SUBNAME_MTAS_FACET_QUERY_VARIABLE_NAME, null);
                  if (name != null) {
                    if (!tmpVariables.containsKey(name)) {
                      tmpVariables.put(name, new ArrayList<String>());
                    }
                    String value = rb.req.getParams().get(PARAM_MTAS_FACET + "."
                        + id + "." + NAME_MTAS_FACET_QUERY + "." + qId + "."
                        + SUBNAME_MTAS_FACET_QUERY_VARIABLE + "." + vId + "."
                        + SUBNAME_MTAS_FACET_QUERY_VARIABLE_VALUE, null);
                    if (value != null) {
                      ArrayList<String> list = new ArrayList<>();
                      String[] subList = value.split("(?<!\\\\),");
                      for (int i = 0; i < subList.length; i++) {
                        list.add(
                            subList[i].replace("\\,", ",").replace("\\\\", "\\"));
                      }
                      tmpVariables.get(name).addAll(list);
                    }
                  }
                }
                for (Entry<String, ArrayList<String>> entry : tmpVariables
                    .entrySet()) {
                  queryVariables[tmpCounter][tmpQCounter].put(entry.getKey(),
                      entry.getValue()
                          .toArray(new String[entry.getValue().size()]));
                }
              }
              tmpQCounter++;
            }
          } else {
            throw new IOException(
                "no " + NAME_MTAS_FACET_QUERY + " for mtas facet " + id);
          }
          Set<String> bIds = MtasSolrResultUtil.getIdsFromParameters(
              rb.req.getParams(),
              PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE);
          if (!bIds.isEmpty()) {
            int tmpBCounter = 0;
            baseFields[tmpCounter] = new String[bIds.size()];
            baseFieldTypes[tmpCounter] = new String[bIds.size()];
            baseTypes[tmpCounter] = new String[bIds.size()];
            baseRangeSizes[tmpCounter] = new Double[bIds.size()];
            baseRangeBases[tmpCounter] = new Double[bIds.size()];
            baseSortTypes[tmpCounter] = new String[bIds.size()];
            baseSortDirections[tmpCounter] = new String[bIds.size()];
            baseNumbers[tmpCounter] = new Integer[bIds.size()];
            baseMinima[tmpCounter] = new Double[bIds.size()];
            baseMaxima[tmpCounter] = new Double[bIds.size()];
            baseFunctionKeys[tmpCounter] = new String[bIds.size()][];
            baseFunctionExpressions[tmpCounter] = new String[bIds.size()][];
            baseFunctionTypes[tmpCounter] = new String[bIds.size()][];
            for (String bId : bIds) {
              baseFields[tmpCounter][tmpBCounter] = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                          + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_FIELD,
                      null);
              baseFieldTypes[tmpCounter][tmpBCounter] = getFieldType(
                  rb.req.getSchema(), baseFields[tmpCounter][tmpBCounter]);
              baseTypes[tmpCounter][tmpBCounter] = rb.req.getParams()
                  .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                      + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_TYPE, null);
              tmpValue = rb.req.getParams()
                  .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                      + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_RANGE + "."
                      + SUBNAME_MTAS_FACET_BASE_RANGE_SIZE, null);
              baseRangeSizes[tmpCounter][tmpBCounter] = tmpValue == null ? null
                  : Double.parseDouble(tmpValue);
              tmpValue = rb.req.getParams()
                  .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                      + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_RANGE + "."
                      + SUBNAME_MTAS_FACET_BASE_RANGE_BASE, null);
              baseRangeBases[tmpCounter][tmpBCounter] = tmpValue == null ? null
                  : Double.parseDouble(tmpValue);
              baseSortTypes[tmpCounter][tmpBCounter] = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                          + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_SORT_TYPE,
                      null);
              baseSortDirections[tmpCounter][tmpBCounter] = rb.req.getParams()
                  .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                      + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_SORT_DIRECTION,
                      null);
              tmpValue = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                          + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_NUMBER,
                      null);
              baseNumbers[tmpCounter][tmpBCounter] = tmpValue != null
                  ? getPositiveInteger(tmpValue) : null;
              tmpValue = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                          + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_MINIMUM,
                      null);
              baseMinima[tmpCounter][tmpBCounter] = tmpValue != null
                  ? getDouble(tmpValue) : null;
              tmpValue = rb.req.getParams()
                  .get(
                      PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                          + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_MAXIMUM,
                      null);
              baseMaxima[tmpCounter][tmpBCounter] = tmpValue != null
                  ? getDouble(tmpValue) : null;
              Set<String> functionIds = MtasSolrResultUtil.getIdsFromParameters(
                  rb.req.getParams(),
                  PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE + "."
                      + bId + "." + SUBNAME_MTAS_FACET_BASE_FUNCTION);
              baseFunctionExpressions[tmpCounter][tmpBCounter] = new String[functionIds
                  .size()];
              baseFunctionKeys[tmpCounter][tmpBCounter] = new String[functionIds
                  .size()];
              baseFunctionTypes[tmpCounter][tmpBCounter] = new String[functionIds
                  .size()];
              int tmpSubCounter = 0;
              for (String functionId : functionIds) {
                baseFunctionKeys[tmpCounter][tmpBCounter][tmpSubCounter] = rb.req
                    .getParams()
                    .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                        + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_FUNCTION + "."
                        + functionId + "." + SUBNAME_MTAS_FACET_BASE_FUNCTION_KEY,
                        String.valueOf(tmpSubCounter))
                    .trim();
                baseFunctionExpressions[tmpCounter][tmpBCounter][tmpSubCounter] = rb.req
                    .getParams()
                    .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                        + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_FUNCTION + "."
                        + functionId + "."
                        + SUBNAME_MTAS_FACET_BASE_FUNCTION_EXPRESSION, null);
                baseFunctionTypes[tmpCounter][tmpBCounter][tmpSubCounter] = rb.req
                    .getParams()
                    .get(PARAM_MTAS_FACET + "." + id + "." + NAME_MTAS_FACET_BASE
                        + "." + bId + "." + SUBNAME_MTAS_FACET_BASE_FUNCTION + "."
                        + functionId + "."
                        + SUBNAME_MTAS_FACET_BASE_FUNCTION_TYPE, null);
                tmpSubCounter++;
              }
              tmpBCounter++;
            }
          } else {
            throw new IOException(
                "no " + NAME_MTAS_FACET_BASE + " for mtas facet " + id);
          }
          tmpCounter++;
        }
        String uniqueKeyField = rb.req.getSchema().getUniqueKeyField().getName();
        mtasFields.doFacet = true;
        rb.setNeedDocSet(true);
        for (String field : fields) {
          if (field == null || field.isEmpty()) {
            throw new IOException("no (valid) field in mtas facet");
          } else if (!mtasFields.list.containsKey(field)) {
            mtasFields.list.put(field, new ComponentField(uniqueKeyField));
          }
        }
        MtasSolrResultUtil.compareAndCheck(keys, fields, NAME_MTAS_FACET_KEY,
            NAME_MTAS_FACET_FIELD, true);
        for (int i = 0; i < fields.length; i++) {
          ComponentField cf = mtasFields.list.get(fields[i]);
          int queryNumber = queryValues[i].length;
          MtasSpanQuery[] ql = new MtasSpanQuery[queryNumber];
          for (int j = 0; j < queryNumber; j++) {
            Integer maximumIgnoreLength = (queryMaximumIgnoreLengths[i][j] == null)
                ? null : Integer.parseInt(queryMaximumIgnoreLengths[i][j]);
            MtasSpanQuery q = MtasSolrResultUtil.constructQuery(queryValues[i][j],
                queryTypes[i][j], queryPrefixes[i][j], queryVariables[i][j],
                fields[i], queryIgnores[i][j], maximumIgnoreLength);
            // minimize number of queries
            if (cf.spanQueryList.contains(q)) {
              q = cf.spanQueryList.get(cf.spanQueryList.indexOf(q));
            } else {
              cf.spanQueryList.add(q);
            }
            ql[j] = q;
          }
          String key = (keys[i] == null) || (keys[i].isEmpty())
              ? String.valueOf(i) + ":" + fields[i] : keys[i].trim();
          try {
            mtasFields.list.get(fields[i]).facetList.add(new ComponentFacet(ql,
                fields[i], key, baseFields[i], baseFieldTypes[i], baseTypes[i],
                baseRangeSizes[i], baseRangeBases[i], baseSortTypes[i],
                baseSortDirections[i], baseNumbers[i], baseMinima[i],
                baseMaxima[i], baseFunctionKeys[i], baseFunctionExpressions[i],
                baseFunctionTypes[i]));
          } catch (ParseException e) {
            throw new IOException(e.getMessage());
          }
        }
      }
    }