Search in sources :

Example 11 with FunctionValues

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

the class MultiDateFunction method getValues.

@Override
public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
    final FunctionValues[] valsArr = new FunctionValues[sources.length];
    for (int i = 0; i < sources.length; i++) {
        valsArr[i] = sources[i].getValues(context, readerContext);
    }
    return new LongDocValues(this) {

        @Override
        public long longVal(int doc) throws IOException {
            return func(doc, valsArr);
        }

        @Override
        public boolean exists(int doc) throws IOException {
            boolean exists = true;
            for (FunctionValues val : valsArr) {
                exists = exists & val.exists(doc);
            }
            return exists;
        }

        @Override
        public String toString(int doc) throws IOException {
            StringBuilder sb = new StringBuilder();
            sb.append(name()).append('(');
            boolean firstTime = true;
            for (FunctionValues vals : valsArr) {
                if (firstTime) {
                    firstTime = false;
                } else {
                    sb.append(',');
                }
                sb.append(vals.toString(doc));
            }
            sb.append(')');
            return sb.toString();
        }

        @Override
        public ValueFiller getValueFiller() {
            return new ValueFiller() {

                private final MutableValueDate mval = new MutableValueDate();

                @Override
                public MutableValue getValue() {
                    return mval;
                }

                @Override
                public void fillValue(int doc) throws IOException {
                    mval.value = longVal(doc);
                    mval.exists = exists(doc);
                }
            };
        }
    };
}
Also used : MutableValueDate(org.apache.lucene.util.mutable.MutableValueDate) FunctionValues(org.apache.lucene.queries.function.FunctionValues) LongDocValues(org.apache.lucene.queries.function.docvalues.LongDocValues)

Example 12 with FunctionValues

use of org.apache.lucene.queries.function.FunctionValues 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 13 with FunctionValues

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

the class BBoxValueSource method getValues.

@Override
public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
    LeafReader reader = readerContext.reader();
    final NumericDocValues minX = DocValues.getNumeric(reader, strategy.field_minX);
    final NumericDocValues minY = DocValues.getNumeric(reader, strategy.field_minY);
    final NumericDocValues maxX = DocValues.getNumeric(reader, strategy.field_maxX);
    final NumericDocValues maxY = DocValues.getNumeric(reader, strategy.field_maxY);
    //reused
    final Rectangle rect = strategy.getSpatialContext().makeRectangle(0, 0, 0, 0);
    return new FunctionValues() {

        private int lastDocID = -1;

        private double getDocValue(NumericDocValues values, int doc) throws IOException {
            int curDocID = values.docID();
            if (doc > curDocID) {
                curDocID = values.advance(doc);
            }
            if (doc == curDocID) {
                return Double.longBitsToDouble(values.longValue());
            } else {
                return 0.0;
            }
        }

        @Override
        public Object objectVal(int doc) throws IOException {
            if (doc < lastDocID) {
                throw new AssertionError("docs were sent out-of-order: lastDocID=" + lastDocID + " vs doc=" + doc);
            }
            lastDocID = doc;
            double minXValue = getDocValue(minX, doc);
            if (minX.docID() != doc) {
                return null;
            } else {
                double minYValue = getDocValue(minY, doc);
                double maxXValue = getDocValue(maxX, doc);
                double maxYValue = getDocValue(maxY, doc);
                rect.reset(minXValue, maxXValue, minYValue, maxYValue);
                return rect;
            }
        }

        @Override
        public String strVal(int doc) throws IOException {
            //TODO support WKT output once Spatial4j does
            Object v = objectVal(doc);
            return v == null ? null : v.toString();
        }

        @Override
        public boolean exists(int doc) throws IOException {
            getDocValue(minX, doc);
            return minX.docID() == doc;
        }

        @Override
        public Explanation explain(int doc) throws IOException {
            return Explanation.match(Float.NaN, toString(doc));
        }

        @Override
        public String toString(int doc) throws IOException {
            return description() + '=' + strVal(doc);
        }
    };
}
Also used : NumericDocValues(org.apache.lucene.index.NumericDocValues) LeafReader(org.apache.lucene.index.LeafReader) Rectangle(org.locationtech.spatial4j.shape.Rectangle) FunctionValues(org.apache.lucene.queries.function.FunctionValues)

Example 14 with FunctionValues

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

the class DistanceValueSource method getValues.

/**
   * Returns the FunctionValues used by the function query.
   */
@Override
public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
    LeafReader reader = readerContext.reader();
    final NumericDocValues ptX = DocValues.getNumeric(reader, strategy.getFieldNameX());
    final NumericDocValues ptY = DocValues.getNumeric(reader, strategy.getFieldNameY());
    return new FunctionValues() {

        private int lastDocID = -1;

        private final Point from = DistanceValueSource.this.from;

        private final DistanceCalculator calculator = strategy.getSpatialContext().getDistCalc();

        private final double nullValue = (strategy.getSpatialContext().isGeo() ? 180 * multiplier : Double.MAX_VALUE);

        private double getDocValue(NumericDocValues values, int doc) throws IOException {
            int curDocID = values.docID();
            if (doc > curDocID) {
                curDocID = values.advance(doc);
            }
            if (doc == curDocID) {
                return Double.longBitsToDouble(values.longValue());
            } else {
                return 0.0;
            }
        }

        @Override
        public float floatVal(int doc) throws IOException {
            return (float) doubleVal(doc);
        }

        @Override
        public double doubleVal(int doc) throws IOException {
            // make sure it has minX and area
            double x = getDocValue(ptX, doc);
            if (ptX.docID() == doc) {
                double y = getDocValue(ptY, doc);
                assert ptY.docID() == doc;
                return calculator.distance(from, x, y) * multiplier;
            }
            return nullValue;
        }

        @Override
        public String toString(int doc) throws IOException {
            return description() + "=" + floatVal(doc);
        }
    };
}
Also used : DistanceCalculator(org.locationtech.spatial4j.distance.DistanceCalculator) NumericDocValues(org.apache.lucene.index.NumericDocValues) LeafReader(org.apache.lucene.index.LeafReader) FunctionValues(org.apache.lucene.queries.function.FunctionValues) Point(org.locationtech.spatial4j.shape.Point) Point(org.locationtech.spatial4j.shape.Point)

Example 15 with FunctionValues

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

the class StringDistanceFunction method getValues.

@Override
public FunctionValues getValues(Map context, LeafReaderContext readerContext) throws IOException {
    final FunctionValues str1DV = str1.getValues(context, readerContext);
    final FunctionValues str2DV = str2.getValues(context, readerContext);
    return new FloatDocValues(this) {

        @Override
        public float floatVal(int doc) throws IOException {
            String s1 = str1DV.strVal(doc);
            String s2 = str2DV.strVal(doc);
            if (null == s1 || null == s2) {
                // the only thing a missing value scores 1.0 with is another missing value
                return (s1 == s2) ? 1.0F : 0.0F;
            }
            return dist.getDistance(s1, s2);
        }

        @Override
        public boolean exists(int doc) throws IOException {
            return str1DV.exists(doc) && str2DV.exists(doc);
        }

        @Override
        public String toString(int doc) throws IOException {
            StringBuilder sb = new StringBuilder();
            sb.append("strdist").append('(');
            sb.append(str1DV.toString(doc)).append(',').append(str2DV.toString(doc)).append(", dist=").append(dist.getClass().getName());
            sb.append(')');
            return sb.toString();
        }
    };
}
Also used : FunctionValues(org.apache.lucene.queries.function.FunctionValues) FloatDocValues(org.apache.lucene.queries.function.docvalues.FloatDocValues)

Aggregations

FunctionValues (org.apache.lucene.queries.function.FunctionValues)45 ValueSource (org.apache.lucene.queries.function.ValueSource)10 DoubleDocValues (org.apache.lucene.queries.function.docvalues.DoubleDocValues)9 LeafReaderContext (org.apache.lucene.index.LeafReaderContext)7 Map (java.util.Map)6 LeafReader (org.apache.lucene.index.LeafReader)6 NumericDocValues (org.apache.lucene.index.NumericDocValues)6 IOException (java.io.IOException)5 FloatDocValues (org.apache.lucene.queries.function.docvalues.FloatDocValues)5 Explanation (org.apache.lucene.search.Explanation)4 ArrayList (java.util.ArrayList)3 Terms (org.apache.lucene.index.Terms)3 BoolDocValues (org.apache.lucene.queries.function.docvalues.BoolDocValues)3 BytesRef (org.apache.lucene.util.BytesRef)3 BytesRefBuilder (org.apache.lucene.util.BytesRefBuilder)3 Point (org.locationtech.spatial4j.shape.Point)3 Rectangle (org.locationtech.spatial4j.shape.Rectangle)3 Date (java.util.Date)2 TermsEnum (org.apache.lucene.index.TermsEnum)2 SimpleFloatFunction (org.apache.lucene.queries.function.valuesource.SimpleFloatFunction)2