/* 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.io.DataInput; import java.io.DataOutput; import java.io.IOException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Comparator; import java.util.Iterator; import java.util.List; import java.util.Stack; import xxl.core.collections.Lists; import xxl.core.collections.MappedList; import xxl.core.functions.AbstractFunction; import xxl.core.io.converters.Converter; import xxl.core.util.Interval1D; /** * This class implements a B+Tree based index. * Note that this implementation is based a one-dimensional R-tree. * * B+tree implementation with linked leaf nodes is {@link BPlusTree} * * * For a detailed discussion see Douglas Comer: * "The Ubiquitous B-Tree", * ACM Comput. Surv. 11(2), 121-137, 1979. */ public class BTree extends ORTree { /** Returns the interval containing the given entry. * * @param entry an entry of the nodes of the b-tree * @return the interval containing the entry */ public Interval1D interval (Object entry) { return (Interval1D)descriptor(entry); } /* (non-Javadoc) * @see xxl.core.indexStructures.Tree#createNode(int) */ public Tree.Node createNode (int level) { return new Node().initialize(level, new ArrayList()); } /* (non-Javadoc) * @see xxl.core.indexStructures.ORTree#computeDescriptor(java.util.Collection) */ public Descriptor computeDescriptor (Collection collection) { List entries = (List)collection; return Descriptors.union(descriptor(entries.get(0)), descriptor(entries.get(entries.size()-1))); } /** <tt>Node</tt> is the class used to represent leaf- and non-leaf nodes of <tt>BTree</tt>. * Nodes are stored in containers. * * @see Tree.Node * @see ORTree.Node */ public class Node extends ORTree.Node { /** * @param right flag indicating if the left (<tt>false</tt>) or right (<tt>true</tt>) border should be returned * @return list of borders */ protected List borders (final boolean right) { return new MappedList((List)this.entries, new AbstractFunction() { public Object invoke (Object object) { return interval(object).border(right); } } ); } /* (non-Javadoc) * @see xxl.core.indexStructures.Tree.Node#query(xxl.core.indexStructures.Descriptor) */ public Iterator query (Descriptor queryDescriptor) { Interval1D interval = (Interval1D)queryDescriptor; int [] indices = new int[2]; for (int i = 0; i<2; i++) { indices[i] = Lists.indexOf(borders(i==0), interval.border(i!=0), interval.comparator(), i!=0); if (indices[i]<0) indices[i] = -indices[i]-1-i; } return ((List)entries).subList(indices[0], indices[1]+1).iterator(); } /* (non-Javadoc) * @see xxl.core.indexStructures.ORTree.Node#chooseSubtree(xxl.core.indexStructures.Descriptor, java.util.Iterator) */ protected ORTree.IndexEntry chooseSubtree (Descriptor descriptor, Iterator entries) { Interval1D interval = (Interval1D)descriptor; int index = Collections.binarySearch(borders(false), interval.border(false), interval.comparator()); return (IndexEntry)((List)this.entries).get(index>=0? index: index==-1? 0: -index-2); } /* (non-Javadoc) * @see xxl.core.indexStructures.Tree.Node#grow(java.lang.Object, java.util.Stack) */ protected void grow (Object data, Stack path) { Interval1D interval = interval(data); int index = Collections.binarySearch(borders(false), interval.border(false), interval.comparator()); ((List)entries).add(index>=0? index: -index-1, data); } /* (non-Javadoc) * @see xxl.core.indexStructures.Tree.Node#split(java.util.Stack) */ protected Tree.Node.SplitInfo split (Stack path) { Node node = (Node)node(path); List [] entryLists = new List[] {(List)node.entries, (List)entries}; List subList = entryLists[0].subList((node.splitMinNumber()+node.splitMaxNumber())/2, entryLists[0].size()); entryLists[1].addAll(subList); subList.clear(); ((IndexEntry)indexEntry(path)).descriptor = computeDescriptor(entryLists[0]); return new SplitInfo(path).initialize(computeDescriptor(entryLists[1])); } } /** Gets a suitable Converter to serialize the tree's entries. * * @param borderConverter a converter to convert borders * @param comparator a comparator for data objects stored in the tree * @return a converter for entries of the tree */ public Converter indexEntryConverter (final Converter borderConverter, final Comparator comparator) { return indexEntryConverter( new Converter () { public Object read (DataInput dataInput, Object object) throws IOException { return new Interval1D( borderConverter.read(dataInput, null), borderConverter.read(dataInput, null), comparator ); } public void write (DataOutput dataOutput, Object object) throws IOException { Interval1D interval = (Interval1D)object; borderConverter.write(dataOutput, interval.border(false)); borderConverter.write(dataOutput, interval.border(true )); } } ); } /** Gets a suitable Converter to serialize the tree's nodes. * * @param objectConverter a converter to convert the data objects stored in the tree * @param borderConverter a converter to convert borders * @param comparator a comparator for data objects stored in the tree * @return a NodeConverter */ public Converter nodeConverter (Converter objectConverter, final Converter borderConverter, final Comparator comparator) { return nodeConverter(objectConverter, indexEntryConverter(borderConverter, comparator)); } }