/* Copyright (C) SYSTAP, LLC DBA Blazegraph 2006-2016. All rights reserved. Contact: SYSTAP, LLC DBA Blazegraph 2501 Calvert ST NW #106 Washington, DC 20008 licenses@blazegraph.com This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ /* * Created on Jun 16, 2008 */ package com.bigdata.btree.filter; import java.util.Properties; import java.util.UUID; import junit.framework.TestCase2; import org.apache.log4j.Level; import com.bigdata.btree.AbstractTupleCursorTestCase; import com.bigdata.btree.BTree; import com.bigdata.btree.DefaultTupleSerializer; import com.bigdata.btree.IRangeQuery; import com.bigdata.btree.ITuple; import com.bigdata.btree.ITupleIterator; import com.bigdata.btree.ITupleSerializer; import com.bigdata.btree.IndexMetadata; import com.bigdata.btree.TestTuple; import com.bigdata.btree.keys.IKeyBuilder; import com.bigdata.btree.keys.KeyBuilder; import com.bigdata.btree.keys.StrengthEnum; import com.bigdata.rawstore.SimpleMemoryRawStore; import com.bigdata.util.BytesUtil; /** * Test suite for the {@link PrefixFilter}. * * @author <a href="mailto:thompsonbry@users.sourceforge.net">Bryan Thompson</a> * @version $Id$ */ public class TestPrefixFilter extends TestCase2 { /** * */ public TestPrefixFilter() { } /** * @param name */ public TestPrefixFilter(String name) { super(name); } /** * Used to form the prefix keys. * <p> * Note: The prefix keys are formed with {@link StrengthEnum#Identical}. * This is necessary in order to match all keys in the index since it causes * the secondary characteristics to NOT be included in the prefix key even * if they are present in the keys in the index. */ final IKeyBuilder prefixKeyBuilder; { Properties properties = new Properties(); properties.setProperty(KeyBuilder.Options.STRENGTH, StrengthEnum.Primary.toString()); prefixKeyBuilder = KeyBuilder.newUnicodeInstance(properties); } /** * Used to form the keys for the index and to (de-)serialize the values * stored in the index. */ final ITupleSerializer tupleSer = DefaultTupleSerializer.newInstance(); protected ITuple<String> newTestTuple(String s) { return new TestTuple<String>(IRangeQuery.DEFAULT | IRangeQuery.CURSOR, tupleSer, s, s, false/* deleted */, 0L/* timestamp */); } protected byte[] asPrefixKey(Object key) { final byte[] b = prefixKeyBuilder.reset().append(key).getKey(); if (log.isInfoEnabled()) log.info("key=" + key + ", byte[]="+BytesUtil.toString(b)); return b; } /** * Unit tests with a single prefix. */ public void test_onePrefix() { final BTree btree; { IndexMetadata md = new IndexMetadata(UUID.randomUUID()); md.setTupleSerializer(tupleSer); btree = BTree.create(new SimpleMemoryRawStore(), md); } /* * Note: The value is the original Unicode string that is then encoded * at PRIMARY strength to obtain the key. Since the key is PRIMARY * strength you can not have entries that differ only on their case. */ btree.insert("Bryan", "Bryan"); btree.insert("Bryan Thompson", "Bryan Thompson"); btree.insert("Mike", "Mike"); btree.insert("Mike Personick", "Mike Personick"); btree.insert("Michael", "Michael"); btree.insert("Michael Personick", "Michael Personick"); btree.dump(Level.DEBUG, System.err); { final ITupleIterator<String> itr = btree.rangeIterator( null/* fromKey */, null/* toKey */, 0/* capacity */, IRangeQuery.DEFAULT | IRangeQuery.CURSOR, new PrefixFilter<String>( asPrefixKey("Mike"))); // ITupleIterator<String> itr = new CompletionScan<String>( // // source cursor. // new ReadOnlyBTreeTupleCursor<String>(btree, new Tuple<String>( // btree, IRangeQuery.DEFAULT), null/* fromKey */, // null/* toKey */), // // prefix for the scan. // asPrefixKey("Mike")); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals(newTestTuple( "Mike"), itr.next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals( newTestTuple("Mike Personick"), itr.next()); assertFalse(itr.hasNext()); } { final ITupleIterator<String> itr = btree.rangeIterator( null/* fromKey */, null/* toKey */, 0/* capacity */, IRangeQuery.DEFAULT | IRangeQuery.CURSOR, new PrefixFilter<String>( asPrefixKey("Bryan"))); // ITupleIterator<String> itr = new CompletionScan<String>( // // source cursor. // new ReadOnlyBTreeTupleCursor<String>(btree, new Tuple<String>( // btree, IRangeQuery.DEFAULT), null/* fromKey */, // null/* toKey */), // // prefix for the scan. // asPrefixKey("Bryan")); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals(newTestTuple( "Bryan"), itr.next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals( newTestTuple("Bryan Thompson"), itr.next()); assertFalse(itr.hasNext()); } { final ITupleIterator<String> itr = btree.rangeIterator( null/* fromKey */, null/* toKey */, 0/* capacity */, IRangeQuery.DEFAULT | IRangeQuery.CURSOR, new PrefixFilter<String>( asPrefixKey("Mi"))); // ITupleIterator<String> itr = new CompletionScan<String>( // // source cursor. // new ReadOnlyBTreeTupleCursor<String>(btree, new Tuple<String>( // btree, IRangeQuery.DEFAULT), null/* fromKey */, // null/* toKey */), // // prefix for the scan. // asPrefixKey("Mi")); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals(newTestTuple("Michael"), itr .next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals(newTestTuple("Michael Personick"), itr .next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals(newTestTuple("Mike"), itr .next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals( newTestTuple("Mike Personick"), itr.next()); assertFalse(itr.hasNext()); } // nothing matches. { final ITupleIterator<String> itr = btree.rangeIterator( null/* fromKey */, null/* toKey */, 0/* capacity */, IRangeQuery.DEFAULT | IRangeQuery.CURSOR, new PrefixFilter<String>( asPrefixKey("Ma"))); // ITupleIterator<String> itr = new CompletionScan<String>( // // source cursor. // new ReadOnlyBTreeTupleCursor<String>(btree, new Tuple<String>( // btree, IRangeQuery.DEFAULT), null/* fromKey */, // null/* toKey */), // // prefix for the scan. // asPrefixKey("Ma")); assertFalse(itr.hasNext()); } } /** * Unit tests with multiple prefixes. */ public void test_multiPrefix() { final BTree btree; { IndexMetadata md = new IndexMetadata(UUID.randomUUID()); md.setTupleSerializer(tupleSer); btree = BTree.create(new SimpleMemoryRawStore(), md); } /* * Note: The value is the original Unicode string that is then encoded * at PRIMARY strength to obtain the key. Since the key is PRIMARY * strength you can not have entries that differ only on their case. */ btree.insert("Bryan", "Bryan"); btree.insert("Bryan Thompson", "Bryan Thompson"); btree.insert("Mike", "Mike"); btree.insert("Mike Personick", "Mike Personick"); btree.insert("Michael", "Michael"); btree.insert("Michael Personick", "Michael Personick"); { final ITupleIterator<String> itr = btree.rangeIterator( null/* fromKey */, null/* toKey */, 0/* capacity */, IRangeQuery.DEFAULT | IRangeQuery.CURSOR, new PrefixFilter<String>( new byte[][] { asPrefixKey("Bryan"), asPrefixKey("Mike") } )); // ITupleIterator<String> itr = new CompletionScan<String>( // // source cursor. // new ReadOnlyBTreeTupleCursor<String>(btree, new Tuple<String>( // btree, IRangeQuery.DEFAULT), null/* fromKey */, // null/* toKey */), // // prefix for the scan. // new byte[][] { // asPrefixKey("Bryan"), // asPrefixKey("Mike") }); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals(newTestTuple( "Bryan"), itr.next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals( newTestTuple("Bryan Thompson"), itr.next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals(newTestTuple( "Mike"), itr.next()); assertTrue(itr.hasNext()); AbstractTupleCursorTestCase.assertEquals( newTestTuple("Mike Personick"), itr.next()); assertFalse(itr.hasNext()); } } }