Search in sources :

Example 1 with ScorerSupplier

use of org.apache.lucene.search.ScorerSupplier in project lucene-solr by apache.

the class LatLonPointDistanceQuery method createWeight.

@Override
public Weight createWeight(IndexSearcher searcher, boolean needsScores, float boost) throws IOException {
    Rectangle box = Rectangle.fromPointDistance(latitude, longitude, radiusMeters);
    // create bounding box(es) for the distance range
    // these are pre-encoded with LatLonPoint's encoding
    final byte[] minLat = new byte[Integer.BYTES];
    final byte[] maxLat = new byte[Integer.BYTES];
    final byte[] minLon = new byte[Integer.BYTES];
    final byte[] maxLon = new byte[Integer.BYTES];
    // second set of longitude ranges to check (for cross-dateline case)
    final byte[] minLon2 = new byte[Integer.BYTES];
    NumericUtils.intToSortableBytes(encodeLatitude(box.minLat), minLat, 0);
    NumericUtils.intToSortableBytes(encodeLatitude(box.maxLat), maxLat, 0);
    // crosses dateline: split
    if (box.crossesDateline()) {
        // box1
        NumericUtils.intToSortableBytes(Integer.MIN_VALUE, minLon, 0);
        NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
        // box2
        NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon2, 0);
    } else {
        NumericUtils.intToSortableBytes(encodeLongitude(box.minLon), minLon, 0);
        NumericUtils.intToSortableBytes(encodeLongitude(box.maxLon), maxLon, 0);
        // disable box2
        NumericUtils.intToSortableBytes(Integer.MAX_VALUE, minLon2, 0);
    }
    // compute exact sort key: avoid any asin() computations
    final double sortKey = GeoUtils.distanceQuerySortKey(radiusMeters);
    final double axisLat = Rectangle.axisLat(latitude, radiusMeters);
    return new ConstantScoreWeight(this, boost) {

        final GeoEncodingUtils.DistancePredicate distancePredicate = GeoEncodingUtils.createDistancePredicate(latitude, longitude, radiusMeters);

        @Override
        public Scorer scorer(LeafReaderContext context) throws IOException {
            ScorerSupplier scorerSupplier = scorerSupplier(context);
            if (scorerSupplier == null) {
                return null;
            }
            return scorerSupplier.get(false);
        }

        @Override
        public ScorerSupplier scorerSupplier(LeafReaderContext context) throws IOException {
            LeafReader reader = context.reader();
            PointValues values = reader.getPointValues(field);
            if (values == null) {
                // No docs in this segment had any points fields
                return null;
            }
            FieldInfo fieldInfo = reader.getFieldInfos().fieldInfo(field);
            if (fieldInfo == null) {
                // No docs in this segment indexed this field at all
                return null;
            }
            LatLonPoint.checkCompatible(fieldInfo);
            // matching docids
            DocIdSetBuilder result = new DocIdSetBuilder(reader.maxDoc(), values, field);
            final IntersectVisitor visitor = new IntersectVisitor() {

                DocIdSetBuilder.BulkAdder adder;

                @Override
                public void grow(int count) {
                    adder = result.grow(count);
                }

                @Override
                public void visit(int docID) {
                    adder.add(docID);
                }

                @Override
                public void visit(int docID, byte[] packedValue) {
                    // bounding box check
                    if (StringHelper.compare(Integer.BYTES, packedValue, 0, maxLat, 0) > 0 || StringHelper.compare(Integer.BYTES, packedValue, 0, minLat, 0) < 0) {
                        // latitude out of bounding box range
                        return;
                    }
                    if ((StringHelper.compare(Integer.BYTES, packedValue, Integer.BYTES, maxLon, 0) > 0 || StringHelper.compare(Integer.BYTES, packedValue, Integer.BYTES, minLon, 0) < 0) && StringHelper.compare(Integer.BYTES, packedValue, Integer.BYTES, minLon2, 0) < 0) {
                        // longitude out of bounding box range
                        return;
                    }
                    int docLatitude = NumericUtils.sortableBytesToInt(packedValue, 0);
                    int docLongitude = NumericUtils.sortableBytesToInt(packedValue, Integer.BYTES);
                    if (distancePredicate.test(docLatitude, docLongitude)) {
                        adder.add(docID);
                    }
                }

                // algorithm: we create a bounding box (two bounding boxes if we cross the dateline).
                // 1. check our bounding box(es) first. if the subtree is entirely outside of those, bail.
                // 2. check if the subtree is disjoint. it may cross the bounding box but not intersect with circle
                // 3. see if the subtree is fully contained. if the subtree is enormous along the x axis, wrapping half way around the world, etc: then this can't work, just go to step 4.
                // 4. recurse naively (subtrees crossing over circle edge)
                @Override
                public Relation compare(byte[] minPackedValue, byte[] maxPackedValue) {
                    if (StringHelper.compare(Integer.BYTES, minPackedValue, 0, maxLat, 0) > 0 || StringHelper.compare(Integer.BYTES, maxPackedValue, 0, minLat, 0) < 0) {
                        // latitude out of bounding box range
                        return Relation.CELL_OUTSIDE_QUERY;
                    }
                    if ((StringHelper.compare(Integer.BYTES, minPackedValue, Integer.BYTES, maxLon, 0) > 0 || StringHelper.compare(Integer.BYTES, maxPackedValue, Integer.BYTES, minLon, 0) < 0) && StringHelper.compare(Integer.BYTES, maxPackedValue, Integer.BYTES, minLon2, 0) < 0) {
                        // longitude out of bounding box range
                        return Relation.CELL_OUTSIDE_QUERY;
                    }
                    double latMin = decodeLatitude(minPackedValue, 0);
                    double lonMin = decodeLongitude(minPackedValue, Integer.BYTES);
                    double latMax = decodeLatitude(maxPackedValue, 0);
                    double lonMax = decodeLongitude(maxPackedValue, Integer.BYTES);
                    return GeoUtils.relate(latMin, latMax, lonMin, lonMax, latitude, longitude, sortKey, axisLat);
                }
            };
            final Weight weight = this;
            return new ScorerSupplier() {

                long cost = -1;

                @Override
                public Scorer get(boolean randomAccess) throws IOException {
                    values.intersect(visitor);
                    return new ConstantScoreScorer(weight, score(), result.build().iterator());
                }

                @Override
                public long cost() {
                    if (cost == -1) {
                        cost = values.estimatePointCount(visitor);
                    }
                    assert cost >= 0;
                    return cost;
                }
            };
        }
    };
}
Also used : IntersectVisitor(org.apache.lucene.index.PointValues.IntersectVisitor) LeafReader(org.apache.lucene.index.LeafReader) Rectangle(org.apache.lucene.geo.Rectangle) ConstantScoreWeight(org.apache.lucene.search.ConstantScoreWeight) Weight(org.apache.lucene.search.Weight) ConstantScoreWeight(org.apache.lucene.search.ConstantScoreWeight) PointValues(org.apache.lucene.index.PointValues) ConstantScoreScorer(org.apache.lucene.search.ConstantScoreScorer) ScorerSupplier(org.apache.lucene.search.ScorerSupplier) LeafReaderContext(org.apache.lucene.index.LeafReaderContext) DocIdSetBuilder(org.apache.lucene.util.DocIdSetBuilder) FieldInfo(org.apache.lucene.index.FieldInfo)

Aggregations

Rectangle (org.apache.lucene.geo.Rectangle)1 FieldInfo (org.apache.lucene.index.FieldInfo)1 LeafReader (org.apache.lucene.index.LeafReader)1 LeafReaderContext (org.apache.lucene.index.LeafReaderContext)1 PointValues (org.apache.lucene.index.PointValues)1 IntersectVisitor (org.apache.lucene.index.PointValues.IntersectVisitor)1 ConstantScoreScorer (org.apache.lucene.search.ConstantScoreScorer)1 ConstantScoreWeight (org.apache.lucene.search.ConstantScoreWeight)1 ScorerSupplier (org.apache.lucene.search.ScorerSupplier)1 Weight (org.apache.lucene.search.Weight)1 DocIdSetBuilder (org.apache.lucene.util.DocIdSetBuilder)1