mirror of https://github.com/apache/lucene.git
LUCENE-4742: Rename spatial Node back to Cell
git-svn-id: https://svn.apache.org/repos/asf/lucene/dev/trunk@1462090 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
6448dce4ea
commit
56a18440e2
|
@ -21,7 +21,7 @@ import com.spatial4j.core.shape.Shape;
|
|||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.index.TermsEnum;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
@ -84,13 +84,13 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
* that there are indexed terms; if not it quickly returns null. Then it calls
|
||||
* {@link #start()} so a subclass can set up a return value, like an
|
||||
* {@link org.apache.lucene.util.OpenBitSet}. Then it starts the traversal
|
||||
* process, calling {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Node)}
|
||||
* process, calling {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Cell)}
|
||||
* which by default finds the top cells that intersect {@code queryShape}. If
|
||||
* there isn't an indexed cell for a corresponding cell returned for this
|
||||
* method then it's short-circuited until it finds one, at which point
|
||||
* {@link #visit(org.apache.lucene.spatial.prefix.tree.Node)} is called. At
|
||||
* {@link #visit(org.apache.lucene.spatial.prefix.tree.Cell)} is called. At
|
||||
* some depths, of the tree, the algorithm switches to a scanning mode that
|
||||
* finds calls {@link #visitScanned(org.apache.lucene.spatial.prefix.tree.Node)}
|
||||
* finds calls {@link #visitScanned(org.apache.lucene.spatial.prefix.tree.Cell)}
|
||||
* for each leaf cell found.
|
||||
*
|
||||
* @lucene.internal
|
||||
|
@ -113,7 +113,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
|
||||
private VNode curVNode;//current pointer, derived from query shape
|
||||
private BytesRef curVNodeTerm = new BytesRef();//curVNode.cell's term.
|
||||
private Node scanCell;
|
||||
private Cell scanCell;
|
||||
|
||||
private BytesRef thisTerm;//the result of termsEnum.term()
|
||||
|
||||
|
@ -132,7 +132,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
return null; // all done
|
||||
|
||||
curVNode = new VNode(null);
|
||||
curVNode.reset(grid.getWorldNode());
|
||||
curVNode.reset(grid.getWorldCell());
|
||||
|
||||
start();
|
||||
|
||||
|
@ -198,11 +198,11 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
return finish();
|
||||
}
|
||||
|
||||
/** Called initially, and whenever {@link #visit(org.apache.lucene.spatial.prefix.tree.Node)}
|
||||
/** Called initially, and whenever {@link #visit(org.apache.lucene.spatial.prefix.tree.Cell)}
|
||||
* returns true. */
|
||||
private void addIntersectingChildren() throws IOException {
|
||||
assert thisTerm != null;
|
||||
Node cell = curVNode.cell;
|
||||
Cell cell = curVNode.cell;
|
||||
if (cell.getLevel() >= detailLevel)
|
||||
throw new IllegalStateException("Spatial logic error");
|
||||
|
||||
|
@ -211,7 +211,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
//If the next indexed term just adds a leaf marker ('+') to cell,
|
||||
// then add all of those docs
|
||||
assert StringHelper.startsWith(thisTerm, curVNodeTerm);
|
||||
scanCell = grid.getNode(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
|
||||
scanCell = grid.getCell(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
|
||||
if (scanCell.getLevel() == cell.getLevel() && scanCell.isLeaf()) {
|
||||
visitLeaf(scanCell);
|
||||
//advance
|
||||
|
@ -230,7 +230,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
if (!scan) {
|
||||
//Divide & conquer (ultimately termsEnum.seek())
|
||||
|
||||
Iterator<Node> subCellsIter = findSubCellsToVisit(cell);
|
||||
Iterator<Cell> subCellsIter = findSubCellsToVisit(cell);
|
||||
if (!subCellsIter.hasNext())//not expected
|
||||
return;
|
||||
curVNode.children = new VNodeCellIterator(subCellsIter, new VNode(curVNode));
|
||||
|
@ -248,7 +248,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
* guaranteed to have an intersection and thus this must return some number
|
||||
* of nodes.
|
||||
*/
|
||||
protected Iterator<Node> findSubCellsToVisit(Node cell) {
|
||||
protected Iterator<Cell> findSubCellsToVisit(Cell cell) {
|
||||
return cell.getSubCells(queryShape).iterator();
|
||||
}
|
||||
|
||||
|
@ -256,13 +256,13 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
* Scans ({@code termsEnum.next()}) terms until a term is found that does
|
||||
* not start with curVNode's cell. If it finds a leaf cell or a cell at
|
||||
* level {@code scanDetailLevel} then it calls {@link
|
||||
* #visitScanned(org.apache.lucene.spatial.prefix.tree.Node)}.
|
||||
* #visitScanned(org.apache.lucene.spatial.prefix.tree.Cell)}.
|
||||
*/
|
||||
protected void scan(int scanDetailLevel) throws IOException {
|
||||
for (;
|
||||
thisTerm != null && StringHelper.startsWith(thisTerm, curVNodeTerm);
|
||||
thisTerm = termsEnum.next()) {
|
||||
scanCell = grid.getNode(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
|
||||
scanCell = grid.getCell(thisTerm.bytes, thisTerm.offset, thisTerm.length, scanCell);
|
||||
|
||||
int termLevel = scanCell.getLevel();
|
||||
if (termLevel > scanDetailLevel)
|
||||
|
@ -276,10 +276,10 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
/** Used for {@link VNode#children}. */
|
||||
private class VNodeCellIterator implements Iterator<VNode> {
|
||||
|
||||
final Iterator<Node> cellIter;
|
||||
final Iterator<Cell> cellIter;
|
||||
private final VNode vNode;
|
||||
|
||||
VNodeCellIterator(Iterator<Node> cellIter, VNode vNode) {
|
||||
VNodeCellIterator(Iterator<Cell> cellIter, VNode vNode) {
|
||||
this.cellIter = cellIter;
|
||||
this.vNode = vNode;
|
||||
}
|
||||
|
@ -309,26 +309,26 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
|
||||
/**
|
||||
* Visit an indexed cell returned from
|
||||
* {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Node)}.
|
||||
* {@link #findSubCellsToVisit(org.apache.lucene.spatial.prefix.tree.Cell)}.
|
||||
*
|
||||
* @param cell An intersecting cell.
|
||||
* @return true to descend to more levels. It is an error to return true
|
||||
* if cell.level == detailLevel
|
||||
*/
|
||||
protected abstract boolean visit(Node cell) throws IOException;
|
||||
protected abstract boolean visit(Cell cell) throws IOException;
|
||||
|
||||
/**
|
||||
* Called after visit() returns true and an indexed leaf cell is found. An
|
||||
* indexed leaf cell means associated documents generally won't be found at
|
||||
* further detail levels.
|
||||
*/
|
||||
protected abstract void visitLeaf(Node cell) throws IOException;
|
||||
protected abstract void visitLeaf(Cell cell) throws IOException;
|
||||
|
||||
/**
|
||||
* The cell is either indexed as a leaf or is the last level of detail. It
|
||||
* might not even intersect the query shape, so be sure to check for that.
|
||||
*/
|
||||
protected abstract void visitScanned(Node cell) throws IOException;
|
||||
protected abstract void visitScanned(Cell cell) throws IOException;
|
||||
|
||||
|
||||
protected void preSiblings(VNode vNode) throws IOException {
|
||||
|
@ -339,7 +339,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
}//class VisitorTemplate
|
||||
|
||||
/**
|
||||
* A Visitor Node/Cell found via the query shape for {@link VisitorTemplate}.
|
||||
* A Visitor Cell/Cell found via the query shape for {@link VisitorTemplate}.
|
||||
* Sometimes these are reset(cell). It's like a LinkedList node but forms a
|
||||
* tree.
|
||||
*
|
||||
|
@ -353,7 +353,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
|
||||
final VNode parent;//only null at the root
|
||||
Iterator<VNode> children;//null, then sometimes set, then null
|
||||
Node cell;//not null (except initially before reset())
|
||||
Cell cell;//not null (except initially before reset())
|
||||
|
||||
/**
|
||||
* call reset(cell) after to set the cell.
|
||||
|
@ -362,7 +362,7 @@ public abstract class AbstractVisitingPrefixTreeFilter extends AbstractPrefixTre
|
|||
this.parent = parent;
|
||||
}
|
||||
|
||||
void reset(Node cell) {
|
||||
void reset(Cell cell) {
|
||||
assert cell != null;
|
||||
this.cell = cell;
|
||||
assert children == null;
|
||||
|
|
|
@ -21,7 +21,7 @@ import com.spatial4j.core.shape.Shape;
|
|||
import com.spatial4j.core.shape.SpatialRelation;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -66,7 +66,7 @@ public class IntersectsPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter
|
|||
}
|
||||
|
||||
@Override
|
||||
protected boolean visit(Node cell) throws IOException {
|
||||
protected boolean visit(Cell cell) throws IOException {
|
||||
if (cell.getShapeRel() == SpatialRelation.WITHIN || cell.getLevel() == detailLevel) {
|
||||
collectDocs(results);
|
||||
return false;
|
||||
|
@ -75,12 +75,12 @@ public class IntersectsPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void visitLeaf(Node cell) throws IOException {
|
||||
protected void visitLeaf(Cell cell) throws IOException {
|
||||
collectDocs(results);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void visitScanned(Node cell) throws IOException {
|
||||
protected void visitScanned(Cell cell) throws IOException {
|
||||
Shape cShape;
|
||||
//if this cell represents a point, use the cell center vs the box
|
||||
// TODO this behavior is debatable; might want to be configurable
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.lucene.spatial.prefix;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -15,10 +17,8 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.lucene.spatial.prefix;
|
||||
|
||||
import com.spatial4j.core.shape.Point;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.spatial.util.ShapeFieldCacheProvider;
|
||||
import org.apache.lucene.util.BytesRef;
|
||||
|
@ -40,11 +40,11 @@ public class PointPrefixTreeFieldCacheProvider extends ShapeFieldCacheProvider<P
|
|||
this.grid = grid;
|
||||
}
|
||||
|
||||
private Node scanCell = null;//re-used in readShape to save GC
|
||||
private Cell scanCell = null;//re-used in readShape to save GC
|
||||
|
||||
@Override
|
||||
protected Point readShape(BytesRef term) {
|
||||
scanCell = grid.getNode(term.bytes, term.offset, term.length, scanCell);
|
||||
scanCell = grid.getCell(term.bytes, term.offset, term.length, scanCell);
|
||||
if (scanCell.getLevel() == grid.getMaxLevels() && !scanCell.isLeaf())
|
||||
return scanCell.getCenter();
|
||||
return null;
|
||||
|
|
|
@ -26,7 +26,7 @@ import org.apache.lucene.document.FieldType;
|
|||
import org.apache.lucene.index.FieldInfo;
|
||||
import org.apache.lucene.queries.function.ValueSource;
|
||||
import org.apache.lucene.spatial.SpatialStrategy;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
import org.apache.lucene.spatial.util.ShapeFieldCacheDistanceValueSource;
|
||||
|
@ -125,7 +125,7 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy {
|
|||
|
||||
public Field[] createIndexableFields(Shape shape, double distErr) {
|
||||
int detailLevel = grid.getLevelForDistance(distErr);
|
||||
List<Node> cells = grid.getNodes(shape, detailLevel, true, simplifyIndexedCells);//intermediates cells
|
||||
List<Cell> cells = grid.getCells(shape, detailLevel, true, simplifyIndexedCells);//intermediates cells
|
||||
|
||||
//TODO is CellTokenStream supposed to be re-used somehow? see Uwe's comments:
|
||||
// http://code.google.com/p/lucene-spatial-playground/issues/detail?id=4
|
||||
|
@ -151,9 +151,9 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy {
|
|||
|
||||
private final CharTermAttribute termAtt = addAttribute(CharTermAttribute.class);
|
||||
|
||||
private Iterator<Node> iter = null;
|
||||
private Iterator<Cell> iter = null;
|
||||
|
||||
public CellTokenStream(Iterator<Node> tokens) {
|
||||
public CellTokenStream(Iterator<Cell> tokens) {
|
||||
this.iter = tokens;
|
||||
}
|
||||
|
||||
|
@ -164,12 +164,12 @@ public abstract class PrefixTreeStrategy extends SpatialStrategy {
|
|||
clearAttributes();
|
||||
if (nextTokenStringNeedingLeaf != null) {
|
||||
termAtt.append(nextTokenStringNeedingLeaf);
|
||||
termAtt.append((char) Node.LEAF_BYTE);
|
||||
termAtt.append((char) Cell.LEAF_BYTE);
|
||||
nextTokenStringNeedingLeaf = null;
|
||||
return true;
|
||||
}
|
||||
if (iter.hasNext()) {
|
||||
Node cell = iter.next();
|
||||
Cell cell = iter.next();
|
||||
CharSequence token = cell.getTokenString();
|
||||
termAtt.append(token);
|
||||
if (cell.isLeaf())
|
||||
|
|
|
@ -20,7 +20,7 @@ package org.apache.lucene.spatial.prefix;
|
|||
import com.spatial4j.core.shape.Shape;
|
||||
import org.apache.lucene.queries.TermsFilter;
|
||||
import org.apache.lucene.search.Filter;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
import org.apache.lucene.spatial.query.SpatialOperation;
|
||||
|
@ -31,7 +31,7 @@ import java.util.List;
|
|||
|
||||
/**
|
||||
* A basic implementation of {@link PrefixTreeStrategy} using a large {@link
|
||||
* TermsFilter} of all the nodes from {@link SpatialPrefixTree#getNodes(com.spatial4j.core.shape.Shape,
|
||||
* TermsFilter} of all the cells from {@link SpatialPrefixTree#getCells(com.spatial4j.core.shape.Shape,
|
||||
* int, boolean, boolean)}. It only supports the search of indexed Point shapes.
|
||||
* <p/>
|
||||
* The precision of query shapes (distErrPct) is an important factor in using
|
||||
|
@ -55,12 +55,12 @@ public class TermQueryPrefixTreeStrategy extends PrefixTreeStrategy {
|
|||
|
||||
Shape shape = args.getShape();
|
||||
int detailLevel = grid.getLevelForDistance(args.resolveDistErr(ctx, distErrPct));
|
||||
List<Node> cells = grid.getNodes(shape, detailLevel,
|
||||
List<Cell> cells = grid.getCells(shape, detailLevel,
|
||||
false,//no parents
|
||||
true);//simplify
|
||||
BytesRef[] terms = new BytesRef[cells.size()];
|
||||
int i = 0;
|
||||
for (Node cell : cells) {
|
||||
for (Cell cell : cells) {
|
||||
terms[i++] = new BytesRef(cell.getTokenString());
|
||||
}
|
||||
return new TermsFilter(getFieldName(), terms);
|
||||
|
|
|
@ -26,7 +26,7 @@ import com.spatial4j.core.shape.Shape;
|
|||
import com.spatial4j.core.shape.SpatialRelation;
|
||||
import org.apache.lucene.index.AtomicReaderContext;
|
||||
import org.apache.lucene.search.DocIdSet;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.util.Bits;
|
||||
import org.apache.lucene.util.FixedBitSet;
|
||||
|
@ -135,13 +135,13 @@ public class WithinPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected Iterator<Node> findSubCellsToVisit(Node cell) {
|
||||
protected Iterator<Cell> findSubCellsToVisit(Cell cell) {
|
||||
//use buffered query shape instead of orig. Works with null too.
|
||||
return cell.getSubCells(bufferedQueryShape).iterator();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean visit(Node cell) throws IOException {
|
||||
protected boolean visit(Cell cell) throws IOException {
|
||||
//cell.relate is based on the bufferedQueryShape; we need to examine what
|
||||
// the relation is against the queryShape
|
||||
visitRelation = cell.getShape().relate(queryShape);
|
||||
|
@ -159,7 +159,7 @@ public class WithinPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void visitLeaf(Node cell) throws IOException {
|
||||
protected void visitLeaf(Cell cell) throws IOException {
|
||||
SpatialRelation relation = visitRelation;
|
||||
assert visitRelation == cell.getShape().relate(queryShape);
|
||||
if (relation.intersects()) {
|
||||
|
@ -170,7 +170,7 @@ public class WithinPrefixTreeFilter extends AbstractVisitingPrefixTreeFilter {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void visitScanned(Node cell) throws IOException {
|
||||
protected void visitScanned(Cell cell) throws IOException {
|
||||
if (queryShape.relate(cell.getShape()).intersects()) {
|
||||
collectDocs(inside);
|
||||
} else {
|
||||
|
|
|
@ -32,7 +32,7 @@ import java.util.List;
|
|||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
public abstract class Node implements Comparable<Node> {
|
||||
public abstract class Cell implements Comparable<Cell> {
|
||||
public static final byte LEAF_BYTE = '+';//NOTE: must sort before letters & numbers
|
||||
|
||||
/*
|
||||
|
@ -58,7 +58,7 @@ public abstract class Node implements Comparable<Node> {
|
|||
*/
|
||||
protected boolean leaf;
|
||||
|
||||
protected Node(String token) {
|
||||
protected Cell(String token) {
|
||||
this.token = token;
|
||||
if (token.length() > 0 && token.charAt(token.length() - 1) == (char) LEAF_BYTE) {
|
||||
this.token = token.substring(0, token.length() - 1);
|
||||
|
@ -69,7 +69,7 @@ public abstract class Node implements Comparable<Node> {
|
|||
getShape();//ensure any lazy instantiation completes to make this threadsafe
|
||||
}
|
||||
|
||||
protected Node(byte[] bytes, int off, int len) {
|
||||
protected Cell(byte[] bytes, int off, int len) {
|
||||
this.bytes = bytes;
|
||||
this.b_off = off;
|
||||
this.b_len = len;
|
||||
|
@ -149,8 +149,8 @@ public abstract class Node implements Comparable<Node> {
|
|||
* Like {@link #getSubCells()} but with the results filtered by a shape. If
|
||||
* that shape is a {@link com.spatial4j.core.shape.Point} then it must call
|
||||
* {@link #getSubCell(com.spatial4j.core.shape.Point)}. The returned cells
|
||||
* should have {@link Node#getShapeRel()} set to their relation with {@code
|
||||
* shapeFilter}. In addition, {@link org.apache.lucene.spatial.prefix.tree.Node#isLeaf()}
|
||||
* should have {@link Cell#getShapeRel()} set to their relation with {@code
|
||||
* shapeFilter}. In addition, {@link Cell#isLeaf()}
|
||||
* must be true when that relation is WITHIN.
|
||||
* <p/>
|
||||
* Precondition: Never called when getLevel() == maxLevel.
|
||||
|
@ -158,22 +158,22 @@ public abstract class Node implements Comparable<Node> {
|
|||
* @param shapeFilter an optional filter for the returned cells.
|
||||
* @return A set of cells (no dups), sorted. Not Modifiable.
|
||||
*/
|
||||
public Collection<Node> getSubCells(Shape shapeFilter) {
|
||||
public Collection<Cell> getSubCells(Shape shapeFilter) {
|
||||
//Note: Higher-performing subclasses might override to consider the shape filter to generate fewer cells.
|
||||
if (shapeFilter instanceof Point) {
|
||||
Node subCell = getSubCell((Point) shapeFilter);
|
||||
Cell subCell = getSubCell((Point) shapeFilter);
|
||||
subCell.shapeRel = SpatialRelation.CONTAINS;
|
||||
return Collections.singletonList(subCell);
|
||||
}
|
||||
Collection<Node> cells = getSubCells();
|
||||
Collection<Cell> cells = getSubCells();
|
||||
|
||||
if (shapeFilter == null) {
|
||||
return cells;
|
||||
}
|
||||
|
||||
//TODO change API to return a filtering iterator
|
||||
List<Node> copy = new ArrayList<Node>(cells.size());
|
||||
for (Node cell : cells) {
|
||||
List<Cell> copy = new ArrayList<Cell>(cells.size());
|
||||
for (Cell cell : cells) {
|
||||
SpatialRelation rel = cell.getShape().relate(shapeFilter);
|
||||
if (rel == SpatialRelation.DISJOINT)
|
||||
continue;
|
||||
|
@ -192,7 +192,7 @@ public abstract class Node implements Comparable<Node> {
|
|||
* <p/>
|
||||
* Precondition: this.getShape().relate(p) != DISJOINT.
|
||||
*/
|
||||
public abstract Node getSubCell(Point p);
|
||||
public abstract Cell getSubCell(Point p);
|
||||
|
||||
//TODO Cell getSubCell(byte b)
|
||||
|
||||
|
@ -202,7 +202,7 @@ public abstract class Node implements Comparable<Node> {
|
|||
*
|
||||
* @return A set of cells (no dups), sorted, modifiable, not empty, not null.
|
||||
*/
|
||||
protected abstract Collection<Node> getSubCells();
|
||||
protected abstract Collection<Cell> getSubCells();
|
||||
|
||||
/**
|
||||
* {@link #getSubCells()}.size() -- usually a constant. Should be >=2
|
||||
|
@ -216,13 +216,13 @@ public abstract class Node implements Comparable<Node> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Node o) {
|
||||
public int compareTo(Cell o) {
|
||||
return getTokenString().compareTo(o.getTokenString());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
return !(obj == null || !(obj instanceof Node)) && getTokenString().equals(((Node) obj).getTokenString());
|
||||
return !(obj == null || !(obj instanceof Cell)) && getTokenString().equals(((Cell) obj).getTokenString());
|
||||
}
|
||||
|
||||
@Override
|
|
@ -79,21 +79,21 @@ public class GeohashPrefixTree extends SpatialPrefixTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Node getNode(Point p, int level) {
|
||||
public Cell getCell(Point p, int level) {
|
||||
return new GhCell(GeohashUtils.encodeLatLon(p.getY(), p.getX(), level));//args are lat,lon (y,x)
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode(String token) {
|
||||
public Cell getCell(String token) {
|
||||
return new GhCell(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode(byte[] bytes, int offset, int len) {
|
||||
public Cell getCell(byte[] bytes, int offset, int len) {
|
||||
return new GhCell(bytes, offset, len);
|
||||
}
|
||||
|
||||
class GhCell extends Node {
|
||||
class GhCell extends Cell {
|
||||
GhCell(String token) {
|
||||
super(token);
|
||||
}
|
||||
|
@ -109,9 +109,9 @@ public class GeohashPrefixTree extends SpatialPrefixTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<Node> getSubCells() {
|
||||
public Collection<Cell> getSubCells() {
|
||||
String[] hashes = GeohashUtils.getSubGeohashes(getGeohash());//sorted
|
||||
List<Node> cells = new ArrayList<Node>(hashes.length);
|
||||
List<Cell> cells = new ArrayList<Cell>(hashes.length);
|
||||
for (String hash : hashes) {
|
||||
cells.add(new GhCell(hash));
|
||||
}
|
||||
|
@ -124,8 +124,8 @@ public class GeohashPrefixTree extends SpatialPrefixTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Node getSubCell(Point p) {
|
||||
return GeohashPrefixTree.this.getNode(p,getLevel()+1);//not performant!
|
||||
public Cell getSubCell(Point p) {
|
||||
return GeohashPrefixTree.this.getCell(p, getLevel() + 1);//not performant!
|
||||
}
|
||||
|
||||
private Shape shape;//cache
|
||||
|
|
|
@ -33,7 +33,7 @@ import java.util.Locale;
|
|||
/**
|
||||
* A {@link SpatialPrefixTree} which uses a
|
||||
* <a href="http://en.wikipedia.org/wiki/Quadtree">quad tree</a> in which an
|
||||
* indexed term will be generated for each node, 'A', 'B', 'C', 'D'.
|
||||
* indexed term will be generated for each cell, 'A', 'B', 'C', 'D'.
|
||||
*
|
||||
* @lucene.experimental
|
||||
*/
|
||||
|
@ -140,19 +140,19 @@ public class QuadPrefixTree extends SpatialPrefixTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Node getNode(Point p, int level) {
|
||||
List<Node> cells = new ArrayList<Node>(1);
|
||||
public Cell getCell(Point p, int level) {
|
||||
List<Cell> cells = new ArrayList<Cell>(1);
|
||||
build(xmid, ymid, 0, cells, new StringBuilder(), ctx.makePoint(p.getX(),p.getY()), level);
|
||||
return cells.get(0);//note cells could be longer if p on edge
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode(String token) {
|
||||
public Cell getCell(String token) {
|
||||
return new QuadCell(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Node getNode(byte[] bytes, int offset, int len) {
|
||||
public Cell getCell(byte[] bytes, int offset, int len) {
|
||||
return new QuadCell(bytes, offset, len);
|
||||
}
|
||||
|
||||
|
@ -160,7 +160,7 @@ public class QuadPrefixTree extends SpatialPrefixTree {
|
|||
double x,
|
||||
double y,
|
||||
int level,
|
||||
List<Node> matches,
|
||||
List<Cell> matches,
|
||||
StringBuilder str,
|
||||
Shape shape,
|
||||
int maxLevel) {
|
||||
|
@ -186,7 +186,7 @@ public class QuadPrefixTree extends SpatialPrefixTree {
|
|||
double cx,
|
||||
double cy,
|
||||
int level,
|
||||
List<Node> matches,
|
||||
List<Cell> matches,
|
||||
StringBuilder str,
|
||||
Shape shape,
|
||||
int maxLevel) {
|
||||
|
@ -217,7 +217,7 @@ public class QuadPrefixTree extends SpatialPrefixTree {
|
|||
str.setLength(strlen);
|
||||
}
|
||||
|
||||
class QuadCell extends Node {
|
||||
class QuadCell extends Cell {
|
||||
|
||||
public QuadCell(String token) {
|
||||
super(token);
|
||||
|
@ -239,8 +239,8 @@ public class QuadPrefixTree extends SpatialPrefixTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Collection<Node> getSubCells() {
|
||||
List<Node> cells = new ArrayList<Node>(4);
|
||||
public Collection<Cell> getSubCells() {
|
||||
List<Cell> cells = new ArrayList<Cell>(4);
|
||||
cells.add(new QuadCell(getTokenString()+"A"));
|
||||
cells.add(new QuadCell(getTokenString()+"B"));
|
||||
cells.add(new QuadCell(getTokenString()+"C"));
|
||||
|
@ -254,8 +254,8 @@ public class QuadPrefixTree extends SpatialPrefixTree {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Node getSubCell(Point p) {
|
||||
return QuadPrefixTree.this.getNode(p,getLevel()+1);//not performant!
|
||||
public Cell getSubCell(Point p) {
|
||||
return QuadPrefixTree.this.getCell(p, getLevel() + 1);//not performant!
|
||||
}
|
||||
|
||||
private Shape shape;//cache
|
||||
|
|
|
@ -79,8 +79,8 @@ public abstract class SpatialPrefixTree {
|
|||
public abstract int getLevelForDistance(double dist);
|
||||
|
||||
/**
|
||||
* Given a node having the specified level, returns the distance from opposite
|
||||
* corners. Since this might very depending on where the node is, this method
|
||||
* Given a cell having the specified level, returns the distance from opposite
|
||||
* corners. Since this might very depending on where the cell is, this method
|
||||
* may over-estimate.
|
||||
*
|
||||
* @param level [1 to maxLevels]
|
||||
|
@ -90,8 +90,8 @@ public abstract class SpatialPrefixTree {
|
|||
if (level < 1 || level > getMaxLevels())
|
||||
throw new IllegalArgumentException("Level must be in 1 to maxLevels range");
|
||||
//TODO cache for each level
|
||||
Node node = getNode(ctx.getWorldBounds().getCenter(), level);
|
||||
Rectangle bbox = node.getShape().getBoundingBox();
|
||||
Cell cell = getCell(ctx.getWorldBounds().getCenter(), level);
|
||||
Rectangle bbox = cell.getShape().getBoundingBox();
|
||||
double width = bbox.getWidth();
|
||||
double height = bbox.getHeight();
|
||||
//Use standard cartesian hypotenuse. For geospatial, this answer is larger
|
||||
|
@ -99,32 +99,32 @@ public abstract class SpatialPrefixTree {
|
|||
return Math.sqrt(width * width + height * height);
|
||||
}
|
||||
|
||||
private transient Node worldNode;//cached
|
||||
private transient Cell worldCell;//cached
|
||||
|
||||
/**
|
||||
* Returns the level 0 cell which encompasses all spatial data. Equivalent to {@link #getNode(String)} with "".
|
||||
* Returns the level 0 cell which encompasses all spatial data. Equivalent to {@link #getCell(String)} with "".
|
||||
* This cell is threadsafe, just like a spatial prefix grid is, although cells aren't
|
||||
* generally threadsafe.
|
||||
* TODO rename to getTopCell or is this fine?
|
||||
*/
|
||||
public Node getWorldNode() {
|
||||
if (worldNode == null) {
|
||||
worldNode = getNode("");
|
||||
public Cell getWorldCell() {
|
||||
if (worldCell == null) {
|
||||
worldCell = getCell("");
|
||||
}
|
||||
return worldNode;
|
||||
return worldCell;
|
||||
}
|
||||
|
||||
/**
|
||||
* The cell for the specified token. The empty string should be equal to {@link #getWorldNode()}.
|
||||
* The cell for the specified token. The empty string should be equal to {@link #getWorldCell()}.
|
||||
* Precondition: Never called when token length > maxLevel.
|
||||
*/
|
||||
public abstract Node getNode(String token);
|
||||
public abstract Cell getCell(String token);
|
||||
|
||||
public abstract Node getNode(byte[] bytes, int offset, int len);
|
||||
public abstract Cell getCell(byte[] bytes, int offset, int len);
|
||||
|
||||
public final Node getNode(byte[] bytes, int offset, int len, Node target) {
|
||||
public final Cell getCell(byte[] bytes, int offset, int len, Cell target) {
|
||||
if (target == null) {
|
||||
return getNode(bytes, offset, len);
|
||||
return getCell(bytes, offset, len);
|
||||
}
|
||||
|
||||
target.reset(bytes, offset, len);
|
||||
|
@ -134,8 +134,8 @@ public abstract class SpatialPrefixTree {
|
|||
/**
|
||||
* Returns the cell containing point {@code p} at the specified {@code level}.
|
||||
*/
|
||||
protected Node getNode(Point p, int level) {
|
||||
return getNodes(p, level, false).get(0);
|
||||
protected Cell getCell(Point p, int level) {
|
||||
return getCells(p, level, false).get(0);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -144,7 +144,7 @@ public abstract class SpatialPrefixTree {
|
|||
* leaf and none of its children are added.
|
||||
* <p/>
|
||||
* This implementation checks if shape is a Point and if so returns {@link
|
||||
* #getNodes(com.spatial4j.core.shape.Point, int, boolean)}.
|
||||
* #getCells(com.spatial4j.core.shape.Point, int, boolean)}.
|
||||
*
|
||||
* @param shape the shape; non-null
|
||||
* @param detailLevel the maximum detail level to get cells for
|
||||
|
@ -155,45 +155,45 @@ public abstract class SpatialPrefixTree {
|
|||
* ~20-25% fewer cells.
|
||||
* @return a set of cells (no dups), sorted, immutable, non-null
|
||||
*/
|
||||
public List<Node> getNodes(Shape shape, int detailLevel, boolean inclParents,
|
||||
public List<Cell> getCells(Shape shape, int detailLevel, boolean inclParents,
|
||||
boolean simplify) {
|
||||
//TODO consider an on-demand iterator -- it won't build up all cells in memory.
|
||||
if (detailLevel > maxLevels) {
|
||||
throw new IllegalArgumentException("detailLevel > maxLevels");
|
||||
}
|
||||
if (shape instanceof Point) {
|
||||
return getNodes((Point) shape, detailLevel, inclParents);
|
||||
return getCells((Point) shape, detailLevel, inclParents);
|
||||
}
|
||||
List<Node> cells = new ArrayList<Node>(inclParents ? 4096 : 2048);
|
||||
recursiveGetNodes(getWorldNode(), shape, detailLevel, inclParents, simplify, cells);
|
||||
List<Cell> cells = new ArrayList<Cell>(inclParents ? 4096 : 2048);
|
||||
recursiveGetCells(getWorldCell(), shape, detailLevel, inclParents, simplify, cells);
|
||||
return cells;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if node was added as a leaf. If it wasn't it recursively
|
||||
* Returns true if cell was added as a leaf. If it wasn't it recursively
|
||||
* descends.
|
||||
*/
|
||||
private boolean recursiveGetNodes(Node node, Shape shape, int detailLevel,
|
||||
private boolean recursiveGetCells(Cell cell, Shape shape, int detailLevel,
|
||||
boolean inclParents, boolean simplify,
|
||||
List<Node> result) {
|
||||
if (node.getLevel() == detailLevel) {
|
||||
node.setLeaf();//FYI might already be a leaf
|
||||
List<Cell> result) {
|
||||
if (cell.getLevel() == detailLevel) {
|
||||
cell.setLeaf();//FYI might already be a leaf
|
||||
}
|
||||
if (node.isLeaf()) {
|
||||
result.add(node);
|
||||
if (cell.isLeaf()) {
|
||||
result.add(cell);
|
||||
return true;
|
||||
}
|
||||
if (inclParents && node.getLevel() != 0)
|
||||
result.add(node);
|
||||
if (inclParents && cell.getLevel() != 0)
|
||||
result.add(cell);
|
||||
|
||||
Collection<Node> subCells = node.getSubCells(shape);
|
||||
Collection<Cell> subCells = cell.getSubCells(shape);
|
||||
int leaves = 0;
|
||||
for (Node subCell : subCells) {
|
||||
if (recursiveGetNodes(subCell, shape, detailLevel, inclParents, simplify, result))
|
||||
for (Cell subCell : subCells) {
|
||||
if (recursiveGetCells(subCell, shape, detailLevel, inclParents, simplify, result))
|
||||
leaves++;
|
||||
}
|
||||
//can we simplify?
|
||||
if (simplify && leaves == node.getSubCellsSize() && node.getLevel() != 0) {
|
||||
if (simplify && leaves == cell.getSubCellsSize() && cell.getLevel() != 0) {
|
||||
//Optimization: substitute the parent as a leaf instead of adding all
|
||||
// children as leaves
|
||||
|
||||
|
@ -201,10 +201,10 @@ public abstract class SpatialPrefixTree {
|
|||
do {
|
||||
result.remove(result.size() - 1);//remove last
|
||||
} while (--leaves > 0);
|
||||
//add node as the leaf
|
||||
node.setLeaf();
|
||||
//add cell as the leaf
|
||||
cell.setLeaf();
|
||||
if (!inclParents) // otherwise it was already added up above
|
||||
result.add(node);
|
||||
result.add(cell);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
@ -212,23 +212,23 @@ public abstract class SpatialPrefixTree {
|
|||
|
||||
/**
|
||||
* A Point-optimized implementation of
|
||||
* {@link #getNodes(com.spatial4j.core.shape.Shape, int, boolean, boolean)}. That
|
||||
* {@link #getCells(com.spatial4j.core.shape.Shape, int, boolean, boolean)}. That
|
||||
* method in facts calls this for points.
|
||||
* <p/>
|
||||
* This implementation depends on {@link #getNode(String)} being fast, as its
|
||||
* This implementation depends on {@link #getCell(String)} being fast, as its
|
||||
* called repeatedly when incPlarents is true.
|
||||
*/
|
||||
public List<Node> getNodes(Point p, int detailLevel, boolean inclParents) {
|
||||
Node cell = getNode(p, detailLevel);
|
||||
public List<Cell> getCells(Point p, int detailLevel, boolean inclParents) {
|
||||
Cell cell = getCell(p, detailLevel);
|
||||
if (!inclParents) {
|
||||
return Collections.singletonList(cell);
|
||||
}
|
||||
|
||||
String endToken = cell.getTokenString();
|
||||
assert endToken.length() == detailLevel;
|
||||
List<Node> cells = new ArrayList<Node>(detailLevel);
|
||||
List<Cell> cells = new ArrayList<Cell>(detailLevel);
|
||||
for (int i = 1; i < detailLevel; i++) {
|
||||
cells.add(getNode(endToken.substring(0, i)));
|
||||
cells.add(getCell(endToken.substring(0, i)));
|
||||
}
|
||||
cells.add(cell);
|
||||
return cells;
|
||||
|
@ -237,12 +237,12 @@ public abstract class SpatialPrefixTree {
|
|||
/**
|
||||
* Will add the trailing leaf byte for leaves. This isn't particularly efficient.
|
||||
*/
|
||||
public static List<String> nodesToTokenStrings(Collection<Node> nodes) {
|
||||
List<String> tokens = new ArrayList<String>((nodes.size()));
|
||||
for (Node node : nodes) {
|
||||
final String token = node.getTokenString();
|
||||
if (node.isLeaf()) {
|
||||
tokens.add(token + (char) Node.LEAF_BYTE);
|
||||
public static List<String> cellsToTokenStrings(Collection<Cell> cells) {
|
||||
List<String> tokens = new ArrayList<String>((cells.size()));
|
||||
for (Cell cell : cells) {
|
||||
final String token = cell.getTokenString();
|
||||
if (cell.isLeaf()) {
|
||||
tokens.add(token + (char) Cell.LEAF_BYTE);
|
||||
} else {
|
||||
tokens.add(token);
|
||||
}
|
||||
|
|
|
@ -26,7 +26,7 @@ import com.spatial4j.core.shape.SpatialRelation;
|
|||
import com.spatial4j.core.shape.impl.RectangleImpl;
|
||||
import org.apache.lucene.search.Query;
|
||||
import org.apache.lucene.spatial.StrategyTestCase;
|
||||
import org.apache.lucene.spatial.prefix.tree.Node;
|
||||
import org.apache.lucene.spatial.prefix.tree.Cell;
|
||||
import org.apache.lucene.spatial.prefix.tree.QuadPrefixTree;
|
||||
import org.apache.lucene.spatial.prefix.tree.SpatialPrefixTree;
|
||||
import org.apache.lucene.spatial.query.SpatialArgs;
|
||||
|
@ -164,12 +164,12 @@ public class SpatialOpRecursivePrefixTreeTest extends StrategyTestCase {
|
|||
double distErrPct = ((PrefixTreeStrategy) strategy).getDistErrPct();
|
||||
double distErr = SpatialArgs.calcDistanceFromErrPct(snapMe, distErrPct, ctx);
|
||||
int detailLevel = grid.getLevelForDistance(distErr);
|
||||
List<Node> cells = grid.getNodes(snapMe, detailLevel, false, true);
|
||||
List<Cell> cells = grid.getCells(snapMe, detailLevel, false, true);
|
||||
|
||||
//calc bounding box of cells.
|
||||
double minX = Double.POSITIVE_INFINITY, maxX = Double.NEGATIVE_INFINITY;
|
||||
double minY = Double.POSITIVE_INFINITY, maxY = Double.NEGATIVE_INFINITY;
|
||||
for (Node cell : cells) {
|
||||
for (Cell cell : cells) {
|
||||
assert cell.getLevel() <= detailLevel;
|
||||
Rectangle cellR = cell.getShape().getBoundingBox();
|
||||
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
package org.apache.lucene.spatial.prefix.tree;
|
||||
|
||||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
|
@ -15,8 +17,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.apache.lucene.spatial.prefix.tree;
|
||||
|
||||
import com.spatial4j.core.context.SpatialContext;
|
||||
import com.spatial4j.core.shape.Point;
|
||||
import com.spatial4j.core.shape.Rectangle;
|
||||
|
@ -49,20 +49,20 @@ public class SpatialPrefixTreeTest extends SpatialTestCase {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testNodeTraverse() {
|
||||
public void testCellTraverse() {
|
||||
trie = new GeohashPrefixTree(ctx,4);
|
||||
|
||||
Node prevN = null;
|
||||
Node n = trie.getWorldNode();
|
||||
assertEquals(0,n.getLevel());
|
||||
assertEquals(ctx.getWorldBounds(),n.getShape());
|
||||
while(n.getLevel() < trie.getMaxLevels()) {
|
||||
prevN = n;
|
||||
n = n.getSubCells().iterator().next();//TODO random which one?
|
||||
Cell prevC = null;
|
||||
Cell c = trie.getWorldCell();
|
||||
assertEquals(0, c.getLevel());
|
||||
assertEquals(ctx.getWorldBounds(), c.getShape());
|
||||
while(c.getLevel() < trie.getMaxLevels()) {
|
||||
prevC = c;
|
||||
c = c.getSubCells().iterator().next();//TODO random which one?
|
||||
|
||||
assertEquals(prevN.getLevel()+1,n.getLevel());
|
||||
Rectangle prevNShape = (Rectangle) prevN.getShape();
|
||||
Shape s = n.getShape();
|
||||
assertEquals(prevC.getLevel()+1,c.getLevel());
|
||||
Rectangle prevNShape = (Rectangle) prevC.getShape();
|
||||
Shape s = c.getShape();
|
||||
Rectangle sbox = s.getBoundingBox();
|
||||
assertTrue(prevNShape.getWidth() > sbox.getWidth());
|
||||
assertTrue(prevNShape.getHeight() > sbox.getHeight());
|
||||
|
|
Loading…
Reference in New Issue