Search in sources :

Example 6 with ValueSource

use of org.apache.lucene.queries.function.ValueSource in project lucene-solr by apache.

the class StatsCollectorSupplierFactory method buildNumericSource.

/**
   * Recursively parses and breaks down the expression string to build a numeric ValueSource.
   * 
   * @param schema The schema to pull fields from.
   * @param expressionString The expression string to build a ValueSource from.
   * @return The value source represented by the given expressionString
   */
private static ValueSource buildNumericSource(IndexSchema schema, String expressionString) {
    int paren = expressionString.indexOf('(');
    String[] arguments;
    String operands;
    if (paren < 0) {
        return buildFieldSource(schema, expressionString, NUMBER_TYPE);
    } else {
        try {
            operands = expressionString.substring(paren + 1, expressionString.lastIndexOf(')')).trim();
        } catch (Exception e) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "Missing closing parenthesis in [" + expressionString + "]");
        }
        arguments = ExpressionFactory.getArguments(operands);
    }
    String operation = expressionString.substring(0, paren).trim();
    if (operation.equals(AnalyticsParams.CONSTANT_NUMBER)) {
        if (arguments.length != 1) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The constant number declaration [" + expressionString + "] does not have exactly 1 argument.");
        }
        return new ConstDoubleSource(Double.parseDouble(arguments[0]));
    } else if (operation.equals(AnalyticsParams.NEGATE)) {
        if (arguments.length != 1) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The negate operation [" + expressionString + "] does not have exactly 1 argument.");
        }
        ValueSource argSource = buildNumericSource(schema, arguments[0]);
        if (argSource == null) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The operation \"" + AnalyticsParams.NEGATE + "\" requires a numeric field or operation as argument. \"" + arguments[0] + "\" is not a numeric field or operation.");
        }
        return new NegateDoubleFunction(argSource);
    } else if (operation.equals(AnalyticsParams.ABSOLUTE_VALUE)) {
        if (arguments.length != 1) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The absolute value operation [" + expressionString + "] does not have exactly 1 argument.");
        }
        ValueSource argSource = buildNumericSource(schema, arguments[0]);
        if (argSource == null) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The operation \"" + AnalyticsParams.NEGATE + "\" requires a numeric field or operation as argument. \"" + arguments[0] + "\" is not a numeric field or operation.");
        }
        return new AbsoluteValueDoubleFunction(argSource);
    } else if (operation.equals(AnalyticsParams.FILTER)) {
        return buildFilterSource(schema, operands, NUMBER_TYPE);
    }
    List<ValueSource> subExpressions = new ArrayList<>();
    for (String argument : arguments) {
        ValueSource argSource = buildNumericSource(schema, argument);
        if (argSource == null) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The operation \"" + operation + "\" requires numeric fields or operations as arguments. \"" + argument + "\" is not a numeric field or operation.");
        }
        subExpressions.add(argSource);
    }
    if (operation.equals(AnalyticsParams.ADD)) {
        return new AddDoubleFunction(subExpressions.toArray(new ValueSource[0]));
    } else if (operation.equals(AnalyticsParams.MULTIPLY)) {
        return new MultiplyDoubleFunction(subExpressions.toArray(new ValueSource[0]));
    } else if (operation.equals(AnalyticsParams.DIVIDE)) {
        if (subExpressions.size() != 2) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The divide operation [" + expressionString + "] does not have exactly 2 arguments.");
        }
        return new DivDoubleFunction(subExpressions.get(0), subExpressions.get(1));
    } else if (operation.equals(AnalyticsParams.POWER)) {
        if (subExpressions.size() != 2) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The power operation [" + expressionString + "] does not have exactly 2 arguments.");
        }
        return new PowDoubleFunction(subExpressions.get(0), subExpressions.get(1));
    } else if (operation.equals(AnalyticsParams.LOG)) {
        if (subExpressions.size() != 2) {
            throw new SolrException(ErrorCode.BAD_REQUEST, "The log operation [" + expressionString + "] does not have exactly 2 arguments.");
        }
        return new LogDoubleFunction(subExpressions.get(0), subExpressions.get(1));
    }
    if (AnalyticsParams.DATE_OPERATION_SET.contains(operation) || AnalyticsParams.STRING_OPERATION_SET.contains(operation)) {
        return null;
    }
    throw new SolrException(ErrorCode.BAD_REQUEST, "The operation [" + expressionString + "] is not supported.");
}
Also used : AddDoubleFunction(org.apache.solr.analytics.util.valuesource.AddDoubleFunction) ArrayList(java.util.ArrayList) DivDoubleFunction(org.apache.solr.analytics.util.valuesource.DivDoubleFunction) ConstDoubleSource(org.apache.solr.analytics.util.valuesource.ConstDoubleSource) SolrException(org.apache.solr.common.SolrException) PowDoubleFunction(org.apache.solr.analytics.util.valuesource.PowDoubleFunction) MultiplyDoubleFunction(org.apache.solr.analytics.util.valuesource.MultiplyDoubleFunction) ValueSource(org.apache.lucene.queries.function.ValueSource) NegateDoubleFunction(org.apache.solr.analytics.util.valuesource.NegateDoubleFunction) AbsoluteValueDoubleFunction(org.apache.solr.analytics.util.valuesource.AbsoluteValueDoubleFunction) LogDoubleFunction(org.apache.solr.analytics.util.valuesource.LogDoubleFunction) SolrException(org.apache.solr.common.SolrException)

Example 7 with ValueSource

use of org.apache.lucene.queries.function.ValueSource in project lucene-solr by apache.

the class MultiStringFunction method description.

@Override
public String description() {
    StringBuilder sb = new StringBuilder();
    sb.append(name()).append('(');
    boolean firstTime = true;
    for (ValueSource source : sources) {
        if (firstTime) {
            firstTime = false;
        } else {
            sb.append(',');
        }
        sb.append(source);
    }
    sb.append(')');
    return sb.toString();
}
Also used : ValueSource(org.apache.lucene.queries.function.ValueSource)

Example 8 with ValueSource

use of org.apache.lucene.queries.function.ValueSource in project lucene-solr by apache.

the class MultiDoubleFunction method description.

@Override
public String description() {
    StringBuilder sb = new StringBuilder();
    sb.append(name()).append('(');
    boolean firstTime = true;
    for (ValueSource source : sources) {
        if (firstTime) {
            firstTime = false;
        } else {
            sb.append(',');
        }
        sb.append(source);
    }
    sb.append(')');
    return sb.toString();
}
Also used : ValueSource(org.apache.lucene.queries.function.ValueSource)

Example 9 with ValueSource

use of org.apache.lucene.queries.function.ValueSource in project lucene-solr by apache.

the class NumericFacets method getCountsSingleValue.

private static NamedList<Integer> getCountsSingleValue(SolrIndexSearcher searcher, DocSet docs, String fieldName, int offset, int limit, int mincount, boolean missing, String sort) throws IOException {
    boolean zeros = mincount <= 0;
    mincount = Math.max(mincount, 1);
    final SchemaField sf = searcher.getSchema().getField(fieldName);
    final FieldType ft = sf.getType();
    final NumberType numericType = ft.getNumberType();
    if (numericType == null) {
        throw new IllegalStateException();
    }
    // We don't return zeros when using PointFields or when index=false
    zeros = zeros && !ft.isPointField() && sf.indexed();
    final List<LeafReaderContext> leaves = searcher.getIndexReader().leaves();
    // 1. accumulate
    final HashTable hashTable = new HashTable(true);
    final Iterator<LeafReaderContext> ctxIt = leaves.iterator();
    LeafReaderContext ctx = null;
    NumericDocValues longs = null;
    int missingCount = 0;
    for (DocIterator docsIt = docs.iterator(); docsIt.hasNext(); ) {
        final int doc = docsIt.nextDoc();
        if (ctx == null || doc >= ctx.docBase + ctx.reader().maxDoc()) {
            do {
                ctx = ctxIt.next();
            } while (ctx == null || doc >= ctx.docBase + ctx.reader().maxDoc());
            assert doc >= ctx.docBase;
            switch(numericType) {
                case LONG:
                case DATE:
                case INTEGER:
                    // Long, Date and Integer
                    longs = DocValues.getNumeric(ctx.reader(), fieldName);
                    break;
                case FLOAT:
                    // TODO: this bit flipping should probably be moved to tie-break in the PQ comparator
                    longs = new FilterNumericDocValues(DocValues.getNumeric(ctx.reader(), fieldName)) {

                        @Override
                        public long longValue() throws IOException {
                            long bits = super.longValue();
                            if (bits < 0)
                                bits ^= 0x7fffffffffffffffL;
                            return bits;
                        }
                    };
                    break;
                case DOUBLE:
                    // TODO: this bit flipping should probably be moved to tie-break in the PQ comparator
                    longs = new FilterNumericDocValues(DocValues.getNumeric(ctx.reader(), fieldName)) {

                        @Override
                        public long longValue() throws IOException {
                            long bits = super.longValue();
                            if (bits < 0)
                                bits ^= 0x7fffffffffffffffL;
                            return bits;
                        }
                    };
                    break;
                default:
                    throw new AssertionError("Unexpected type: " + numericType);
            }
        }
        int valuesDocID = longs.docID();
        if (valuesDocID < doc - ctx.docBase) {
            valuesDocID = longs.advance(doc - ctx.docBase);
        }
        if (valuesDocID == doc - ctx.docBase) {
            hashTable.add(doc, longs.longValue(), 1);
        } else {
            ++missingCount;
        }
    }
    // 2. select top-k facet values
    final int pqSize = limit < 0 ? hashTable.size : Math.min(offset + limit, hashTable.size);
    final PriorityQueue<Entry> pq;
    if (FacetParams.FACET_SORT_COUNT.equals(sort) || FacetParams.FACET_SORT_COUNT_LEGACY.equals(sort)) {
        pq = new PriorityQueue<Entry>(pqSize) {

            @Override
            protected boolean lessThan(Entry a, Entry b) {
                if (a.count < b.count || (a.count == b.count && a.bits > b.bits)) {
                    return true;
                } else {
                    return false;
                }
            }
        };
    } else {
        pq = new PriorityQueue<Entry>(pqSize) {

            @Override
            protected boolean lessThan(Entry a, Entry b) {
                return a.bits > b.bits;
            }
        };
    }
    Entry e = null;
    for (int i = 0; i < hashTable.bits.length; ++i) {
        if (hashTable.counts[i] >= mincount) {
            if (e == null) {
                e = new Entry();
            }
            e.bits = hashTable.bits[i];
            e.count = hashTable.counts[i];
            e.docID = hashTable.docIDs[i];
            e = pq.insertWithOverflow(e);
        }
    }
    // 4. build the NamedList
    final ValueSource vs = ft.getValueSource(sf, null);
    final NamedList<Integer> result = new NamedList<>();
    // to be merged with terms from the terms dict
    if (!zeros || FacetParams.FACET_SORT_COUNT.equals(sort) || FacetParams.FACET_SORT_COUNT_LEGACY.equals(sort)) {
        // Only keep items we're interested in
        final Deque<Entry> counts = new ArrayDeque<>();
        while (pq.size() > offset) {
            counts.addFirst(pq.pop());
        }
        // Entries from the PQ first, then using the terms dictionary
        for (Entry entry : counts) {
            final int readerIdx = ReaderUtil.subIndex(entry.docID, leaves);
            final FunctionValues values = vs.getValues(Collections.emptyMap(), leaves.get(readerIdx));
            result.add(values.strVal(entry.docID - leaves.get(readerIdx).docBase), entry.count);
        }
        if (zeros && (limit < 0 || result.size() < limit)) {
            // need to merge with the term dict
            if (!sf.indexed() && !sf.hasDocValues()) {
                throw new IllegalStateException("Cannot use " + FacetParams.FACET_MINCOUNT + "=0 on field " + sf.getName() + " which is neither indexed nor docValues");
            }
            // Add zeros until there are limit results
            final Set<String> alreadySeen = new HashSet<>();
            while (pq.size() > 0) {
                Entry entry = pq.pop();
                final int readerIdx = ReaderUtil.subIndex(entry.docID, leaves);
                final FunctionValues values = vs.getValues(Collections.emptyMap(), leaves.get(readerIdx));
                alreadySeen.add(values.strVal(entry.docID - leaves.get(readerIdx).docBase));
            }
            for (int i = 0; i < result.size(); ++i) {
                alreadySeen.add(result.getName(i));
            }
            final Terms terms = searcher.getSlowAtomicReader().terms(fieldName);
            if (terms != null) {
                final String prefixStr = TrieField.getMainValuePrefix(ft);
                final BytesRef prefix;
                if (prefixStr != null) {
                    prefix = new BytesRef(prefixStr);
                } else {
                    prefix = new BytesRef();
                }
                final TermsEnum termsEnum = terms.iterator();
                BytesRef term;
                switch(termsEnum.seekCeil(prefix)) {
                    case FOUND:
                    case NOT_FOUND:
                        term = termsEnum.term();
                        break;
                    case END:
                        term = null;
                        break;
                    default:
                        throw new AssertionError();
                }
                final CharsRefBuilder spare = new CharsRefBuilder();
                for (int skipped = hashTable.size; skipped < offset && term != null && StringHelper.startsWith(term, prefix); ) {
                    ft.indexedToReadable(term, spare);
                    final String termStr = spare.toString();
                    if (!alreadySeen.contains(termStr)) {
                        ++skipped;
                    }
                    term = termsEnum.next();
                }
                for (; term != null && StringHelper.startsWith(term, prefix) && (limit < 0 || result.size() < limit); term = termsEnum.next()) {
                    ft.indexedToReadable(term, spare);
                    final String termStr = spare.toString();
                    if (!alreadySeen.contains(termStr)) {
                        result.add(termStr, 0);
                    }
                }
            }
        }
    } else {
        // => Merge the PQ and the terms dictionary on the fly
        if (!sf.indexed()) {
            throw new IllegalStateException("Cannot use " + FacetParams.FACET_SORT + "=" + FacetParams.FACET_SORT_INDEX + " on a field which is not indexed");
        }
        final Map<String, Integer> counts = new HashMap<>();
        while (pq.size() > 0) {
            final Entry entry = pq.pop();
            final int readerIdx = ReaderUtil.subIndex(entry.docID, leaves);
            final FunctionValues values = vs.getValues(Collections.emptyMap(), leaves.get(readerIdx));
            counts.put(values.strVal(entry.docID - leaves.get(readerIdx).docBase), entry.count);
        }
        final Terms terms = searcher.getSlowAtomicReader().terms(fieldName);
        if (terms != null) {
            final String prefixStr = TrieField.getMainValuePrefix(ft);
            final BytesRef prefix;
            if (prefixStr != null) {
                prefix = new BytesRef(prefixStr);
            } else {
                prefix = new BytesRef();
            }
            final TermsEnum termsEnum = terms.iterator();
            BytesRef term;
            switch(termsEnum.seekCeil(prefix)) {
                case FOUND:
                case NOT_FOUND:
                    term = termsEnum.term();
                    break;
                case END:
                    term = null;
                    break;
                default:
                    throw new AssertionError();
            }
            final CharsRefBuilder spare = new CharsRefBuilder();
            for (int i = 0; i < offset && term != null && StringHelper.startsWith(term, prefix); ++i) {
                term = termsEnum.next();
            }
            for (; term != null && StringHelper.startsWith(term, prefix) && (limit < 0 || result.size() < limit); term = termsEnum.next()) {
                ft.indexedToReadable(term, spare);
                final String termStr = spare.toString();
                Integer count = counts.get(termStr);
                if (count == null) {
                    count = 0;
                }
                result.add(termStr, count);
            }
        }
    }
    if (missing) {
        result.add(null, missingCount);
    }
    return result;
}
Also used : FilterNumericDocValues(org.apache.lucene.index.FilterNumericDocValues) NumericDocValues(org.apache.lucene.index.NumericDocValues) SortedNumericDocValues(org.apache.lucene.index.SortedNumericDocValues) DocIterator(org.apache.solr.search.DocIterator) HashMap(java.util.HashMap) TermsEnum(org.apache.lucene.index.TermsEnum) LeafReaderContext(org.apache.lucene.index.LeafReaderContext) CharsRefBuilder(org.apache.lucene.util.CharsRefBuilder) BytesRef(org.apache.lucene.util.BytesRef) HashSet(java.util.HashSet) NamedList(org.apache.solr.common.util.NamedList) Terms(org.apache.lucene.index.Terms) IOException(java.io.IOException) FilterNumericDocValues(org.apache.lucene.index.FilterNumericDocValues) ArrayDeque(java.util.ArrayDeque) FieldType(org.apache.solr.schema.FieldType) SchemaField(org.apache.solr.schema.SchemaField) NumberType(org.apache.solr.schema.NumberType) ValueSource(org.apache.lucene.queries.function.ValueSource) FunctionValues(org.apache.lucene.queries.function.FunctionValues)

Example 10 with ValueSource

use of org.apache.lucene.queries.function.ValueSource in project lucene-solr by apache.

the class GeoDistValueSourceParser method parse.

@Override
public ValueSource parse(FunctionQParser fp) throws SyntaxError {
    // TODO: dispatch through SpatialQueryable in the future?
    //note: parseValueSourceList can't handle a field reference to an AbstractSpatialFieldType,
    // so those fields are expressly handled via sfield=
    List<ValueSource> sources = fp.parseValueSourceList();
    // "m" is a multi-value source, "x" is a single-value source
    // allow (m,m) (m,x,x) (x,x,m) (x,x,x,x)
    // if not enough points are present, "pt" will be checked first, followed by "sfield".
    MultiValueSource mv1 = null;
    MultiValueSource mv2 = null;
    if (sources.size() == 0) {
    // nothing to do now
    } else if (sources.size() == 1) {
        ValueSource vs = sources.get(0);
        if (!(vs instanceof MultiValueSource)) {
            throw new SyntaxError("geodist - invalid parameters:" + sources);
        }
        mv1 = (MultiValueSource) vs;
    } else if (sources.size() == 2) {
        ValueSource vs1 = sources.get(0);
        ValueSource vs2 = sources.get(1);
        if (vs1 instanceof MultiValueSource && vs2 instanceof MultiValueSource) {
            mv1 = (MultiValueSource) vs1;
            mv2 = (MultiValueSource) vs2;
        } else {
            mv1 = makeMV(sources, sources);
        }
    } else if (sources.size() == 3) {
        ValueSource vs1 = sources.get(0);
        ValueSource vs2 = sources.get(1);
        if (vs1 instanceof MultiValueSource) {
            // (m,x,x)
            mv1 = (MultiValueSource) vs1;
            mv2 = makeMV(sources.subList(1, 3), sources);
        } else {
            // (x,x,m)
            mv1 = makeMV(sources.subList(0, 2), sources);
            vs1 = sources.get(2);
            if (!(vs1 instanceof MultiValueSource)) {
                throw new SyntaxError("geodist - invalid parameters:" + sources);
            }
            mv2 = (MultiValueSource) vs1;
        }
    } else if (sources.size() == 4) {
        mv1 = makeMV(sources.subList(0, 2), sources);
        mv2 = makeMV(sources.subList(2, 4), sources);
    } else if (sources.size() > 4) {
        throw new SyntaxError("geodist - invalid parameters:" + sources);
    }
    if (mv1 == null) {
        mv1 = parsePoint(fp);
        mv2 = parseSfield(fp);
    } else if (mv2 == null) {
        mv2 = parsePoint(fp);
        if (mv2 == null)
            mv2 = parseSfield(fp);
    }
    if (mv1 == null || mv2 == null) {
        throw new SyntaxError("geodist - not enough parameters:" + sources);
    }
    // We have all the parameters at this point, now check if one of the points is constant
    //latLon
    double[] constants;
    constants = getConstants(mv1);
    MultiValueSource other = mv2;
    if (constants == null) {
        constants = getConstants(mv2);
        other = mv1;
    }
    // sfield can only be in mv2, according to the logic above
    if (mv2 instanceof SpatialStrategyMultiValueSource) {
        if (constants == null)
            throw new SyntaxError("When using AbstractSpatialFieldType (e.g. RPT not LatLonType)," + " the point must be supplied as constants");
        // note: uses Haversine by default but can be changed via distCalc=...
        SpatialStrategy strategy = ((SpatialStrategyMultiValueSource) mv2).strategy;
        DistanceUnits distanceUnits = ((SpatialStrategyMultiValueSource) mv2).distanceUnits;
        Point queryPoint = strategy.getSpatialContext().makePoint(constants[1], constants[0]);
        return strategy.makeDistanceValueSource(queryPoint, distanceUnits.multiplierFromDegreesToThisUnit());
    }
    if (constants != null && other instanceof VectorValueSource) {
        return new HaversineConstFunction(constants[0], constants[1], (VectorValueSource) other);
    }
    return new HaversineFunction(mv1, mv2, DistanceUtils.EARTH_MEAN_RADIUS_KM, true);
}
Also used : SyntaxError(org.apache.solr.search.SyntaxError) VectorValueSource(org.apache.lucene.queries.function.valuesource.VectorValueSource) ValueSource(org.apache.lucene.queries.function.ValueSource) DoubleConstValueSource(org.apache.lucene.queries.function.valuesource.DoubleConstValueSource) MultiValueSource(org.apache.lucene.queries.function.valuesource.MultiValueSource) VectorValueSource(org.apache.lucene.queries.function.valuesource.VectorValueSource) DistanceUnits(org.apache.solr.util.DistanceUnits) Point(org.locationtech.spatial4j.shape.Point) MultiValueSource(org.apache.lucene.queries.function.valuesource.MultiValueSource) SpatialStrategy(org.apache.lucene.spatial.SpatialStrategy)

Aggregations

ValueSource (org.apache.lucene.queries.function.ValueSource)54 Query (org.apache.lucene.search.Query)13 FunctionQuery (org.apache.lucene.queries.function.FunctionQuery)12 SolrException (org.apache.solr.common.SolrException)11 SchemaField (org.apache.solr.schema.SchemaField)11 FunctionValues (org.apache.lucene.queries.function.FunctionValues)10 ArrayList (java.util.ArrayList)8 QueryValueSource (org.apache.lucene.queries.function.valuesource.QueryValueSource)7 FieldType (org.apache.solr.schema.FieldType)6 BooleanQuery (org.apache.lucene.search.BooleanQuery)5 AggValueSource (org.apache.solr.search.facet.AggValueSource)5 IOException (java.io.IOException)4 Map (java.util.Map)4 DoubleConstValueSource (org.apache.lucene.queries.function.valuesource.DoubleConstValueSource)4 VectorValueSource (org.apache.lucene.queries.function.valuesource.VectorValueSource)4 MatchAllDocsQuery (org.apache.lucene.search.MatchAllDocsQuery)4 IndexReader (org.apache.lucene.index.IndexReader)3 LeafReaderContext (org.apache.lucene.index.LeafReaderContext)3 BoostedQuery (org.apache.lucene.queries.function.BoostedQuery)3 TermGroupSelector (org.apache.lucene.search.grouping.TermGroupSelector)3