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