Example usage for org.apache.lucene.queries.function.valuesource QueryValueSource QueryValueSource

List of usage examples for org.apache.lucene.queries.function.valuesource QueryValueSource QueryValueSource

Introduction

In this page you can find the example usage for org.apache.lucene.queries.function.valuesource QueryValueSource QueryValueSource.

Prototype

public QueryValueSource(Query q, float defVal) 

Source Link

Usage

From source file:org.apache.solr.handler.component.StatsField.java

License:Apache License

/**
 * Inspects a {@link Query} to see if it directly maps to a {@link ValueSource},
 * and if so returns it -- otherwise wraps it as needed.
 *
 * @param q Query whose scores we have been asked to compute stats of
 * @returns a ValueSource to use for computing the stats
 *//*  ww w. j  a  v  a 2 s .c om*/
private static ValueSource extractValueSource(Query q) {
    return (q instanceof FunctionQuery) ?
    // Common case: we're wrapping a func, so we can directly pull out ValueSource
            ((FunctionQuery) q).getValueSource() :
            // asked to compute stats over a query, wrap it up as a ValueSource
            new QueryValueSource(q, 0.0F);
}

From source file:org.apache.solr.search.AqpExtendedDismaxQParserPlugin.java

License:Apache License

/**
 * Parses all multiplicative boosts//  w ww  .j a  v  a 2 s.  c  om
 */
protected List<ValueSource> getMultiplicativeBoosts() throws SyntaxError {
    List<ValueSource> boosts = new ArrayList<>();
    if (config.hasMultiplicativeBoosts()) {
        for (String boostStr : config.multBoosts) {
            if (boostStr == null || boostStr.length() == 0)
                continue;
            Query boost = subQuery(boostStr, FunctionQParserPlugin.NAME).getQuery();
            ValueSource vs;
            if (boost instanceof FunctionQuery) {
                vs = ((FunctionQuery) boost).getValueSource();
            } else {
                vs = new QueryValueSource(boost, 1.0f);
            }
            boosts.add(vs);
        }
    }
    return boosts;
}

From source file:org.apache.solr.search.BoostQParserPlugin.java

License:Apache License

@Override
public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
    return new QParser(qstr, localParams, params, req) {
        QParser baseParser;/*from w  w w.j  av  a  2  s  .  com*/
        ValueSource vs;
        String b;

        @Override
        public Query parse() throws SyntaxError {
            b = localParams.get(BOOSTFUNC);
            baseParser = subQuery(localParams.get(QueryParsing.V), null);
            Query q = baseParser.getQuery();

            if (b == null)
                return q;
            Query bq = subQuery(b, FunctionQParserPlugin.NAME).getQuery();
            if (bq instanceof FunctionQuery) {
                vs = ((FunctionQuery) bq).getValueSource();
            } else {
                vs = new QueryValueSource(bq, 0.0f);
            }
            return new BoostedQuery(q, vs);
        }

        @Override
        public String[] getDefaultHighlightFields() {
            return baseParser.getDefaultHighlightFields();
        }

        @Override
        public Query getHighlightQuery() throws SyntaxError {
            return baseParser.getHighlightQuery();
        }

        @Override
        public void addDebugInfo(NamedList<Object> debugInfo) {
            // encapsulate base debug info in a sub-list?
            baseParser.addDebugInfo(debugInfo);
            debugInfo.add("boost_str", b);
            debugInfo.add("boost_parsed", vs);
        }
    };
}

From source file:org.apache.solr.search.ExtendedDismaxQParser.java

License:Apache License

/**
 * Parses all multiplicative boosts/* ww w .  jav a 2  s . c  o  m*/
 */
protected List<ValueSource> getMultiplicativeBoosts() throws SyntaxError {
    List<ValueSource> boosts = new ArrayList<ValueSource>();
    if (config.hasMultiplicativeBoosts()) {
        for (String boostStr : config.multBoosts) {
            if (boostStr == null || boostStr.length() == 0)
                continue;
            Query boost = subQuery(boostStr, FunctionQParserPlugin.NAME).getQuery();
            ValueSource vs;
            if (boost instanceof FunctionQuery) {
                vs = ((FunctionQuery) boost).getValueSource();
            } else {
                vs = new QueryValueSource(boost, 1.0f);
            }
            boosts.add(vs);
        }
    }
    return boosts;
}

From source file:org.apache.solr.search.FunctionQParser.java

License:Apache License

/**
 * Parse an individual value source.//from   w  w w.  ja  v a  2s . c o  m
 * 
 * @param doConsumeDelimiter whether to consume a delimiter following the ValueSource  
 */
protected ValueSource parseValueSource(boolean doConsumeDelimiter) throws SyntaxError {
    ValueSource valueSource;

    int ch = sp.peek();
    if (ch >= '0' && ch <= '9' || ch == '.' || ch == '+' || ch == '-') {
        Number num = sp.getNumber();
        if (num instanceof Long) {
            valueSource = new LongConstValueSource(num.longValue());
        } else if (num instanceof Double) {
            valueSource = new DoubleConstValueSource(num.doubleValue());
        } else {
            // shouldn't happen
            valueSource = new ConstValueSource(num.floatValue());
        }
    } else if (ch == '"' || ch == '\'') {
        valueSource = new LiteralValueSource(sp.getQuotedString());
    } else if (ch == '$') {
        sp.pos++;
        String param = sp.getId();
        String val = getParam(param);
        if (val == null) {
            throw new SyntaxError("Missing param " + param + " while parsing function '" + sp.val + "'");
        }

        QParser subParser = subQuery(val, "func");
        if (subParser instanceof FunctionQParser) {
            ((FunctionQParser) subParser).setParseMultipleSources(true);
        }
        Query subQuery = subParser.getQuery();
        if (subQuery instanceof FunctionQuery) {
            valueSource = ((FunctionQuery) subQuery).getValueSource();
        } else {
            valueSource = new QueryValueSource(subQuery, 0.0f);
        }

        /***
         // dereference *simple* argument (i.e., can't currently be a function)
         // In the future we could support full function dereferencing via a stack of ValueSource (or StringParser) objects
        ch = val.length()==0 ? '\0' : val.charAt(0);
                
        if (ch>='0' && ch<='9'  || ch=='.' || ch=='+' || ch=='-') {
          QueryParsing.StrParser sp = new QueryParsing.StrParser(val);
          Number num = sp.getNumber();
          if (num instanceof Long) {
            valueSource = new LongConstValueSource(num.longValue());
          } else if (num instanceof Double) {
            valueSource = new DoubleConstValueSource(num.doubleValue());
          } else {
            // shouldn't happen
            valueSource = new ConstValueSource(num.floatValue());
          }
        } else if (ch == '"' || ch == '\'') {
          QueryParsing.StrParser sp = new QueryParsing.StrParser(val);
          val = sp.getQuotedString();
          valueSource = new LiteralValueSource(val);
        } else {
          if (val.length()==0) {
            valueSource = new LiteralValueSource(val);
          } else {
            String id = val;
            SchemaField f = req.getSchema().getField(id);
            valueSource = f.getType().getValueSource(f, this);
          }
        }
         ***/

    } else {

        String id = sp.getId();
        if (sp.opt("(")) {
            // a function... look it up.
            ValueSourceParser argParser = req.getCore().getValueSourceParser(id);
            if (argParser == null) {
                throw new SyntaxError("Unknown function " + id + " in FunctionQuery(" + sp + ")");
            }
            valueSource = argParser.parse(this);
            sp.expect(")");
        } else {
            if ("true".equals(id)) {
                valueSource = new BoolConstValueSource(true);
            } else if ("false".equals(id)) {
                valueSource = new BoolConstValueSource(false);
            } else {
                SchemaField f = req.getSchema().getField(id);
                valueSource = f.getType().getValueSource(f, this);
            }
        }

    }

    if (doConsumeDelimiter)
        consumeArgumentDelimiter();

    return valueSource;
}

From source file:org.apache.solr.search.FunctionRangeQParserPlugin.java

License:Apache License

@Override
public QParser createParser(String qstr, SolrParams localParams, SolrParams params, SolrQueryRequest req) {
    return new QParser(qstr, localParams, params, req) {
        ValueSource vs;// www.j a v a2s . c  o m
        String funcStr;

        @Override
        public Query parse() throws SyntaxError {
            funcStr = localParams.get(QueryParsing.V, null);
            Query funcQ = subQuery(funcStr, FunctionQParserPlugin.NAME).getQuery();
            if (funcQ instanceof FunctionQuery) {
                vs = ((FunctionQuery) funcQ).getValueSource();
            } else {
                vs = new QueryValueSource(funcQ, 0.0f);
            }

            String l = localParams.get("l");
            String u = localParams.get("u");
            boolean includeLower = localParams.getBool("incl", true);
            boolean includeUpper = localParams.getBool("incu", true);

            // TODO: add a score=val option to allow score to be the value
            ValueSourceRangeFilter rf = new ValueSourceRangeFilter(vs, l, u, includeLower, includeUpper);
            FunctionRangeQuery frq = new FunctionRangeQuery(rf);
            return frq;
        }
    };
}

From source file:org.apache.solr.search.Grouping.java

License:Apache License

public void addFunctionCommand(String groupByStr, SolrQueryRequest request) throws SyntaxError {
    QParser parser = QParser.getParser(groupByStr, "func", request);
    Query q = parser.getQuery();//w  w  w.  j  a  v  a  2 s . c  om
    final Grouping.Command gc;
    if (q instanceof FunctionQuery) {
        ValueSource valueSource = ((FunctionQuery) q).getValueSource();
        if (valueSource instanceof StrFieldSource) {
            String field = ((StrFieldSource) valueSource).getField();
            CommandField commandField = new CommandField();
            commandField.groupBy = field;
            gc = commandField;
        } else {
            CommandFunc commandFunc = new CommandFunc();
            commandFunc.groupBy = valueSource;
            gc = commandFunc;
        }
    } else {
        CommandFunc commandFunc = new CommandFunc();
        commandFunc.groupBy = new QueryValueSource(q, 0.0f);
        gc = commandFunc;
    }
    gc.groupSort = groupSort;
    gc.key = groupByStr;
    gc.numGroups = limitDefault;
    gc.docsPerGroup = docsPerGroupDefault;
    gc.groupOffset = groupOffsetDefault;
    gc.offset = cmd.getOffset();
    gc.sort = sort;
    gc.format = defaultFormat;
    gc.totalCount = defaultTotalCount;

    if (main) {
        gc.main = true;
        gc.format = Grouping.Format.simple;
    }

    if (gc.format == Grouping.Format.simple) {
        gc.groupOffset = 0; // doesn't make sense
    }

    commands.add(gc);
}

From source file:org.apache.solr.search.QueryParsing.java

License:Apache License

/**
 * Returns null if the sortSpec is the standard sort desc.
 * <p/>//w  ww  .  jav  a  2 s . co m
 * <p>
 * The form of the sort specification string currently parsed is:
 * </p>
 * <pre>
 * SortSpec ::= SingleSort [, SingleSort]*
 * SingleSort ::= &lt;fieldname&gt; SortDirection
 * SortDirection ::= top | desc | bottom | asc
 * </pre>
 * Examples:
 * <pre>
 *   score desc               #normal sort by score (will return null)
 *   weight bottom            #sort by weight ascending
 *   weight desc              #sort by weight descending
 *   height desc,weight desc  #sort by height descending, and use weight descending to break any ties
 *   height desc,weight asc   #sort by height descending, using weight ascending as a tiebreaker
 * </pre>
 */
public static Sort parseSort(String sortSpec, SolrQueryRequest req) {
    if (sortSpec == null || sortSpec.length() == 0)
        return null;
    List<SortField> lst = new ArrayList<SortField>(4);

    try {

        StrParser sp = new StrParser(sortSpec);
        while (sp.pos < sp.end) {
            sp.eatws();

            final int start = sp.pos;

            // short circuit test for a really simple field name
            String field = sp.getId(null);
            Exception qParserException = null;

            if (field == null || !Character.isWhitespace(sp.peekChar())) {
                // let's try it as a function instead
                field = null;
                String funcStr = sp.val.substring(start);

                QParser parser = QParser.getParser(funcStr, FunctionQParserPlugin.NAME, req);
                Query q = null;
                try {
                    if (parser instanceof FunctionQParser) {
                        FunctionQParser fparser = (FunctionQParser) parser;
                        fparser.setParseMultipleSources(false);
                        fparser.setParseToEnd(false);

                        q = fparser.getQuery();

                        if (fparser.localParams != null) {
                            if (fparser.valFollowedParams) {
                                // need to find the end of the function query via the string parser
                                int leftOver = fparser.sp.end - fparser.sp.pos;
                                sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
                            } else {
                                // the value was via the "v" param in localParams, so we need to find
                                // the end of the local params themselves to pick up where we left off
                                sp.pos = start + fparser.localParamsEnd;
                            }
                        } else {
                            // need to find the end of the function query via the string parser
                            int leftOver = fparser.sp.end - fparser.sp.pos;
                            sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
                        }
                    } else {
                        // A QParser that's not for function queries.
                        // It must have been specified via local params.
                        q = parser.getQuery();

                        assert parser.getLocalParams() != null;
                        sp.pos = start + parser.localParamsEnd;
                    }

                    Boolean top = sp.getSortDirection();
                    if (null != top) {
                        // we have a Query and a valid direction
                        if (q instanceof FunctionQuery) {
                            lst.add(((FunctionQuery) q).getValueSource().getSortField(top));
                        } else {
                            lst.add((new QueryValueSource(q, 0.0f)).getSortField(top));
                        }
                        continue;
                    }
                } catch (Exception e) {
                    // hang onto this in case the string isn't a full field name either
                    qParserException = e;
                }
            }

            // if we made it here, we either have a "simple" field name,
            // or there was a problem parsing the string as a complex func/quer

            if (field == null) {
                // try again, simple rules for a field name with no whitespace
                sp.pos = start;
                field = sp.getSimpleString();
            }
            Boolean top = sp.getSortDirection();
            if (null == top) {
                throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
                        "Can't determine a Sort Order (asc or desc) in sort spec " + sp);
            }

            if (SCORE.equals(field)) {
                if (top) {
                    lst.add(SortField.FIELD_SCORE);
                } else {
                    lst.add(new SortField(null, SortField.Type.SCORE, true));
                }
            } else if (DOCID.equals(field)) {
                lst.add(new SortField(null, SortField.Type.DOC, top));
            } else {
                // try to find the field
                SchemaField sf = req.getSchema().getFieldOrNull(field);
                if (null == sf) {
                    if (null != qParserException) {
                        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
                                "sort param could not be parsed as a query, and is not a "
                                        + "field that exists in the index: " + field,
                                qParserException);
                    }
                    throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
                            "sort param field can't be found: " + field);
                }
                lst.add(sf.getSortField(top));
            }
        }

    } catch (SyntaxError e) {
        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "error in sort: " + sortSpec, e);
    }

    // normalize a sort on score desc to null
    if (lst.size() == 1 && lst.get(0) == SortField.FIELD_SCORE) {
        return null;
    }

    return new Sort(lst.toArray(new SortField[lst.size()]));
}

From source file:org.apache.solr.search.ReturnFields.java

License:Apache License

private void add(String fl, NamedList<String> rename, DocTransformers augmenters, SolrQueryRequest req) {
    if (fl == null) {
        return;//from ww  w .  java  2 s .  co m
    }
    try {
        QueryParsing.StrParser sp = new QueryParsing.StrParser(fl);

        for (;;) {
            sp.opt(',');
            sp.eatws();
            if (sp.pos >= sp.end)
                break;

            int start = sp.pos;

            // short circuit test for a really simple field name
            String key = null;
            String field = getFieldName(sp);
            char ch = sp.ch();

            if (field != null) {
                if (sp.opt(':')) {
                    // this was a key, not a field name
                    key = field;
                    field = null;
                    sp.eatws();
                    start = sp.pos;
                } else {
                    if (ch == ' ' || ch == ',' || ch == 0) {
                        addField(field, key, augmenters, req);
                        continue;
                    }
                    // an invalid field name... reset the position pointer to retry
                    sp.pos = start;
                    field = null;
                }
            }

            if (key != null) {
                // we read "key : "
                field = sp.getId(null);
                ch = sp.ch();
                if (field != null && (ch == ' ' || ch == ',' || ch == 0)) {
                    rename.add(field, key);
                    addField(field, key, augmenters, req);
                    continue;
                }
                // an invalid field name... reset the position pointer to retry
                sp.pos = start;
                field = null;
            }

            if (field == null) {
                // We didn't find a simple name, so let's see if it's a globbed field name.
                // Globbing only works with field names of the recommended form (roughly like java identifiers)

                field = sp.getGlobbedId(null);
                ch = sp.ch();
                if (field != null && (ch == ' ' || ch == ',' || ch == 0)) {
                    // "*" looks and acts like a glob, but we give it special treatment
                    if ("*".equals(field)) {
                        _wantsAllFields = true;
                    } else {
                        globs.add(field);
                    }
                    continue;
                }

                // an invalid glob
                sp.pos = start;
            }

            String funcStr = sp.val.substring(start);

            // Is it an augmenter of the form [augmenter_name foo=1 bar=myfield]?
            // This is identical to localParams syntax except it uses [] instead of {!}

            if (funcStr.startsWith("[")) {
                Map<String, String> augmenterArgs = new HashMap<String, String>();
                int end = QueryParsing.parseLocalParams(funcStr, 0, augmenterArgs, req.getParams(), "[", ']');
                sp.pos += end;

                // [foo] is short for [type=foo] in localParams syntax
                String augmenterName = augmenterArgs.remove("type");
                String disp = key;
                if (disp == null) {
                    disp = '[' + augmenterName + ']';
                }

                TransformerFactory factory = req.getCore().getTransformerFactory(augmenterName);
                if (factory != null) {
                    MapSolrParams augmenterParams = new MapSolrParams(augmenterArgs);
                    augmenters.addTransformer(factory.create(disp, augmenterParams, req));
                } else {
                    // unknown transformer?
                }
                addField(field, disp, augmenters, req);
                continue;
            }

            // let's try it as a function instead
            QParser parser = QParser.getParser(funcStr, FunctionQParserPlugin.NAME, req);
            Query q = null;
            ValueSource vs = null;

            try {
                if (parser instanceof FunctionQParser) {
                    FunctionQParser fparser = (FunctionQParser) parser;
                    fparser.setParseMultipleSources(false);
                    fparser.setParseToEnd(false);

                    q = fparser.getQuery();

                    if (fparser.localParams != null) {
                        if (fparser.valFollowedParams) {
                            // need to find the end of the function query via the string parser
                            int leftOver = fparser.sp.end - fparser.sp.pos;
                            sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
                        } else {
                            // the value was via the "v" param in localParams, so we need to find
                            // the end of the local params themselves to pick up where we left off
                            sp.pos = start + fparser.localParamsEnd;
                        }
                    } else {
                        // need to find the end of the function query via the string parser
                        int leftOver = fparser.sp.end - fparser.sp.pos;
                        sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
                    }
                } else {
                    // A QParser that's not for function queries.
                    // It must have been specified via local params.
                    q = parser.getQuery();

                    assert parser.getLocalParams() != null;
                    sp.pos = start + parser.localParamsEnd;
                }

                if (q instanceof FunctionQuery) {
                    vs = ((FunctionQuery) q).getValueSource();
                } else {
                    vs = new QueryValueSource(q, 0.0f);
                }

                if (key == null) {
                    SolrParams localParams = parser.getLocalParams();
                    if (localParams != null) {
                        key = localParams.get("key");
                    }
                    if (key == null) {
                        // use the function name itself as the field name
                        key = sp.val.substring(start, sp.pos);
                    }
                }

                if (key == null) {
                    key = funcStr;
                }
                okFieldNames.add(key);
                okFieldNames.add(funcStr);
                augmenters.addTransformer(new ValueSourceAugmenter(key, parser, vs));
            } catch (ParseException e) {
                // try again, simple rules for a field name with no whitespace
                sp.pos = start;
                field = sp.getSimpleString();

                if (req.getSchema().getFieldOrNull(field) != null) {
                    // OK, it was an oddly named field
                    fields.add(field);
                    if (key != null) {
                        rename.add(field, key);
                    }
                } else {
                    throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
                            "Error parsing fieldname: " + e.getMessage(), e);
                }
            }

            // end try as function

        } // end for(;;)
    } catch (ParseException e) {
        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error parsing fieldname", e);
    }
}

From source file:org.apache.solr.search.SolrReturnFields.java

License:Apache License

private void add(String fl, NamedList<String> rename, DocTransformers augmenters, SolrQueryRequest req) {
    if (fl == null) {
        return;/*from   w ww . ja  v a  2  s  .co m*/
    }
    try {
        QueryParsing.StrParser sp = new QueryParsing.StrParser(fl);

        for (;;) {
            sp.opt(',');
            sp.eatws();
            if (sp.pos >= sp.end)
                break;

            int start = sp.pos;

            // short circuit test for a really simple field name
            String key = null;
            String field = getFieldName(sp);
            char ch = sp.ch();

            if (field != null) {
                if (sp.opt(':')) {
                    // this was a key, not a field name
                    key = field;
                    field = null;
                    sp.eatws();
                    start = sp.pos;
                } else {
                    if (Character.isWhitespace(ch) || ch == ',' || ch == 0) {
                        addField(field, key, augmenters, req);
                        continue;
                    }
                    // an invalid field name... reset the position pointer to retry
                    sp.pos = start;
                    field = null;
                }
            }

            if (key != null) {
                // we read "key : "
                field = sp.getId(null);
                ch = sp.ch();
                if (field != null && (Character.isWhitespace(ch) || ch == ',' || ch == 0)) {
                    rename.add(field, key);
                    addField(field, key, augmenters, req);
                    continue;
                }
                // an invalid field name... reset the position pointer to retry
                sp.pos = start;
                field = null;
            }

            if (field == null) {
                // We didn't find a simple name, so let's see if it's a globbed field name.
                // Globbing only works with field names of the recommended form (roughly like java identifiers)

                field = sp.getGlobbedId(null);
                ch = sp.ch();
                if (field != null && (Character.isWhitespace(ch) || ch == ',' || ch == 0)) {
                    // "*" looks and acts like a glob, but we give it special treatment
                    if ("*".equals(field)) {
                        _wantsAllFields = true;
                    } else {
                        globs.add(field);
                    }
                    continue;
                }

                // an invalid glob
                sp.pos = start;
            }

            String funcStr = sp.val.substring(start);

            // Is it an augmenter of the form [augmenter_name foo=1 bar=myfield]?
            // This is identical to localParams syntax except it uses [] instead of {!}

            if (funcStr.startsWith("[")) {
                Map<String, String> augmenterArgs = new HashMap<String, String>();
                int end = QueryParsing.parseLocalParams(funcStr, 0, augmenterArgs, req.getParams(), "[", ']');
                sp.pos += end;

                // [foo] is short for [type=foo] in localParams syntax
                String augmenterName = augmenterArgs.remove("type");
                String disp = key;
                if (disp == null) {
                    disp = '[' + augmenterName + ']';
                }

                TransformerFactory factory = req.getCore().getTransformerFactory(augmenterName);
                if (factory != null) {
                    MapSolrParams augmenterParams = new MapSolrParams(augmenterArgs);
                    augmenters.addTransformer(factory.create(disp, augmenterParams, req));
                } else {
                    // unknown transformer?
                }
                addField(field, disp, augmenters, req);
                continue;
            }

            // let's try it as a function instead
            QParser parser = QParser.getParser(funcStr, FunctionQParserPlugin.NAME, req);
            Query q = null;
            ValueSource vs = null;

            try {
                if (parser instanceof FunctionQParser) {
                    FunctionQParser fparser = (FunctionQParser) parser;
                    fparser.setParseMultipleSources(false);
                    fparser.setParseToEnd(false);

                    q = fparser.getQuery();

                    if (fparser.localParams != null) {
                        if (fparser.valFollowedParams) {
                            // need to find the end of the function query via the string parser
                            int leftOver = fparser.sp.end - fparser.sp.pos;
                            sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
                        } else {
                            // the value was via the "v" param in localParams, so we need to find
                            // the end of the local params themselves to pick up where we left off
                            sp.pos = start + fparser.localParamsEnd;
                        }
                    } else {
                        // need to find the end of the function query via the string parser
                        int leftOver = fparser.sp.end - fparser.sp.pos;
                        sp.pos = sp.end - leftOver; // reset our parser to the same amount of leftover
                    }
                } else {
                    // A QParser that's not for function queries.
                    // It must have been specified via local params.
                    q = parser.getQuery();

                    assert parser.getLocalParams() != null;
                    sp.pos = start + parser.localParamsEnd;
                }

                if (q instanceof FunctionQuery) {
                    vs = ((FunctionQuery) q).getValueSource();
                } else {
                    vs = new QueryValueSource(q, 0.0f);
                }

                if (key == null) {
                    SolrParams localParams = parser.getLocalParams();
                    if (localParams != null) {
                        key = localParams.get("key");
                    }
                    if (key == null) {
                        // use the function name itself as the field name
                        key = sp.val.substring(start, sp.pos);
                    }
                }

                if (key == null) {
                    key = funcStr;
                }
                okFieldNames.add(key);
                okFieldNames.add(funcStr);
                augmenters.addTransformer(new ValueSourceAugmenter(key, parser, vs));
            } catch (SyntaxError e) {
                // try again, simple rules for a field name with no whitespace
                sp.pos = start;
                field = sp.getSimpleString();

                if (req.getSchema().getFieldOrNull(field) != null) {
                    // OK, it was an oddly named field
                    fields.add(field);
                    if (key != null) {
                        rename.add(field, key);
                    }
                } else {
                    throw new SolrException(SolrException.ErrorCode.BAD_REQUEST,
                            "Error parsing fieldname: " + e.getMessage(), e);
                }
            }

            // end try as function

        } // end for(;;)
    } catch (SyntaxError e) {
        throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Error parsing fieldname", e);
    }
}