@Override
  public Filter parse(QueryParseContext parseContext) throws IOException, QueryParsingException {
    XContentParser parser = parseContext.parser();

    XContentParser.Token token;

    boolean cache = false; // no need to cache it by default, changes a lot?
    CacheKeyFilter.Key cacheKey = null;
    // also, when caching, since its isCacheable is false, will result in loading all bit set...
    String script = null;
    String scriptLang = null;
    Map<String, Object> params = null;

    String filterName = null;
    String currentFieldName = null;
    while ((token = parser.nextToken()) != XContentParser.Token.END_OBJECT) {
      if (token == XContentParser.Token.FIELD_NAME) {
        currentFieldName = parser.currentName();
      } else if (token == XContentParser.Token.START_OBJECT) {
        if ("params".equals(currentFieldName)) {
          params = parser.map();
        } else {
          throw new QueryParsingException(
              parseContext.index(), "[script] filter does not support [" + currentFieldName + "]");
        }
      } else if (token.isValue()) {
        if ("script".equals(currentFieldName)) {
          script = parser.text();
        } else if ("lang".equals(currentFieldName)) {
          scriptLang = parser.text();
        } else if ("_name".equals(currentFieldName)) {
          filterName = parser.text();
        } else if ("_cache".equals(currentFieldName)) {
          cache = parser.booleanValue();
        } else if ("_cache_key".equals(currentFieldName) || "_cacheKey".equals(currentFieldName)) {
          cacheKey = new CacheKeyFilter.Key(parser.text());
        } else {
          throw new QueryParsingException(
              parseContext.index(), "[script] filter does not support [" + currentFieldName + "]");
        }
      }
    }

    if (script == null) {
      throw new QueryParsingException(
          parseContext.index(), "script must be provided with a [script] filter");
    }
    if (params == null) {
      params = newHashMap();
    }

    Filter filter =
        new ScriptFilter(
            scriptLang, script, params, parseContext.scriptService(), parseContext.lookup());
    if (cache) {
      filter = parseContext.cacheFilter(filter, cacheKey);
    }
    if (filterName != null) {
      parseContext.addNamedFilter(filterName, filter);
    }
    return filter;
  }