/* * Copyright 2010 Outerthought bvba * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.lilyproject.hbaseindex; import java.io.IOException; import java.math.BigDecimal; import java.util.Arrays; import com.gotometrics.orderly.Order; import org.apache.hadoop.hbase.util.Bytes; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.lilyproject.hadooptestfw.HBaseProxy; import org.lilyproject.hadooptestfw.TestHelper; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.fail; // Important: while not done in these testcases, it is recommended to call QueryResult.close() // when done using the QueryResult. public class IndexTest { private static HBaseProxy HBASE_PROXY; @BeforeClass public static void setUpBeforeClass() throws Exception { TestHelper.setupLogging(); HBASE_PROXY = new HBaseProxy(); HBASE_PROXY.start(); } @AfterClass public static void tearDownAfterClass() throws Exception { HBASE_PROXY.stop(); } @Test public void testSingleStringFieldIndex() throws Exception { final String INDEX_NAME = "singleStringField"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); Index index = indexManager.getIndex(indexDef); // Create a few index entries, inserting them in non-sorted order String[] values = {"d", "a", "c", "e", "b"}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + i)); index.addEntry(entry); } Query query = new Query(); query.setRangeCondition("field1", "b", "d"); QueryResult result = index.performQuery(query); assertResultIds(result, "key4", "key2", "key0"); } @Test public void testSingleByteFieldIndex() throws Exception { final String INDEX_NAME = "singleByteField"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addByteField("field1", 3); Index index = indexManager.getIndex(indexDef); // Create a few index entries, inserting them in non-sorted order byte[][] values = {Bytes.toBytes("aaa"), Bytes.toBytes("aab")}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + i)); index.addEntry(entry); } Query query = new Query(); query.setRangeCondition("field1", Bytes.toBytes("aaa"), Bytes.toBytes("aab")); QueryResult result = index.performQuery(query); assertResultIds(result, "key0", "key1"); } @Test public void testSingleIntFieldIndex() throws Exception { final String INDEX_NAME = "singleIntField"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addIntegerField("field1"); Index index = indexManager.getIndex(indexDef); final int COUNT = 1000; final int MAXVALUE = Integer.MAX_VALUE; int[] values = new int[COUNT]; for (int i = 0; i < COUNT; i++) { values[i] = (int) (Math.random() * MAXVALUE); } for (int value : values) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", value); entry.setIdentifier(Bytes.toBytes("key" + value)); index.addEntry(entry); } Query query = new Query(); query.setRangeCondition("field1", new Integer(0), new Integer(MAXVALUE)); QueryResult result = index.performQuery(query); Arrays.sort(values); for (int value : values) { assertEquals("key" + value, Bytes.toString(result.next())); } assertNull(result.next()); } @Test public void testSingleLongFieldIndex() throws Exception { final String INDEX_NAME = "singleLongField"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addLongField("field1"); Index index = indexManager.getIndex(indexDef); long values[] = {Long.MIN_VALUE, -1, 0, 1, Long.MAX_VALUE}; for (long value : values) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", value); entry.setIdentifier(Bytes.toBytes("key" + value)); index.addEntry(entry); } Query query = new Query(); query.setRangeCondition("field1", Long.MIN_VALUE, Long.MAX_VALUE); QueryResult result = index.performQuery(query); for (long value : values) { assertEquals("key" + value, Bytes.toString(result.next())); } assertNull(result.next()); } @Test public void testSingleFloatFieldIndex() throws Exception { final String INDEX_NAME = "singleFloatField"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addFloatField("field1"); Index index = indexManager.getIndex(indexDef); float[] values = {55.45f, 63.88f, 55.46f, 55.47f, -0.3f}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + i)); index.addEntry(entry); } Query query = new Query(); query.setRangeCondition("field1", new Float(55.44f), new Float(55.48f)); QueryResult result = index.performQuery(query); assertResultIds(result, "key0", "key2", "key3"); } @Test public void testSingleDecimalFieldIndex() throws Exception { final String INDEX_NAME = "singleDecimalField"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addDecimalField("field1"); Index index = indexManager.getIndex(indexDef); String[] values = {"33.66", "-1", "-3.00007E77"}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", new BigDecimal(values[i])); entry.setIdentifier(Bytes.toBytes("key" + i)); index.addEntry(entry); } { Query query = new Query(); query.setRangeCondition("field1", new BigDecimal(values[2]), new BigDecimal(values[0])); QueryResult result = index.performQuery(query); assertResultIds(result, "key2", "key1", "key0"); } { Query query = new Query(); query.addEqualsCondition("field1", new BigDecimal(values[2])); QueryResult result = index.performQuery(query); assertResultIds(result, "key2"); } } @Test public void testDuplicateValuesIndex() throws Exception { final String INDEX_NAME = "duplicateValues"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); Index index = indexManager.getIndex(indexDef); // Create a few index entries, inserting them in non-sorted order String[] values = {"a", "a", "a", "a", "b", "c", "d"}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + i)); index.addEntry(entry); } Query query = new Query(); query.addEqualsCondition("field1", "a"); QueryResult result = index.performQuery(query); assertResultSize(4, result); } @Test public void testMultiFieldIndex() throws Exception { final String INDEX_NAME = "multiField"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addIntegerField("field1"); indexDef.addStringField("field2"); Index index = indexManager.getIndex(indexDef); IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", 10); entry.addField("field2", "a"); entry.setIdentifier(Bytes.toBytes("key1")); index.addEntry(entry); entry.setIdentifier(Bytes.toBytes("key2")); index.addEntry(entry); entry.setIdentifier(Bytes.toBytes("key3")); index.addEntry(entry); entry = new IndexEntry(indexDef); entry.addField("field1", 11); entry.addField("field2", "a"); entry.setIdentifier(Bytes.toBytes("key4")); index.addEntry(entry); entry = new IndexEntry(indexDef); entry.addField("field1", 10); entry.addField("field2", "b"); entry.setIdentifier(Bytes.toBytes("key5")); index.addEntry(entry); Query query = new Query(); query.addEqualsCondition("field1", 10); query.addEqualsCondition("field2", "a"); QueryResult result = index.performQuery(query); assertResultSize(3, result); } @Test public void testDeleteFromIndex() throws Exception { final String INDEX_NAME = "deleteFromIndex"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); Index index = indexManager.getIndex(indexDef); // Add the entry IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", "foobar"); entry.setIdentifier(Bytes.toBytes("key1")); index.addEntry(entry); // Test it is there Query query = new Query(); query.addEqualsCondition("field1", "foobar"); QueryResult result = index.performQuery(query); assertEquals("key1", Bytes.toString(result.next())); assertNull(result.next()); // Delete the entry index.removeEntry(entry); // Test it is gone result = index.performQuery(query); assertNull(result.next()); // Delete the entry again, this should not give an error index.removeEntry(entry); } @Test public void testNullIndex() throws Exception { final String INDEX_NAME = "nullIndex"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); indexDef.addStringField("field2"); Index index = indexManager.getIndex(indexDef); IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", "foobar"); entry.setIdentifier(Bytes.toBytes("key1")); index.addEntry(entry); entry = new IndexEntry(indexDef); entry.setIdentifier(Bytes.toBytes("key2")); index.addEntry(entry); entry = new IndexEntry(indexDef); entry.addField("field2", "foobar"); entry.setIdentifier(Bytes.toBytes("key3")); index.addEntry(entry); Query query = new Query(); query.addEqualsCondition("field1", "foobar"); query.addEqualsCondition("field2", null); QueryResult result = index.performQuery(query); assertResultIds(result, "key1"); query = new Query(); query.addEqualsCondition("field1", null); query.addEqualsCondition("field2", null); result = index.performQuery(query); assertResultIds(result, "key2"); query = new Query(); query.addEqualsCondition("field1", null); query.addEqualsCondition("field2", "foobar"); result = index.performQuery(query); assertResultIds(result, "key3"); } @Test public void testNotExistingIndex() throws Exception { final String INDEX_NAME = "notExisting"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); try { indexManager.getIndex(INDEX_NAME); fail("Expected an IndexNotFoundException."); } catch (IndexNotFoundException e) { // ok } } @Test public void testDeleteIndex() throws Exception { final String INDEX_NAME = "deleteIndex"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("foo"); indexManager.getIndex(indexDef); indexManager.getIndex(INDEX_NAME); indexManager.deleteIndex(INDEX_NAME); try { indexManager.getIndex(INDEX_NAME); fail("Expected an IndexNotFoundException."); } catch (IndexNotFoundException e) { // ok } } @Test public void testIndexEntryVerificationIndex() throws Exception { final String INDEX_NAME = "indexEntryVerification"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("stringfield"); indexDef.addFloatField("floatfield"); indexManager.getIndex(indexDef); Index index = indexManager.getIndex(INDEX_NAME); IndexEntry entry = new IndexEntry(indexDef); try { entry.addField("nonexistingfield", "foobar"); fail("Expected a MalformedIndexEntryException."); } catch (MalformedIndexEntryException e) { // ok } entry = new IndexEntry(indexDef); try { entry.addField("stringfield", new Integer(55)); fail("Expected a MalformedIndexEntryException."); } catch (MalformedIndexEntryException e) { // ok } entry = new IndexEntry(indexDef); try { entry.addField("floatfield", "hello world"); fail("Expected a MalformedIndexEntryException."); } catch (MalformedIndexEntryException e) { // ok } } @Test public void testStringPrefixQuery() throws Exception { final String INDEX_NAME = "stringPrefixQuery"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); Index index = indexManager.getIndex(indexDef); String[] values = {"baard", "boer", "beek", "kanaal", "paard"}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + i)); index.addEntry(entry); } Query query = new Query(); query.setRangeCondition("field1", "b", "b"); QueryResult result = index.performQuery(query); assertResultIds(result, "key0", "key2", "key1"); } /** * Test searching on a subset of the fields. */ @Test public void testPartialQuery() throws Exception { final String INDEX_NAME = "partialQuery"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); indexDef.addIntegerField("field2"); indexDef.addStringField("field3"); Index index = indexManager.getIndex(indexDef); for (int i = 0; i < 3; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", "value A " + i); entry.addField("field2", 10 + i); entry.addField("field3", "value B " + i); entry.setIdentifier(Bytes.toBytes("key" + i)); index.addEntry(entry); } // Search only on the leftmost field { Query query = new Query(); query.addEqualsCondition("field1", "value A 0"); QueryResult result = index.performQuery(query); assertResultIds(result, "key0"); } // Search only on the two leftmost fields { Query query = new Query(); query.addEqualsCondition("field1", "value A 0"); query.addEqualsCondition("field2", 10); QueryResult result = index.performQuery(query); assertResultIds(result, "key0"); } // Search only on the two leftmost fields, with range query on the second { Query query = new Query(); query.addEqualsCondition("field1", "value A 0"); query.setRangeCondition("field2", 9, 11); QueryResult result = index.performQuery(query); assertResultIds(result, "key0"); } // Try searching on just the second field, should give error { Query query = new Query(); query.addEqualsCondition("field2", 10); try { index.performQuery(query); fail("Exception expected"); } catch (MalformedQueryException e) { //System.out.println(e.getMessage()); } } // Try searching on just the second field, should give error { Query query = new Query(); query.setRangeCondition("field2", 9, 11); try { index.performQuery(query); fail("Exception expected"); } catch (MalformedQueryException e) { //System.out.println(e.getMessage()); } } // Try not using all fields from left to right, should give error { Query query = new Query(); query.addEqualsCondition("field1", "value A 0"); // skip field 2 query.addEqualsCondition("field3", "value B 0"); try { index.performQuery(query); fail("Exception expected"); } catch (MalformedQueryException e) { //System.out.println(e.getMessage()); } } // Try not using all fields from left to right, should give error { Query query = new Query(); query.addEqualsCondition("field1", "value A 0"); // skip field 2 query.setRangeCondition("field3", "a", "b"); try { index.performQuery(query); fail("Exception expected"); } catch (MalformedQueryException e) { //System.out.println(e.getMessage()); } } } @Test public void testDataTypeChecks() throws Exception { final String INDEX_NAME = "dataTypeChecks"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); indexDef.addIntegerField("field2"); Index index = indexManager.getIndex(indexDef); // // Index entry checks // // First test correct situation IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", "a"); entry.setIdentifier(Bytes.toBytes("1")); index.addEntry(entry); // Now test incorrect situation entry = new IndexEntry(indexDef); try { entry.addField("field1", 55); fail("Expected exception."); } catch (MalformedIndexEntryException e) { //System.out.println(e.getMessage()); } // // Query checks // // First test correct situation Query query = new Query(); query.addEqualsCondition("field1", "a"); index.performQuery(query); // Now test incorrect situation query = new Query(); query.addEqualsCondition("field1", 55); try { index.performQuery(query); fail("Expected exception."); } catch (MalformedQueryException e) { //System.out.println(e.getMessage()); } } @Test public void testEmptyDefinition() throws Exception { final String INDEX_NAME = "emptyDef"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); try { indexManager.getIndex(indexDef); fail("Exception expected."); } catch (IllegalArgumentException e) { } } @Test public void testExclusiveRanges() throws Exception { final String INDEX_NAME = "exclusiveRanges"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addIntegerField("field1"); Index index = indexManager.getIndex(indexDef); int[] values = {1, 2, 3, 4}; for (int value : values) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", value); entry.setIdentifier(Bytes.toBytes("key" + value)); index.addEntry(entry); } { Query query = new Query(); query.setRangeCondition("field1", 1, 4); QueryResult result = index.performQuery(query); assertResultIds(result, "key1", "key2", "key3", "key4"); } { Query query = new Query(); query.setRangeCondition("field1", 1, 4, false, false); QueryResult result = index.performQuery(query); assertResultIds(result, "key2", "key3"); } { Query query = new Query(); query.setRangeCondition("field1", 1, 4, false, true); QueryResult result = index.performQuery(query); assertResultIds(result, "key2", "key3", "key4"); } { Query query = new Query(); query.setRangeCondition("field1", 1, 4, true, false); QueryResult result = index.performQuery(query); assertResultIds(result, "key1", "key2", "key3"); } } @Test public void testMinMaxRanges() throws Exception { final String INDEX_NAME = "minmaxranges"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addIntegerField("field1"); Index index = indexManager.getIndex(indexDef); Integer[] values = {null, Integer.MIN_VALUE, 1, 2, Integer.MAX_VALUE}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + (i + 1))); index.addEntry(entry); } { Query query = new Query(); query.setRangeCondition("field1", Query.MIN_VALUE, Query.MAX_VALUE); QueryResult result = index.performQuery(query); assertResultIds(result, "key1", "key2", "key3", "key4", "key5"); } { Query query = new Query(); query.setRangeCondition("field1", Query.MIN_VALUE, 0); QueryResult result = index.performQuery(query); assertResultIds(result, "key1", "key2"); } { Query query = new Query(); query.setRangeCondition("field1", 0, Query.MAX_VALUE); QueryResult result = index.performQuery(query); assertResultIds(result, "key3", "key4", "key5"); } } @Test public void testDescendingIntIndex() throws Exception { final String INDEX_NAME = "descendingIntIndex"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.setIdentifierOrder(Order.DESCENDING); IntegerIndexFieldDefinition fieldDef = indexDef.addIntegerField("field1"); fieldDef.setOrder(Order.DESCENDING); Index index = indexManager.getIndex(indexDef); Integer[] values = {null, 1, 2, 2, 3}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + (i + 1))); index.addEntry(entry); } { Query query = new Query(); query.setRangeCondition("field1", Query.MIN_VALUE, Query.MAX_VALUE); QueryResult result = index.performQuery(query); assertResultIds(result, "key5", "key4", "key3", "key2", "key1"); } { Query query = new Query(); query.setRangeCondition("field1", 3, 1); QueryResult result = index.performQuery(query); assertResultIds(result, "key5", "key4", "key3", "key2"); } } @Test public void testDescendingIntAscendingKeyIndex() throws Exception { final String INDEX_NAME = "descendingIntAscendingKey"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); IntegerIndexFieldDefinition fieldDef = indexDef.addIntegerField("field1"); fieldDef.setOrder(Order.DESCENDING); Index index = indexManager.getIndex(indexDef); Integer[] values = {1, 1, 2, 2}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + (i + 1))); index.addEntry(entry); } // The index on the value is descending, the identifiers themselves are ascending! Query query = new Query(); query.setRangeCondition("field1", 2, 1); QueryResult result = index.performQuery(query); assertResultIds(result, "key3", "key4", "key1", "key2"); } @Test public void testAscendingStringIndex() throws Exception { final String INDEX_NAME = "ascendingStringIndex"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.setIdentifierOrder(Order.ASCENDING); StringIndexFieldDefinition fieldDef = indexDef.addStringField("field1"); fieldDef.setOrder(Order.ASCENDING); Index index = indexManager.getIndex(indexDef); String[] values = {"a", "ab", "abc", "b"}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + (i + 1))); index.addEntry(entry); } { Query query = new Query(); query.setRangeCondition("field1", Query.MIN_VALUE, Query.MAX_VALUE); QueryResult result = index.performQuery(query); assertResultIds(result, "key1", "key2", "key3", "key4"); } { Query query = new Query(); query.setRangeCondition("field1", "a", "b"); QueryResult result = index.performQuery(query); assertResultIds(result, "key1", "key2", "key3", "key4"); } { Query query = new Query(); query.setRangeCondition("field1", "a", "a"); QueryResult result = index.performQuery(query); assertResultIds(result, "key1", "key2", "key3"); } } @Test public void testDescendingStringIndex() throws Exception { final String INDEX_NAME = "descendingStringIndex"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.setIdentifierOrder(Order.DESCENDING); StringIndexFieldDefinition fieldDef = indexDef.addStringField("field1"); fieldDef.setOrder(Order.DESCENDING); Index index = indexManager.getIndex(indexDef); String[] values = {"a", "ab", "abc", "b"}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + (i + 1))); index.addEntry(entry); } // { // Query query = new Query(); // query.setRangeCondition("field1", Query.MIN_VALUE, Query.MAX_VALUE); // QueryResult result = index.performQuery(query); // assertResultIds(result, "key4", "key3", "key2", "key1"); // } // // { // Query query = new Query(); // query.setRangeCondition("field1", "b", "a"); // QueryResult result = index.performQuery(query); // assertResultIds(result, "key4", "key3", "key2", "key1"); // } { Query query = new Query(); query.setRangeCondition("field1", "a", "a"); QueryResult result = index.performQuery(query); assertResultIds(result, "key3", "key2", "key1"); } } @Test public void testDescendingStringIndexSpecialCases() throws Exception { final String INDEX_NAME = "descendingStringIndexSpecialCases"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.setIdentifierOrder(Order.DESCENDING); StringIndexFieldDefinition fieldDef = indexDef.addStringField("field1"); fieldDef.setOrder(Order.DESCENDING); Index index = indexManager.getIndex(indexDef); String[] values = {null, "", "a", "aa", "ab"}; for (int i = 0; i < values.length; i++) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", values[i]); entry.setIdentifier(Bytes.toBytes("key" + (i + 1))); index.addEntry(entry); } { Query query = new Query(); query.setRangeCondition("field1", Query.MIN_VALUE, Query.MAX_VALUE); QueryResult result = index.performQuery(query); assertResultIds(result, "key5", "key4", "key3", "key2", "key1"); } { Query query = new Query(); query.setRangeCondition("field1", "a", "a"); QueryResult result = index.performQuery(query); assertResultIds(result, "key5", "key4", "key3"); } } @Test public void testMultiFieldIndexPrefixSearch() throws Exception { final String INDEX_NAME = "multiFieldPrefixSearch"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.setIdentifierOrder(Order.DESCENDING); indexDef.addStringField("field1").setOrder(Order.DESCENDING); indexDef.addStringField("field2").setOrder(Order.DESCENDING); Index index = indexManager.getIndex(indexDef); { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", "ab"); entry.addField("field2", "cd"); entry.setIdentifier(Bytes.toBytes("key1")); index.addEntry(entry); } { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", "abc"); entry.addField("field2", "d"); entry.setIdentifier(Bytes.toBytes("key2")); index.addEntry(entry); } { Query query = new Query(); query.setRangeCondition("field1", "ab", "ab"); QueryResult result = index.performQuery(query); assertResultIds(result, "key2", "key1"); } { Query query = new Query(); query.setRangeCondition("field1", "abc", "abc"); QueryResult result = index.performQuery(query); assertResultIds(result, "key2"); } } @Test public void testData() throws Exception { final String INDEX_NAME = "dataIndex"; IndexManager indexManager = new IndexManager(HBASE_PROXY.getConf()); IndexDefinition indexDef = new IndexDefinition(INDEX_NAME); indexDef.addStringField("field1"); indexManager.getIndex(indexDef); Index index = indexManager.getIndex(INDEX_NAME); String[] values = new String[]{"foo", "bar"}; for (String value : values) { IndexEntry entry = new IndexEntry(indexDef); entry.addField("field1", value); entry.addData(Bytes.toBytes("originalValue"), Bytes.toBytes(value)); entry.setIdentifier(Bytes.toBytes(value)); index.addEntry(entry); } Query query = new Query(); query.setRangeCondition("field1", Query.MIN_VALUE, Query.MAX_VALUE); QueryResult result = index.performQuery(query); assertNotNull(result.next()); assertEquals("bar", result.getDataAsString("originalValue")); assertNotNull(result.next()); assertEquals("foo", result.getDataAsString("originalValue")); } private void assertResultIds(QueryResult result, String... expectedIdentifiers) throws IOException { int resultIdx = 0; byte[] identifier; while ((identifier = result.next()) != null) { if (resultIdx >= expectedIdentifiers.length) { fail("Too many query results."); } assertEquals(expectedIdentifiers[resultIdx], Bytes.toString(identifier)); resultIdx++; } assertNull(result.next()); assertEquals("too little query results", expectedIdentifiers.length, resultIdx); } private void assertResultSize(int expectedCount, QueryResult result) throws IOException { int matchCount = 0; while (result.next() != null) { matchCount++; } assertEquals(expectedCount, matchCount); } }