use of de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.xtree.util.SplitHistory in project elki by elki-project.
the class AbstractXTree method createNewRoot.
/**
* Creates a new root node that points to the two specified child nodes and
* return the path to the new root.
*
* @param oldRoot the old root of this RTree
* @param newNode the new split node
* @param splitAxis the split axis used for the split causing this new root
* @return the path to the new root node that points to the two specified
* child nodes
*/
protected IndexTreePath<SpatialEntry> createNewRoot(final N oldRoot, final N newNode, int splitAxis) {
N root = createNewDirectoryNode();
writeNode(root);
// get split history
SplitHistory sh = null;
// TODO: see whether root entry is ALWAYS a directory entry .. it SHOULD!
sh = ((XTreeDirectoryEntry) getRootEntry()).getSplitHistory();
if (sh == null) {
sh = new SplitHistory(getDimensionality());
}
sh.setDim(splitAxis);
// switch the ids
oldRoot.setPageID(root.getPageID());
if (!oldRoot.isLeaf()) {
// TODO: test whether this is neccessary
for (int i = 0; i < oldRoot.getNumEntries(); i++) {
N node = getNode(oldRoot.getEntry(i));
writeNode(node);
}
}
// adjust supernode id
if (oldRoot.isSuperNode()) {
supernodes.remove(new Long(getRootID()));
supernodes.put(new Long(oldRoot.getPageID()), oldRoot);
}
root.setPageID(getRootID());
SpatialEntry oldRootEntry = createNewDirectoryEntry(oldRoot);
SpatialEntry newNodeEntry = createNewDirectoryEntry(newNode);
((SplitHistorySpatialEntry) oldRootEntry).setSplitHistory(sh);
try {
((SplitHistorySpatialEntry) newNodeEntry).setSplitHistory((SplitHistory) sh.clone());
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Clone of a split history should not throw an Exception", e);
}
root.addDirectoryEntry(oldRootEntry);
root.addDirectoryEntry(newNodeEntry);
writeNode(root);
writeNode(oldRoot);
writeNode(newNode);
if (getLogger().isDebugging()) {
getLogger().debugFine(//
new StringBuilder(1000).append("Create new Root: ID=").append(root.getPageID()).append("\nchild1 ").append(oldRoot).append(' ').append(//
new HyperBoundingBox(oldRootEntry)).append("\nchild2 ").append(newNode).append(' ').append(new HyperBoundingBox(newNodeEntry)));
}
// the root entry still needs to be set to the new root node's MBR
return new IndexTreePath<>(null, getRootEntry(), 0);
}
use of de.lmu.ifi.dbs.elki.index.tree.spatial.rstarvariants.xtree.util.SplitHistory in project elki by elki-project.
the class AbstractXTree method adjustTree.
/**
* Adjusts the tree after insertion of some nodes.
*
* @param subtree the subtree to be adjusted
*/
@Override
protected void adjustTree(IndexTreePath<SpatialEntry> subtree) {
if (getLogger().isDebugging()) {
getLogger().debugFine("Adjust tree " + subtree);
}
// get the root of the subtree
N node = getNode(subtree.getEntry());
// overflow in node
if (hasOverflow(node)) {
if (node.isSuperNode()) {
int new_capacity = node.growSuperNode();
getLogger().finest("Extending supernode to new capacity " + new_capacity);
if (isRoot(node)) {
// is root
node.adjustEntry(getRootEntry());
} else {
N parent = getNode(subtree.getParentPath().getEntry());
SpatialEntry e = parent.getEntry(subtree.getIndex());
HyperBoundingBox mbr = new HyperBoundingBox(e);
node.adjustEntry(e);
if (!SpatialUtil.equals(mbr, e)) {
// MBR has changed
// write changes in parent to file
writeNode(parent);
adjustTree(subtree.getParentPath());
}
}
} else {
int[] splitAxis = { -1 };
// treatment of overflow: reinsertion or split
N split = overflowTreatment(node, subtree, splitAxis);
// node was split
if (split != null) {
// split nodes
if (isRoot(node)) {
IndexTreePath<SpatialEntry> newRootPath = createNewRoot(node, split, splitAxis[0]);
height++;
adjustTree(newRootPath);
} else // node is not root
{
// get the parent and add the new split node
N parent = getNode(subtree.getParentPath().getEntry());
if (getLogger().isDebugging()) {
getLogger().debugFine("parent " + parent);
}
SpatialEntry newEntry = createNewDirectoryEntry(split);
parent.addDirectoryEntry(newEntry);
// The below variant does not work in the persistent version
// E oldEntry = subtree.getEntry();
// [reason: if oldEntry is modified, this must be permanent]
SpatialEntry oldEntry = parent.getEntry(subtree.getIndex());
// adjust split history
SplitHistory sh = ((SplitHistorySpatialEntry) oldEntry).getSplitHistory();
if (sh == null) {
// not yet initialized (dimension not known of this tree)
sh = new SplitHistory(oldEntry.getDimensionality());
sh.setDim(splitAxis[0]);
((SplitHistorySpatialEntry) oldEntry).setSplitHistory(sh);
} else {
((SplitHistorySpatialEntry) oldEntry).addSplitDimension(splitAxis[0]);
}
try {
((SplitHistorySpatialEntry) newEntry).setSplitHistory((SplitHistory) sh.clone());
} catch (CloneNotSupportedException e) {
throw new RuntimeException("Clone of a split history should not throw an Exception", e);
}
// adjust the entry representing the (old) node, that has
// been split
node.adjustEntry(oldEntry);
// write changes in parent to file
writeNode(parent);
adjustTree(subtree.getParentPath());
}
}
}
} else // no overflow, only adjust parameters of the entry representing the
// node
{
if (!isRoot(node)) {
N parent = getNode(subtree.getParentPath().getEntry());
SpatialEntry e = parent.getEntry(subtree.getIndex());
HyperBoundingBox mbr = new HyperBoundingBox(e);
node.adjustEntry(e);
if (// we already know that mbr is extended
node.isLeaf() || !SpatialUtil.equals(mbr, e)) {
// MBR has changed
// write changes in parent to file
writeNode(parent);
adjustTree(subtree.getParentPath());
}
} else // root level is reached
{
node.adjustEntry(getRootEntry());
}
}
}
Aggregations