/* XXL: The eXtensible and fleXible Library for data processing Copyright (C) 2000-2011 Prof. Dr. Bernhard Seeger Head of the Database Research Group Department of Mathematics and Computer Science University of Marburg Germany This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 3 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library; If not, see <http://www.gnu.org/licenses/>. http://code.google.com/p/xxl/ */ package xxl.core.indexStructures; import java.util.Iterator; import java.util.List; import xxl.core.collections.containers.Container; import xxl.core.functions.Function; import xxl.core.indexStructures.BPlusTree.IndexEntry; import xxl.core.indexStructures.BPlusTree.Node; import xxl.core.predicates.Predicate; import xxl.core.spatial.rectangles.Rectangle; /** * This class provides functionality to bulk-load a <tt>HilbertRTree</tt>. * The tree is created bottom-up. */ public class HilbertRTreeBulkLoading extends BPlusTreeBulkLoading { /** * Bulk loads the given <tt>tree</tt> * with the given <tt>objects</tt>. * @param tree * @param objects * @param order in which the data objects are sorted */ public HilbertRTreeBulkLoading(HilbertRTree tree, Iterator objects){ this( tree, objects, tree.getContainer, HilbertRTreeBulkLoading.ASCENDING_BULKLOAD); } /** * Bulk loads the given <tt>tree</tt> * with the given <tt>objects</tt>. * @param tree * @param objects * @param order in which the data objects are sorted */ public HilbertRTreeBulkLoading(HilbertRTree tree, Iterator objects, boolean order){ this( tree, objects, tree.getContainer, order); } /** * Bulk loads the given <tt>tree</tt> * with the given <tt>objects</tt>. * * @see BPlusTree#bulkLoad(BPlusTree, Iterator , Function<BPlusTree.Node,Container> , Predicate ) * @param tree * @param objects * @param determineContainer * @param order in which the data objects are sorted */ public HilbertRTreeBulkLoading(HilbertRTree tree, Iterator objects, Function<BPlusTree.Node,Container> determineContainer, boolean order){ this(tree, objects, determineContainer, tree.overflows , order); } public HilbertRTreeBulkLoading(HilbertRTree tree, Iterator objects, Function<Node, Container> determineContainer, Predicate overflows, boolean order) { super(tree, objects, determineContainer, overflows, order); Node node = (Node)btree.rootEntry.get(); Rectangle rootsMBR = ((HilbertRTree)btree).computeMBR(node.entries()); ((HilbertRTree.ORKeyRange)btree.rootDescriptor).entryMBR = rootsMBR; } /** * Method corrects left flank while bulk loading the data objects in descending order mode * and rigth flank in ascending mode * @param newSep * @param level */ protected void adjustFlankPath(Separator newSep, int level){ adjustFlankPath(newSep, level, null, null); } protected void adjustFlankPath(Separator newSep, int level, Rectangle flankNodeMBR, Rectangle siblingMBR){ Container container = btree.container(); Node flankNode = (Node)treePath.get(level).getValue(); Object flankEntry = treePath.get(level).getKey(); int secondIndex = 1; // index of the second entry in the current node int firstIndex = 0; // index of the first entry in the current node if (level < bufferPath.size()){ Node sibling = (Node)bufferPath.get(level).getValue(); Object siblingEntry = bufferPath.get(level).getKey(); Separator newSeparator = null; // Rectangle nodeNewMBR = null; Rectangle siblingNewMBR = null; if (level > 0 && newSep != null) {//below root node and have created new Separator with redistribute if (descending){ // left flank ((HilbertRTree.ORSeparator)((IndexEntry)flankNode.getFirst()).separator).updateSepValue(newSep.sepValue) ; ((HilbertRTree.ORSeparator)((IndexEntry)flankNode.getFirst()).separator).updateMBR(flankNodeMBR); if (flankNode.number() > 1) ((HilbertRTree.ORSeparator)((IndexEntry)flankNode.getEntry(secondIndex)).separator).updateMBR(siblingMBR); else ((HilbertRTree.ORSeparator)((IndexEntry)sibling.getFirst()).separator).updateMBR(siblingMBR); }else{ // right flank if (flankNode.number() > 1){//more than one item in right node, therefore update ((HilbertRTree.ORSeparator)((IndexEntry)flankNode.getEntry(flankNode.number()-2)).separator).updateSepValue(newSep.sepValue); ((HilbertRTree.ORSeparator)((IndexEntry)flankNode.getEntry(flankNode.number()-2)).separator).updateMBR(siblingMBR);//father node has more than one entry so we must update last node instead of left sibling. } else{ ((HilbertRTree.ORSeparator)((IndexEntry)sibling.getLast()).separator).updateSepValue(newSep.sepValue()); ((HilbertRTree.ORSeparator)((IndexEntry)sibling.getLast()).separator).updateMBR(siblingMBR); } ((HilbertRTree.ORSeparator)((IndexEntry)flankNode.getLast()).separator).updateMBR(flankNodeMBR); } // end adjust sep } //redistribute if (flankNode.underflows()){ int D = sibling.level() == 0 ? btree.D_LeafNode : btree.D_IndexNode; // if (descending){ List newEntries = sibling.entries.subList(firstIndex, D); // flankNode.entries.addAll(flankNode.number(), newEntries);// newEntries.clear(); newSeparator = (Separator)btree.separator(flankNode.getLast()).clone(); }else{ List newEntries = sibling.entries.subList(D, sibling.number()); // flankNode.entries.addAll(0, newEntries);// newEntries.clear(); newSeparator = (Separator)btree.separator(sibling.getLast()).clone(); } // compute MBRs nodeNewMBR = ((HilbertRTree)btree).computeMBR(flankNode.entries()); siblingNewMBR = ((HilbertRTree)btree).computeMBR(sibling.entries()); //update nodes container.update(flankEntry, flankNode); container.update(siblingEntry, sibling); }// end redistribute //shared parent node without underflow if (newSeparator == null && newSep != null ){ container.update(flankEntry, flankNode); } //Rekursion //TODO adjustFlankPath(newSeparator, level+1, nodeNewMBR, siblingNewMBR); }else{ if ( newSep != null ){ if (descending){ ((IndexEntry)flankNode.getFirst()).separator = (Separator)newSep.clone(); }else{ ((IndexEntry)flankNode.getEntry(flankNode.number()-2)).separator = (Separator)newSep.clone(); } container.update(flankEntry, flankNode); } } } /** * Saves a node of the tree to external memory. * (Computes MBR of the Node) * @param id * @param node * @param isDuplicateEnabled * @return */ protected BPlusTree.IndexEntry saveBulk (Object id, BPlusTree.Node node, boolean isDuplicateEnabled){ Container container = determineTreeContainer.invoke(node); container.update(id, node); Separator sep = (Separator) btree.separator(node.getLast()).clone(); Rectangle nodesMBR = ((HilbertRTree)btree).computeMBR(node.entries()); ((HilbertRTree.ORSeparator)sep).updateMBR(nodesMBR); return (BPlusTree.IndexEntry)((BPlusTree.IndexEntry)btree.createIndexEntry(node.level+1)).initialize(sep).initialize(container, id); } }