Skip to content
Snippets Groups Projects
Verified Commit 3820ccde authored by David Procházka's avatar David Procházka
Browse files

ADD: DCs in approx state, DC measurement in search, search state

parent fa41c1f2
No related branches found
No related tags found
No related merge requests found
......@@ -6,6 +6,7 @@ public class ApproxState {
protected int limit;
protected int objectsChecked;
protected int bucketsVisited;
protected long computedDistances;
protected ApproxState() {
}
......@@ -22,14 +23,17 @@ public class ApproxState {
return new ApproxStateObjects(limits.getLocalSearchParam());
case DATA_PARTITIONS:
return new ApproxStateBuckets(limits.getLocalSearchParam());
case ABS_DC_COUNT:
return new ApproxStateDistanceComputations(limits.getLocalSearchParam());
default:
return new ApproxState();
}
}
public void update(LeafNode node) {
public void update(LeafNode node, long distanceComputations) {
objectsChecked += node.getObjectCount();
bucketsVisited++;
computedDistances = distanceComputations;
}
public boolean stop() {
......@@ -57,4 +61,23 @@ public class ApproxState {
return objectsChecked >= limit;
}
}
private static class ApproxStateDistanceComputations extends ApproxState {
protected ApproxStateDistanceComputations(int limit) {
super(limit);
}
@Override
public boolean stop() {
return computedDistances >= limit;
}
}
public long getComputedDistances() {
return computedDistances;
}
public void setComputedDistances(long computedDistances) {
this.computedDistances = computedDistances;
}
}
......@@ -110,17 +110,4 @@ class InternalNode extends Node implements Serializable {
protected void gatherLeafNodes(List<LeafNode> leafNodes) {
children.forEach(child -> child.gatherLeafNodes(leafNodes));
}
/**
* Returns the number of internal nodes in this subtree.
*
* @return the number of internal nodes in this subtree
*/
protected int getInternalNodesCount() {
return children
.stream()
.filter(Node::isInternal)
.mapToInt(x -> ((InternalNode) x).getInternalNodesCount())
.sum() + 1;
}
}
......@@ -10,8 +10,7 @@ import messif.objects.LocalAbstractObject;
import messif.operations.data.InsertOperation;
import messif.operations.query.ApproxKNNQueryOperation;
import messif.operations.query.KNNQueryOperation;
import messif.statistics.OperationStatistics;
import messif.statistics.StatisticCounter;
import messif.statistics.Statistics;
import java.io.Serializable;
import java.util.ArrayList;
......@@ -29,18 +28,16 @@ public class MHTree extends Algorithm implements Serializable {
* Serialization ID
*/
private static final long serialVersionUID = 42L;
private static final String STAT_NAME_LEAVES_VISITED = "Node.Leaf.Visited";
private static final StatisticCounter statVisitedLeaves = StatisticCounter.getStatistics(STAT_NAME_LEAVES_VISITED);
/**
* Minimal number of objects in leaf node's bucket.
*/
private final int LEAF_CAPACITY;
private final int leafCapacity;
/**
* Maximal degree of internal node.
* Maximal degree of an internal node.
*/
private final int NODE_DEGREE;
private final int nodeDegree;
private final Node root;
private final InsertType insertType;
private final ObjectToNodeDistance objectToNodeDistance;
......@@ -52,8 +49,8 @@ public class MHTree extends Algorithm implements Serializable {
private MHTree(Builder builder) {
super("MH-Tree");
LEAF_CAPACITY = builder.LEAF_CAPACITY;
NODE_DEGREE = builder.NODE_DEGREE;
leafCapacity = builder.leafCapacity;
nodeDegree = builder.nodeDegree;
bucketDispatcher = builder.bucketDispatcher;
insertType = builder.insertType;
......@@ -63,45 +60,54 @@ public class MHTree extends Algorithm implements Serializable {
}
public void approxKNN(ApproxKNNQueryOperation operation) {
approxKNNSearch(operation, ApproxState.create(operation, this));
}
SearchState state = (SearchState) operation.suppData;
private void approxKNNSearch(ApproxKNNQueryOperation operation, ApproxState approxState) {
LocalAbstractObject queryObject = operation.getQueryObject();
if (state.done) {
return;
}
PriorityQueue<ObjectToNodeDistanceRank> queue = new PriorityQueue<>();
queue.add(new ObjectToNodeDistanceRank(queryObject, root));
long distanceComputations = (long) Statistics.getStatistics("DistanceComputations").getValue();
statVisitedLeaves.reset();
StatisticCounter counter = OperationStatistics.getOpStatisticCounter(STAT_NAME_LEAVES_VISITED);
counter.bindTo(statVisitedLeaves);
LocalAbstractObject queryObject = operation.getQueryObject();
while (!queue.isEmpty()) {
if (approxState.stop())
break;
long toThisIterationDistanceComputations = 0;
Node node = queue.remove().getNode();
if (state.queue == null || state.approxState == null) {
state.queue = new PriorityQueue<>();
state.queue.add(new ObjectToNodeDistanceRank(queryObject, root));
state.approxState = ApproxState.create(operation, this);
} else {
toThisIterationDistanceComputations = state.approxState.getComputedDistances() - 1000;
state.approxState.setComputedDistances(0);
}
if (operation.isAnswerFull() && isPrunable(node, queryObject, operation))
continue;
while (!state.queue.isEmpty()) {
if (state.approxState.stop()) {
return;
}
if (node.isLeaf()) {
statVisitedLeaves.add();
Node node = state.queue.remove().getNode();
if (node.isLeaf()) {
for (LocalAbstractObject object : node.getObjects()) {
if (!operation.isAnswerFull() || queryObject.getDistance(object) < operation.getAnswerDistance()) {
operation.addToAnswer(object);
}
}
approxState.update((LeafNode) node);
long changeInDistanceComputations = (long) Statistics.getStatistics("DistanceComputations").getValue() - distanceComputations;
state.approxState.update(
(LeafNode) node,
toThisIterationDistanceComputations + changeInDistanceComputations);
} else {
for (Node child : ((InternalNode) node).getChildren())
if (!operation.isAnswerFull() || !isPrunable(child, queryObject, operation))
queue.add(new ObjectToNodeDistanceRank(queryObject, child));
for (Node child : ((InternalNode) node).getChildren()) {
state.queue.add(new ObjectToNodeDistanceRank(queryObject, child));
}
}
}
state.done = true;
operation.endOperation();
}
......@@ -114,6 +120,10 @@ public class MHTree extends Algorithm implements Serializable {
return bucketDispatcher.getObjectCount();
}
public List<LocalAbstractObject> getObjects() {
return root.getObjects();
}
public void insert(InsertOperation operation) throws BucketStorageException {
LocalAbstractObject object = operation.getInsertedObject();
......@@ -136,12 +146,6 @@ public class MHTree extends Algorithm implements Serializable {
return nodes;
}
private int getNumberOfInternalNodes() {
if (root.isLeaf()) return 0;
return ((InternalNode) root).getInternalNodesCount();
}
/**
* Returns a list of leaf nodes.
*
......@@ -170,14 +174,16 @@ public class MHTree extends Algorithm implements Serializable {
.mapToInt(LocalBucket::getObjectCount)
.sum();
int numberOfNodes = getNodes().size();
System.out.println("Insert type: " + insertType);
System.out.println("Height: " + root.getHeight());
System.out.println("Node degree: " + NODE_DEGREE);
System.out.println("Leaf object capacity: " + LEAF_CAPACITY);
System.out.println("Node degree: " + nodeDegree);
System.out.println("Leaf object capacity: " + leafCapacity);
System.out.println("Number of objects: " + numberOfObjects);
System.out.println("Number of nodes: " + nodeHullObjects.getCount());
System.out.println("Number of internal nodes: " + getNumberOfInternalNodes());
System.out.println("Number of nodes: " + numberOfNodes);
System.out.println("Number of internal nodes: " + (numberOfNodes - leafNodeObjects.getCount()));
System.out.println("Number of leaf nodes: " + leafNodeObjects.getCount());
System.out.printf("Number of hull objects per node - min: %d, avg: %.2f, max: %d, sum: %d\n",
......@@ -195,17 +201,13 @@ public class MHTree extends Algorithm implements Serializable {
@Override
public String toString() {
return "MHTree{" +
"leafCapacity=" + LEAF_CAPACITY +
", nodeDegree=" + NODE_DEGREE +
"leafCapacity=" + leafCapacity +
", nodeDegree=" + nodeDegree +
", insertType=" + insertType +
", objectToNodeDistance=" + objectToNodeDistance +
'}';
}
private boolean isPrunable(Node child, LocalAbstractObject queryObject, ApproxKNNQueryOperation operation) {
return operation.getAnswerDistance() < child.getDistanceToNearest(queryObject);
}
public static class Builder {
/**
......@@ -216,12 +218,12 @@ public class MHTree extends Algorithm implements Serializable {
/**
* Minimal number of objects in leaf node's bucket.
*/
private final int LEAF_CAPACITY;
private final int leafCapacity;
/**
* Maximal degree of internal node.
*/
private final int NODE_DEGREE;
private final int nodeDegree;
/**
* Specifies which method to use when adding a new object.
......@@ -265,12 +267,12 @@ public class MHTree extends Algorithm implements Serializable {
public Builder(List<LocalAbstractObject> objects, int leafCapacity, int nodeDegree) {
this.objects = objects;
this.LEAF_CAPACITY = leafCapacity;
this.NODE_DEGREE = nodeDegree;
this.leafCapacity = leafCapacity;
this.nodeDegree = nodeDegree;
this.insertType = InsertType.GREEDY;
this.objectToNodeDistance = ObjectToNodeDistance.NEAREST;
this.bucketDispatcher = new BucketDispatcher(Integer.MAX_VALUE, Long.MAX_VALUE, LEAF_CAPACITY, 0, false, MemoryStorageBucket.class, null);
this.bucketDispatcher = new BucketDispatcher(Integer.MAX_VALUE, Long.MAX_VALUE, leafCapacity, 0, false, MemoryStorageBucket.class, null);
}
public Builder insertType(InsertType insertType) {
......@@ -289,12 +291,12 @@ public class MHTree extends Algorithm implements Serializable {
}
public Builder bucketDispatcher(Class<? extends LocalBucket> defaultBucketClass, Map<String, Object> bucketClassParams) {
this.bucketDispatcher = new BucketDispatcher(Integer.MAX_VALUE, Long.MAX_VALUE, LEAF_CAPACITY, 0, false, defaultBucketClass, bucketClassParams);
this.bucketDispatcher = new BucketDispatcher(Integer.MAX_VALUE, Long.MAX_VALUE, leafCapacity, 0, false, defaultBucketClass, bucketClassParams);
return this;
}
public MHTree build() throws BucketStorageException {
nodes = new Node[objects.size() / LEAF_CAPACITY];
nodes = new Node[objects.size() / leafCapacity];
validNodeIndices = new BitSet(nodes.length);
validNodeIndices.set(0, nodes.length);
......@@ -302,16 +304,16 @@ public class MHTree extends Algorithm implements Serializable {
objectDistances = new AbstractRepresentation.PrecomputedDistances(objects);
// Every object is stored in the root
if (objectDistances.getObjectCount() <= LEAF_CAPACITY) {
if (objectDistances.getObjectCount() <= leafCapacity) {
root = new LeafNode(objectDistances, bucketDispatcher.createBucket(), insertType, objectToNodeDistance);
return new MHTree(this);
}
createLeafNodes(LEAF_CAPACITY);
createLeafNodes(leafCapacity);
nodeDistances = new PrecomputedNodeDistances();
root = createRoot(NODE_DEGREE);
root = createRoot(nodeDegree);
return new MHTree(this);
}
......@@ -444,7 +446,7 @@ public class MHTree extends Algorithm implements Serializable {
* Merges nodes specified by indices in set state in {@code nodeIndices}.
* The new node is placed on the first set index in {@code nodeIndices}.
*
* @param nodeIndices
* @param nodeIndices the bitset of nodes to be merged
*/
private void mergeNodes(BitSet nodeIndices) {
List<Integer> indices = nodeIndices
......
......@@ -8,23 +8,15 @@ import messif.objects.LocalAbstractObject;
public class ObjectToNodeDistanceRank implements Comparable<ObjectToNodeDistanceRank> {
private final Node node;
private final boolean isCovered;
private final double distance;
public ObjectToNodeDistanceRank(LocalAbstractObject object, Node node) {
this.node = node;
this.isCovered = node.isCovered(object);
this.distance = node.getDistance(object);
}
@Override
public int compareTo(ObjectToNodeDistanceRank rank) {
// Prioritize the node covering the object
int coverageComparison = Boolean.compare(!this.isCovered, !rank.isCovered);
if (coverageComparison != 0) {
return coverageComparison;
}
return Double.compare(this.distance, rank.distance);
}
......
package mhtree;
import java.util.PriorityQueue;
public class SearchState {
public PriorityQueue<ObjectToNodeDistanceRank> queue;
public ApproxState approxState;
public boolean done;
public SearchState(PriorityQueue<ObjectToNodeDistanceRank> queue, ApproxState approxState, boolean done) {
this.queue = queue;
this.approxState = approxState;
this.done = done;
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment