@Override
  protected QueryNode postProcessNode(QueryNode node) throws QueryNodeException {

    if (node instanceof AqpWhiteSpacedQueryNode) {

      QueryConfigHandler config = getQueryConfigHandler();

      if (!config.has(
          AqpAdsabsQueryConfigHandler.ConfigurationKeys.FUNCTION_QUERY_BUILDER_CONFIG)) {
        throw new QueryNodeException(
            new MessageImpl("Invalid configuration", "Missing FunctionQueryBuilder provider"));
      }

      String funcName = getFuncName();
      String subQuery = ((FieldQueryNode) node).getTextAsString();
      String field = ((FieldQueryNode) node).getFieldAsString();
      if (field.equals(
          config.get(AqpAdsabsQueryConfigHandler.ConfigurationKeys.UNFIELDED_SEARCH_FIELD))) {
        field = null;
      }

      if (field != null) {
        subQuery = field + ":" + subQuery;
      }

      if (node.getParent() instanceof SlopQueryNode) {
        subQuery = "(" + subQuery + ")";
        subQuery = subQuery + "~" + ((SlopQueryNode) node.getParent()).getValue();
        if (node.getParent().getParent() instanceof BoostQueryNode) {
          subQuery = subQuery + "^" + ((BoostQueryNode) node.getParent().getParent()).getValue();
        }
      } else if (node.getParent() instanceof BoostQueryNode) {
        subQuery = "(" + subQuery + ")";
        subQuery = subQuery + "^" + ((BoostQueryNode) node.getParent()).getValue();
      }

      node.setTag("subQuery", subQuery);

      AqpFunctionQueryBuilder builder =
          config
              .get(AqpAdsabsQueryConfigHandler.ConfigurationKeys.FUNCTION_QUERY_BUILDER_CONFIG)
              .getBuilder(funcName, (QueryNode) node, config);

      if (builder == null) {
        throw new QueryNodeException(
            new MessageImpl(
                QueryParserMessages.INVALID_SYNTAX, "Unknown function: \"" + funcName + "\""));
      }

      List<OriginalInput> fValues = new ArrayList<OriginalInput>();
      fValues.add(
          new OriginalInput(
              subQuery,
              ((AqpWhiteSpacedQueryNode) node).getBegin(),
              ((AqpWhiteSpacedQueryNode) node).getEnd()));
      return new AqpFunctionQueryNode(funcName, builder, fValues);
    }
    return node;
  }
 public static String getDefaultDatatype(QueryConfigHandler config) {
   if (config.has(KeywordConfigurationKeys.DEFAULT_DATATYPE)) {
     return config.get(KeywordConfigurationKeys.DEFAULT_DATATYPE);
   } else {
     throw new IllegalArgumentException(
         "KeywordConfigurationKeys.DEFAULT_DATATYPE should be set on the ExtendedKeywordQueryConfigHandler");
   }
 }
  @Override
  public Query build(final QueryNode queryNode) throws QueryNodeException {
    if (conf.has(ConciseKeywordQueryConfigHandler.ConciseKeywordConfigurationKeys.ATTRIBUTE)) {
      final String attribute =
          conf.get(ConciseKeywordQueryConfigHandler.ConciseKeywordConfigurationKeys.ATTRIBUTE);
      final String field =
          conf.get(ConciseKeywordQueryConfigHandler.ConciseKeywordConfigurationKeys.FIELD);

      // create the node term query
      NodeTermQuery ntq =
          new NodeTermQuery(
              new Term(field, ConciseNodeBuilderUtil.prepend(builder, attribute, "")));

      // assign the datatype. We must always have a datatype assigned.
      String datatype = DatatypeProcessor.getDefaultDatatype(this.conf);
      ntq.setDatatype(datatype);

      return ntq;
    } else {
      return new BooleanQuery();
    }
  }