Search in sources :

Example 1 with XYZBounds

use of org.apache.lucene.spatial3d.geom.XYZBounds in project lucene-solr by apache.

the class Geo3DPointDistanceComparator method setBottom.

@Override
public void setBottom(int slot) {
    bottomDistance = values[slot];
    // boxes if comparator hits a worst case order (e.g. backwards distance order)
    if (setBottomCounter < 1024 || (setBottomCounter & 0x3F) == 0x3F) {
        // Update bounds
        final XYZBounds bounds = new XYZBounds();
        distanceShape.getDistanceBounds(bounds, DistanceStyle.ARC, bottomDistance);
        priorityQueueBounds = bounds;
    }
    setBottomCounter++;
}
Also used : XYZBounds(org.apache.lucene.spatial3d.geom.XYZBounds)

Example 2 with XYZBounds

use of org.apache.lucene.spatial3d.geom.XYZBounds in project lucene-solr by apache.

the class TestGeo3DPoint method verify.

private static void verify(double[] lats, double[] lons) throws Exception {
    IndexWriterConfig iwc = newIndexWriterConfig();
    GeoPoint[] points = new GeoPoint[lats.length];
    GeoPoint[] unquantizedPoints = new GeoPoint[lats.length];
    // Pre-quantize all lat/lons:
    for (int i = 0; i < lats.length; i++) {
        if (Double.isNaN(lats[i]) == false) {
            //System.out.println("lats[" + i + "] = " + lats[i]);
            unquantizedPoints[i] = new GeoPoint(PlanetModel.WGS84, toRadians(lats[i]), toRadians(lons[i]));
            points[i] = quantize(unquantizedPoints[i]);
        }
    }
    // Else we can get O(N^2) merging:
    int mbd = iwc.getMaxBufferedDocs();
    if (mbd != -1 && mbd < points.length / 100) {
        iwc.setMaxBufferedDocs(points.length / 100);
    }
    iwc.setCodec(getCodec());
    Directory dir;
    if (points.length > 100000) {
        dir = newFSDirectory(createTempDir("TestBKDTree"));
    } else {
        dir = getDirectory();
    }
    Set<Integer> deleted = new HashSet<>();
    // RandomIndexWriter is too slow here:
    IndexWriter w = new IndexWriter(dir, iwc);
    for (int id = 0; id < points.length; id++) {
        Document doc = new Document();
        doc.add(newStringField("id", "" + id, Field.Store.NO));
        doc.add(new NumericDocValuesField("id", id));
        GeoPoint point = points[id];
        if (point != null) {
            doc.add(new Geo3DPoint("point", point.x, point.y, point.z));
        }
        w.addDocument(doc);
        if (id > 0 && random().nextInt(100) == 42) {
            int idToDelete = random().nextInt(id);
            w.deleteDocuments(new Term("id", "" + idToDelete));
            deleted.add(idToDelete);
            if (VERBOSE) {
                System.err.println("  delete id=" + idToDelete);
            }
        }
    }
    if (random().nextBoolean()) {
        w.forceMerge(1);
    }
    final IndexReader r = DirectoryReader.open(w);
    if (VERBOSE) {
        System.out.println("TEST: using reader " + r);
    }
    w.close();
    // We can't wrap with "exotic" readers because the geo3d query must see the Geo3DDVFormat:
    IndexSearcher s = newSearcher(r, false);
    final int iters = atLeast(100);
    for (int iter = 0; iter < iters; iter++) {
        /*
      GeoShape shape = randomShape();

      if (VERBOSE) {
        System.err.println("\nTEST: iter=" + iter + " shape="+shape);
      }
      */
        // Geo3DPoint.newShapeQuery("point", shape);
        Query query = random3DQuery("point");
        if (VERBOSE) {
            System.err.println("  using query: " + query);
        }
        final FixedBitSet hits = new FixedBitSet(r.maxDoc());
        s.search(query, new SimpleCollector() {

            private int docBase;

            @Override
            public boolean needsScores() {
                return false;
            }

            @Override
            protected void doSetNextReader(LeafReaderContext context) throws IOException {
                docBase = context.docBase;
            }

            @Override
            public void collect(int doc) {
                hits.set(docBase + doc);
            }
        });
        if (VERBOSE) {
            System.err.println("  hitCount: " + hits.cardinality());
        }
        NumericDocValues docIDToID = MultiDocValues.getNumericValues(r, "id");
        for (int docID = 0; docID < r.maxDoc(); docID++) {
            assertEquals(docID, docIDToID.nextDoc());
            int id = (int) docIDToID.longValue();
            GeoPoint point = points[id];
            GeoPoint unquantizedPoint = unquantizedPoints[id];
            if (point != null && unquantizedPoint != null) {
                GeoShape shape = ((PointInGeo3DShapeQuery) query).getShape();
                XYZBounds bounds = new XYZBounds();
                shape.getBounds(bounds);
                XYZSolid solid = XYZSolidFactory.makeXYZSolid(PlanetModel.WGS84, bounds.getMinimumX(), bounds.getMaximumX(), bounds.getMinimumY(), bounds.getMaximumY(), bounds.getMinimumZ(), bounds.getMaximumZ());
                boolean expected = ((deleted.contains(id) == false) && shape.isWithin(point));
                if (hits.get(docID) != expected) {
                    StringBuilder b = new StringBuilder();
                    if (expected) {
                        b.append("FAIL: id=" + id + " should have matched but did not\n");
                    } else {
                        b.append("FAIL: id=" + id + " should not have matched but did\n");
                    }
                    b.append("  shape=" + shape + "\n");
                    b.append("  bounds=" + bounds + "\n");
                    b.append("  world bounds=(" + " minX=" + PlanetModel.WGS84.getMinimumXValue() + " maxX=" + PlanetModel.WGS84.getMaximumXValue() + " minY=" + PlanetModel.WGS84.getMinimumYValue() + " maxY=" + PlanetModel.WGS84.getMaximumYValue() + " minZ=" + PlanetModel.WGS84.getMinimumZValue() + " maxZ=" + PlanetModel.WGS84.getMaximumZValue() + "\n");
                    b.append("  quantized point=" + point + " within shape? " + shape.isWithin(point) + " within bounds? " + solid.isWithin(point) + "\n");
                    b.append("  unquantized point=" + unquantizedPoint + " within shape? " + shape.isWithin(unquantizedPoint) + " within bounds? " + solid.isWithin(unquantizedPoint) + "\n");
                    b.append("  docID=" + docID + " deleted?=" + deleted.contains(id) + "\n");
                    b.append("  query=" + query + "\n");
                    b.append("  explanation:\n    " + explain("point", shape, point, unquantizedPoint, r, docID).replace("\n", "\n  "));
                    fail(b.toString());
                }
            } else {
                assertFalse(hits.get(docID));
            }
        }
    }
    IOUtils.close(r, dir);
}
Also used : IndexSearcher(org.apache.lucene.search.IndexSearcher) NumericDocValues(org.apache.lucene.index.NumericDocValues) Query(org.apache.lucene.search.Query) GeoShape(org.apache.lucene.spatial3d.geom.GeoShape) Document(org.apache.lucene.document.Document) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) SimpleCollector(org.apache.lucene.search.SimpleCollector) NumericDocValuesField(org.apache.lucene.document.NumericDocValuesField) FixedBitSet(org.apache.lucene.util.FixedBitSet) LeafReaderContext(org.apache.lucene.index.LeafReaderContext) Directory(org.apache.lucene.store.Directory) HashSet(java.util.HashSet) Term(org.apache.lucene.index.Term) IOException(java.io.IOException) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) IndexWriter(org.apache.lucene.index.IndexWriter) IndexReader(org.apache.lucene.index.IndexReader) XYZSolid(org.apache.lucene.spatial3d.geom.XYZSolid) XYZBounds(org.apache.lucene.spatial3d.geom.XYZBounds) IndexWriterConfig(org.apache.lucene.index.IndexWriterConfig)

Example 3 with XYZBounds

use of org.apache.lucene.spatial3d.geom.XYZBounds in project lucene-solr by apache.

the class TestGeo3DPoint method testGeo3DRelations.

/** Tests consistency of GeoArea.getRelationship vs GeoShape.isWithin */
public void testGeo3DRelations() throws Exception {
    int numDocs = atLeast(1000);
    if (VERBOSE) {
        System.out.println("TEST: " + numDocs + " docs");
    }
    GeoPoint[] docs = new GeoPoint[numDocs];
    GeoPoint[] unquantizedDocs = new GeoPoint[numDocs];
    for (int docID = 0; docID < numDocs; docID++) {
        unquantizedDocs[docID] = new GeoPoint(PlanetModel.WGS84, toRadians(GeoTestUtil.nextLatitude()), toRadians(GeoTestUtil.nextLongitude()));
        docs[docID] = quantize(unquantizedDocs[docID]);
        if (VERBOSE) {
            System.out.println("  doc=" + docID + ": " + docs[docID] + "; unquantized: " + unquantizedDocs[docID]);
        }
    }
    int iters = atLeast(10);
    int recurseDepth = RandomNumbers.randomIntBetween(random(), 5, 15);
    iters = atLeast(50);
    for (int iter = 0; iter < iters; iter++) {
        GeoShape shape = randomShape();
        StringWriter sw = new StringWriter();
        PrintWriter log = new PrintWriter(sw, true);
        if (VERBOSE) {
            log.println("TEST: iter=" + iter + " shape=" + shape);
        }
        XYZBounds bounds = new XYZBounds();
        shape.getBounds(bounds);
        // Start with the root cell that fully contains the shape:
        Cell root = new Cell(null, encodeValueLenient(bounds.getMinimumX()), encodeValueLenient(bounds.getMaximumX()), encodeValueLenient(bounds.getMinimumY()), encodeValueLenient(bounds.getMaximumY()), encodeValueLenient(bounds.getMinimumZ()), encodeValueLenient(bounds.getMaximumZ()), 0);
        if (VERBOSE) {
            log.println("  root cell: " + root);
        }
        // make sure the root cell (XYZBounds) does in fact contain all points that the shape contains
        {
            boolean fail = false;
            for (int docID = 0; docID < numDocs; docID++) {
                if (root.contains(docs[docID]) == false) {
                    boolean expected = shape.isWithin(unquantizedDocs[docID]);
                    if (expected) {
                        log.println("    doc=" + docID + " is contained by shape but is outside the returned XYZBounds");
                        log.println("      unquantized=" + unquantizedDocs[docID]);
                        log.println("      quantized=" + docs[docID]);
                        fail = true;
                    }
                }
            }
            if (fail) {
                log.println("  shape=" + shape);
                log.println("  bounds=" + bounds);
                System.out.print(sw.toString());
                fail("invalid bounds for shape=" + shape);
            }
        }
        List<Cell> queue = new ArrayList<>();
        queue.add(root);
        Set<Integer> hits = new HashSet<>();
        while (queue.size() > 0) {
            Cell cell = queue.get(queue.size() - 1);
            queue.remove(queue.size() - 1);
            if (VERBOSE) {
                log.println("  cycle: " + cell + " queue.size()=" + queue.size());
            }
            if (random().nextInt(10) == 7 || cell.splitCount > recurseDepth) {
                if (VERBOSE) {
                    log.println("    leaf");
                }
                // Leaf cell: brute force check all docs that fall within this cell:
                for (int docID = 0; docID < numDocs; docID++) {
                    GeoPoint point = docs[docID];
                    GeoPoint mappedPoint = unquantizedDocs[docID];
                    boolean pointWithinShape = shape.isWithin(point);
                    boolean mappedPointWithinShape = shape.isWithin(mappedPoint);
                    if (cell.contains(point)) {
                        if (mappedPointWithinShape) {
                            if (VERBOSE) {
                                log.println("    check doc=" + docID + ": match!  Actual quantized point within: " + pointWithinShape);
                            }
                            hits.add(docID);
                        } else {
                            if (VERBOSE) {
                                log.println("    check doc=" + docID + ": no match.  Quantized point within: " + pointWithinShape);
                            }
                        }
                    }
                }
            } else {
                GeoArea xyzSolid = GeoAreaFactory.makeGeoArea(PlanetModel.WGS84, Geo3DUtil.decodeValueFloor(cell.xMinEnc), Geo3DUtil.decodeValueCeil(cell.xMaxEnc), Geo3DUtil.decodeValueFloor(cell.yMinEnc), Geo3DUtil.decodeValueCeil(cell.yMaxEnc), Geo3DUtil.decodeValueFloor(cell.zMinEnc), Geo3DUtil.decodeValueCeil(cell.zMaxEnc));
                if (VERBOSE) {
                    log.println("    minx=" + Geo3DUtil.decodeValueFloor(cell.xMinEnc) + " maxx=" + Geo3DUtil.decodeValueCeil(cell.xMaxEnc) + " miny=" + Geo3DUtil.decodeValueFloor(cell.yMinEnc) + " maxy=" + Geo3DUtil.decodeValueCeil(cell.yMaxEnc) + " minz=" + Geo3DUtil.decodeValueFloor(cell.zMinEnc) + " maxz=" + Geo3DUtil.decodeValueCeil(cell.zMaxEnc));
                }
                switch(xyzSolid.getRelationship(shape)) {
                    case GeoArea.CONTAINS:
                        // Shape fully contains the cell: blindly add all docs in this cell:
                        if (VERBOSE) {
                            log.println("    GeoArea.CONTAINS: now addAll");
                        }
                        for (int docID = 0; docID < numDocs; docID++) {
                            if (cell.contains(docs[docID])) {
                                if (VERBOSE) {
                                    log.println("    addAll doc=" + docID);
                                }
                                hits.add(docID);
                            }
                        }
                        continue;
                    case GeoArea.OVERLAPS:
                        if (VERBOSE) {
                            log.println("    GeoArea.OVERLAPS: keep splitting");
                        }
                        //log.println("    crosses1");
                        break;
                    case GeoArea.WITHIN:
                        if (VERBOSE) {
                            log.println("    GeoArea.WITHIN: keep splitting");
                        }
                        //log.println("    crosses2");
                        break;
                    case GeoArea.DISJOINT:
                        //log.println("    outside");
                        if (VERBOSE) {
                            log.println("    GeoArea.DISJOINT: drop this cell");
                            for (int docID = 0; docID < numDocs; docID++) {
                                if (cell.contains(docs[docID])) {
                                    log.println("    skip doc=" + docID);
                                }
                            }
                        }
                        continue;
                    default:
                        assert false;
                }
                // Randomly split:
                switch(random().nextInt(3)) {
                    case 0:
                        // Split on X:
                        {
                            int splitValue = RandomNumbers.randomIntBetween(random(), cell.xMinEnc, cell.xMaxEnc);
                            if (VERBOSE) {
                                log.println("    now split on x=" + splitValue);
                            }
                            Cell cell1 = new Cell(cell, cell.xMinEnc, splitValue, cell.yMinEnc, cell.yMaxEnc, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            Cell cell2 = new Cell(cell, splitValue, cell.xMaxEnc, cell.yMinEnc, cell.yMaxEnc, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            if (VERBOSE) {
                                log.println("    split cell1: " + cell1);
                                log.println("    split cell2: " + cell2);
                            }
                            queue.add(cell1);
                            queue.add(cell2);
                        }
                        break;
                    case 1:
                        // Split on Y:
                        {
                            int splitValue = RandomNumbers.randomIntBetween(random(), cell.yMinEnc, cell.yMaxEnc);
                            if (VERBOSE) {
                                log.println("    now split on y=" + splitValue);
                            }
                            Cell cell1 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, cell.yMinEnc, splitValue, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            Cell cell2 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, splitValue, cell.yMaxEnc, cell.zMinEnc, cell.zMaxEnc, cell.splitCount + 1);
                            if (VERBOSE) {
                                log.println("    split cell1: " + cell1);
                                log.println("    split cell2: " + cell2);
                            }
                            queue.add(cell1);
                            queue.add(cell2);
                        }
                        break;
                    case 2:
                        // Split on Z:
                        {
                            int splitValue = RandomNumbers.randomIntBetween(random(), cell.zMinEnc, cell.zMaxEnc);
                            if (VERBOSE) {
                                log.println("    now split on z=" + splitValue);
                            }
                            Cell cell1 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, cell.yMinEnc, cell.yMaxEnc, cell.zMinEnc, splitValue, cell.splitCount + 1);
                            Cell cell2 = new Cell(cell, cell.xMinEnc, cell.xMaxEnc, cell.yMinEnc, cell.yMaxEnc, splitValue, cell.zMaxEnc, cell.splitCount + 1);
                            if (VERBOSE) {
                                log.println("    split cell1: " + cell1);
                                log.println("    split cell2: " + cell2);
                            }
                            queue.add(cell1);
                            queue.add(cell2);
                        }
                        break;
                }
            }
        }
        if (VERBOSE) {
            log.println("  " + hits.size() + " hits");
        }
        // Done matching, now verify:
        boolean fail = false;
        for (int docID = 0; docID < numDocs; docID++) {
            GeoPoint point = docs[docID];
            GeoPoint mappedPoint = unquantizedDocs[docID];
            boolean expected = shape.isWithin(mappedPoint);
            boolean actual = hits.contains(docID);
            if (actual != expected) {
                if (actual) {
                    log.println("doc=" + docID + " should not have matched but did");
                } else {
                    log.println("doc=" + docID + " should match but did not");
                }
                log.println("  point=" + point);
                log.println("  mappedPoint=" + mappedPoint);
                fail = true;
            }
        }
        if (fail) {
            System.out.print(sw.toString());
            fail("invalid hits for shape=" + shape);
        }
    }
}
Also used : GeoShape(org.apache.lucene.spatial3d.geom.GeoShape) ArrayList(java.util.ArrayList) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint) GeoArea(org.apache.lucene.spatial3d.geom.GeoArea) StringWriter(java.io.StringWriter) XYZBounds(org.apache.lucene.spatial3d.geom.XYZBounds) PrintWriter(java.io.PrintWriter) HashSet(java.util.HashSet)

Example 4 with XYZBounds

use of org.apache.lucene.spatial3d.geom.XYZBounds in project lucene-solr by apache.

the class TestGeo3DPoint method explain.

public static String explain(String fieldName, GeoShape shape, GeoPoint targetDocPoint, GeoPoint scaledDocPoint, IndexReader reader, int docID) throws Exception {
    final XYZBounds bounds = new XYZBounds();
    shape.getBounds(bounds);
    // First find the leaf reader that owns this doc:
    int subIndex = ReaderUtil.subIndex(docID, reader.leaves());
    LeafReader leafReader = reader.leaves().get(subIndex).reader();
    StringBuilder b = new StringBuilder();
    b.append("target is in leaf " + leafReader + " of full reader " + reader + "\n");
    DocIdSetBuilder hits = new DocIdSetBuilder(leafReader.maxDoc());
    ExplainingVisitor visitor = new ExplainingVisitor(shape, targetDocPoint, scaledDocPoint, new PointInShapeIntersectVisitor(hits, shape, bounds), docID - reader.leaves().get(subIndex).docBase, 3, Integer.BYTES, b);
    // Do first phase, where we just figure out the "path" that leads to the target docID:
    leafReader.getPointValues(fieldName).intersect(visitor);
    // Do second phase, where we we see how the wrapped visitor responded along that path:
    visitor.startSecondPhase();
    leafReader.getPointValues(fieldName).intersect(visitor);
    return b.toString();
}
Also used : LeafReader(org.apache.lucene.index.LeafReader) XYZBounds(org.apache.lucene.spatial3d.geom.XYZBounds) DocIdSetBuilder(org.apache.lucene.util.DocIdSetBuilder) GeoPoint(org.apache.lucene.spatial3d.geom.GeoPoint)

Aggregations

XYZBounds (org.apache.lucene.spatial3d.geom.XYZBounds)4 GeoPoint (org.apache.lucene.spatial3d.geom.GeoPoint)3 HashSet (java.util.HashSet)2 GeoShape (org.apache.lucene.spatial3d.geom.GeoShape)2 IOException (java.io.IOException)1 PrintWriter (java.io.PrintWriter)1 StringWriter (java.io.StringWriter)1 ArrayList (java.util.ArrayList)1 Document (org.apache.lucene.document.Document)1 NumericDocValuesField (org.apache.lucene.document.NumericDocValuesField)1 IndexReader (org.apache.lucene.index.IndexReader)1 IndexWriter (org.apache.lucene.index.IndexWriter)1 IndexWriterConfig (org.apache.lucene.index.IndexWriterConfig)1 LeafReader (org.apache.lucene.index.LeafReader)1 LeafReaderContext (org.apache.lucene.index.LeafReaderContext)1 NumericDocValues (org.apache.lucene.index.NumericDocValues)1 Term (org.apache.lucene.index.Term)1 IndexSearcher (org.apache.lucene.search.IndexSearcher)1 Query (org.apache.lucene.search.Query)1 SimpleCollector (org.apache.lucene.search.SimpleCollector)1