Implementing LuceneQueryImpl.search Implementing search by invoking the LuceneFunction from within LuceneQueryImpl.search and building a result set. Adding unit tests for the same.
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/3e743df8 Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/3e743df8 Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/3e743df8 Branch: refs/heads/develop Commit: 3e743df86ce7487fd1cf094734ca8a5bbe7895cb Parents: 8fb4ad7 Author: Dan Smith <[email protected]> Authored: Wed Sep 23 15:28:19 2015 -0700 Committer: Dan Smith <[email protected]> Committed: Wed Sep 23 15:53:09 2015 -0700 ---------------------------------------------------------------------- .../gemfire/cache/lucene/LuceneQuery.java | 4 +- .../cache/lucene/LuceneQueryFactory.java | 8 +- .../lucene/internal/LuceneQueryFactoryImpl.java | 39 ++++----- .../cache/lucene/internal/LuceneQueryImpl.java | 42 +++++++--- .../lucene/internal/LuceneServiceImpl.java | 2 +- .../LuceneQueryFactoryImplJUnitTest.java | 32 ++++++++ .../internal/LuceneQueryImplJUnitTest.java | 84 ++++++++++++++++++++ .../LuceneFunctionReadPathDUnitTest.java | 34 +++----- 8 files changed, 177 insertions(+), 68 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java index 548bb00..09d3a07 100644 --- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java +++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQuery.java @@ -6,11 +6,11 @@ package com.gemstone.gemfire.cache.lucene; * {@link LuceneQueryFactory#create}. * */ -public interface LuceneQuery { +public interface LuceneQuery<K, V> { /** * Execute the search and get results. */ - public LuceneQueryResults search(); + public LuceneQueryResults<K, V> search(); /** * Get page size setting of current query. http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java index 55f1b3a..b5598ad 100644 --- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java +++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryFactory.java @@ -56,10 +56,12 @@ public interface LuceneQueryFactory { * @param regionName region name * @param indexName index name * @param queryString query string in lucene QueryParser's syntax + * @param K the key type in the query results + * @param V the value type in the query results * @return LuceneQuery object * @throws ParseException */ - public LuceneQuery create(String indexName, String regionName, String queryString) + public <K, V> LuceneQuery<K, V> create(String indexName, String regionName, String queryString) throws ParseException; /** @@ -70,7 +72,9 @@ public interface LuceneQueryFactory { * @param indexName index name * @param regionName region name * @param provider constructs and provides a Lucene Query object + * @param K the key type in the query results + * @param V the value type in the query results * @return LuceneQuery object */ - public LuceneQuery create(String indexName, String regionName, LuceneQueryProvider provider); + public <K, V> LuceneQuery<K, V> create(String indexName, String regionName, LuceneQueryProvider provider); } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java index 9210929..2a602a5 100644 --- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java +++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImpl.java @@ -3,13 +3,10 @@ package com.gemstone.gemfire.cache.lucene.internal; import java.util.HashSet; import java.util.Set; -import org.apache.lucene.analysis.Analyzer; -import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.queryparser.classic.ParseException; -import org.apache.lucene.queryparser.classic.QueryParser; -import org.apache.lucene.search.Query; -import com.gemstone.gemfire.cache.lucene.LuceneIndex; +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.lucene.LuceneQuery; import com.gemstone.gemfire.cache.lucene.LuceneQueryFactory; import com.gemstone.gemfire.cache.lucene.LuceneQueryProvider; @@ -17,13 +14,13 @@ import com.gemstone.gemfire.cache.lucene.LuceneQueryProvider; public class LuceneQueryFactoryImpl implements LuceneQueryFactory { private int limit = DEFAULT_LIMIT; private int pageSize = DEFAULT_PAGESIZE; - private Set<String> projectionFields = new HashSet<String>(); + private String[] projectionFields = null; + private Cache cache; + + LuceneQueryFactoryImpl(Cache cache) { + this.cache = cache; + } - /* reference to the index. One index could have multiple Queries, but one Query must belong - * to one index - */ - private LuceneIndex relatedIndex; - @Override public LuceneQueryFactory setPageSize(int pageSize) { this.pageSize = pageSize; @@ -37,28 +34,20 @@ public class LuceneQueryFactoryImpl implements LuceneQueryFactory { } @Override - public LuceneQuery create(String indexName, String regionName, - String queryString) throws ParseException { + public <K, V> LuceneQuery<K, V> create(String indexName, String regionName, + String queryString) { return create(indexName, regionName, new StringQueryProvider(queryString)); } - public LuceneQuery create(String indexName, String regionName, LuceneQueryProvider provider) { - LuceneQueryImpl luceneQuery = new LuceneQueryImpl(indexName, regionName, provider, projectionFields, limit, pageSize); + public <K, V> LuceneQuery<K, V> create(String indexName, String regionName, LuceneQueryProvider provider) { + Region region = cache.getRegion(regionName); + LuceneQueryImpl<K, V> luceneQuery = new LuceneQueryImpl<K, V>(indexName, region, provider, projectionFields, limit, pageSize); return luceneQuery; } - - public LuceneIndex getRelatedIndex() { - return this.relatedIndex; - } - @Override public LuceneQueryFactory setProjectionFields(String... fieldNames) { - if (fieldNames != null) { - for (String fieldName:fieldNames) { - this.projectionFields.add(fieldName); - } - } + projectionFields = fieldNames.clone(); return this; } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java index 714df95..a5cbc79 100644 --- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java +++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImpl.java @@ -2,29 +2,34 @@ package com.gemstone.gemfire.cache.lucene.internal; import java.util.Set; -import org.apache.lucene.search.Query; - +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.execute.FunctionService; +import com.gemstone.gemfire.cache.execute.ResultCollector; import com.gemstone.gemfire.cache.lucene.LuceneQuery; import com.gemstone.gemfire.cache.lucene.LuceneQueryFactory; import com.gemstone.gemfire.cache.lucene.LuceneQueryProvider; import com.gemstone.gemfire.cache.lucene.LuceneQueryResults; +import com.gemstone.gemfire.cache.lucene.internal.distributed.LuceneFunction; +import com.gemstone.gemfire.cache.lucene.internal.distributed.LuceneFunctionContext; +import com.gemstone.gemfire.cache.lucene.internal.distributed.TopEntries; +import com.gemstone.gemfire.cache.lucene.internal.distributed.TopEntriesCollector; +import com.gemstone.gemfire.cache.lucene.internal.distributed.TopEntriesCollectorManager; +import com.gemstone.gemfire.cache.lucene.internal.distributed.TopEntriesFunctionCollector; -public class LuceneQueryImpl implements LuceneQuery { +public class LuceneQueryImpl<K, V> implements LuceneQuery<K, V> { private int limit = LuceneQueryFactory.DEFAULT_LIMIT; private int pageSize = LuceneQueryFactory.DEFAULT_PAGESIZE; private String indexName; - private String regionName; - // The projected fields are local to a specific index per Query object. - private Set<String> projectedFieldNames; - + private String[] projectedFieldNames; /* the lucene Query object to be wrapped here */ private LuceneQueryProvider query; + private Region<K, V> region; - LuceneQueryImpl(String indexName, String regionName, LuceneQueryProvider provider, Set<String> projectionFields, + public LuceneQueryImpl(String indexName, Region<K, V> region, LuceneQueryProvider provider, String[] projectionFields, int limit, int pageSize) { this.indexName = indexName; - this.regionName = regionName; + this.region = region; this.limit = limit; this.pageSize = pageSize; this.projectedFieldNames = projectionFields; @@ -32,9 +37,20 @@ public class LuceneQueryImpl implements LuceneQuery { } @Override - public LuceneQueryResults search() { - // TODO Auto-generated method stub - return null; + public LuceneQueryResults<K, V> search() { + LuceneFunctionContext<TopEntriesCollector> context = new LuceneFunctionContext<>(query, indexName, + new TopEntriesCollectorManager()); + TopEntriesFunctionCollector collector = new TopEntriesFunctionCollector(); + + ResultCollector<TopEntriesCollector, TopEntries> rc = (ResultCollector<TopEntriesCollector, TopEntries>) FunctionService.onRegion(region) + .withArgs(context) + .withCollector(collector) + .execute(LuceneFunction.ID); + + //TODO provide a timeout to the user? + TopEntries entries = rc.getResult(); + + return new LuceneQueryResultsImpl<K, V>(entries.getHits(), region, pageSize); } @Override @@ -49,7 +65,7 @@ public class LuceneQueryImpl implements LuceneQuery { @Override public String[] getProjectedFieldNames() { - return (String[])this.projectedFieldNames.toArray(); + return this.projectedFieldNames; } } http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java index cb6e5fc..b1631d1 100644 --- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java +++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneServiceImpl.java @@ -142,7 +142,7 @@ public class LuceneServiceImpl implements InternalLuceneService { @Override public LuceneQueryFactory createLuceneQueryFactory() { - return new LuceneQueryFactoryImpl(); + return new LuceneQueryFactoryImpl(cache); } @Override http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImplJUnitTest.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImplJUnitTest.java b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImplJUnitTest.java new file mode 100644 index 0000000..6cb5368 --- /dev/null +++ b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryFactoryImplJUnitTest.java @@ -0,0 +1,32 @@ +package com.gemstone.gemfire.cache.lucene.internal; + +import static org.junit.Assert.*; + +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.mockito.Mockito; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.lucene.LuceneQuery; +import com.gemstone.gemfire.test.junit.categories.UnitTest; + +@Category(UnitTest.class) +public class LuceneQueryFactoryImplJUnitTest { + + @Test + public void test() { + Cache cache = Mockito.mock(Cache.class); + LuceneQueryFactoryImpl f = new LuceneQueryFactoryImpl(cache); + f.setPageSize(5); + f.setResultLimit(25); + String[] projection = new String[] {"a", "b"}; + f.setProjectionFields(projection); + LuceneQuery<Object, Object> query = f.create("index", "region", new StringQueryProvider("test")); + assertEquals(25, query.getLimit()); + assertEquals(5, query.getPageSize()); + assertArrayEquals(projection, query.getProjectedFieldNames()); + + Mockito.verify(cache).getRegion(Mockito.eq("region")); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImplJUnitTest.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImplJUnitTest.java b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImplJUnitTest.java new file mode 100644 index 0000000..d3ffd19 --- /dev/null +++ b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryImplJUnitTest.java @@ -0,0 +1,84 @@ +package com.gemstone.gemfire.cache.lucene.internal; + +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.gemstone.gemfire.cache.Cache; +import com.gemstone.gemfire.cache.CacheFactory; +import com.gemstone.gemfire.cache.Region; +import com.gemstone.gemfire.cache.RegionShortcut; +import com.gemstone.gemfire.cache.execute.FunctionAdapter; +import com.gemstone.gemfire.cache.execute.FunctionContext; +import com.gemstone.gemfire.cache.execute.FunctionService; +import com.gemstone.gemfire.cache.lucene.LuceneQueryResults; +import com.gemstone.gemfire.cache.lucene.internal.distributed.LuceneFunction; +import com.gemstone.gemfire.cache.lucene.internal.distributed.LuceneFunctionContext; +import com.gemstone.gemfire.cache.lucene.internal.distributed.TopEntriesCollector; +import com.gemstone.gemfire.test.junit.categories.IntegrationTest; + +@Category(IntegrationTest.class) +public class LuceneQueryImplJUnitTest { + + private Cache cache; + private Region<Object, Object> region; + @Before + public void createCache() { + cache = new CacheFactory().set("mcast-port", "0").create(); + region = cache.createRegionFactory(RegionShortcut.REPLICATE).create("region"); + } + + @After + public void removeCache() { + FunctionService.unregisterFunction(LuceneFunction.ID); + cache.close(); + } + @Test + public void test() { + //Register a fake function to observe the function invocation + FunctionService.unregisterFunction(LuceneFunction.ID); + TestLuceneFunction function = new TestLuceneFunction(); + FunctionService.registerFunction(function); + + + StringQueryProvider provider = new StringQueryProvider(); + LuceneQueryImpl query = new LuceneQueryImpl("index", region, provider, null, 100, 20); + LuceneQueryResults results = query.search(); + List nextPage = results.getNextPage(); + assertEquals(3, nextPage.size()); + assertEquals(.3f, results.getMaxScore(), 0.01); + assertTrue(function.wasInvoked); + + LuceneFunctionContext args = (LuceneFunctionContext) function.args; + assertEquals(provider.getQueryString(), ((StringQueryProvider) args.getQueryProvider()).getQueryString()); + assertEquals("index", args.getIndexName()); + assertEquals(100, args.getLimit()); + } + + private static class TestLuceneFunction extends FunctionAdapter { + + private boolean wasInvoked; + private Object args; + + @Override + public void execute(FunctionContext context) { + this.args = context.getArguments(); + wasInvoked = true; + TopEntriesCollector lastResult = new TopEntriesCollector(); + lastResult.collect(3, .3f); + lastResult.collect(2, .2f); + lastResult.collect(1, .1f); + context.getResultSender().lastResult(lastResult); + } + + @Override + public String getId() { + return LuceneFunction.ID; + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/3e743df8/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java ---------------------------------------------------------------------- diff --git a/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java index 939790d..3448725 100644 --- a/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java +++ b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/distributed/LuceneFunctionReadPathDUnitTest.java @@ -1,7 +1,6 @@ package com.gemstone.gemfire.cache.lucene.internal.distributed; import java.io.Serializable; -import java.util.concurrent.TimeUnit; import org.junit.Assert; import org.junit.experimental.categories.Category; @@ -10,14 +9,11 @@ import com.gemstone.gemfire.cache.Cache; import com.gemstone.gemfire.cache.Region; import com.gemstone.gemfire.cache.RegionFactory; import com.gemstone.gemfire.cache.RegionShortcut; -import com.gemstone.gemfire.cache.execute.FunctionService; -import com.gemstone.gemfire.cache.execute.ResultCollector; -import com.gemstone.gemfire.cache.lucene.LuceneIndex; -import com.gemstone.gemfire.cache.lucene.LuceneQueryProvider; +import com.gemstone.gemfire.cache.lucene.LuceneQuery; +import com.gemstone.gemfire.cache.lucene.LuceneQueryResults; import com.gemstone.gemfire.cache.lucene.LuceneService; import com.gemstone.gemfire.cache.lucene.LuceneServiceProvider; import com.gemstone.gemfire.cache.lucene.internal.InternalLuceneIndex; -import com.gemstone.gemfire.cache.lucene.internal.StringQueryProvider; import com.gemstone.gemfire.cache.lucene.internal.repository.IndexRepository; import com.gemstone.gemfire.cache30.CacheTestCase; import com.gemstone.gemfire.internal.cache.BucketNotFoundException; @@ -25,7 +21,6 @@ import com.gemstone.gemfire.test.junit.categories.DistributedTest; import dunit.Host; import dunit.SerializableCallable; -import dunit.SerializableRunnable; import dunit.VM; @Category(DistributedTest.class) @@ -87,32 +82,21 @@ public class LuceneFunctionReadPathDUnitTest extends CacheTestCase { server1.invoke(createPartitionRegion); server2.invoke(createPartitionRegion); - SerializableRunnable executeSearch = new SerializableRunnable("executeSearch") { + SerializableCallable executeSearch = new SerializableCallable("executeSearch") { private static final long serialVersionUID = 1L; - public void run() { + public Object call() throws Exception { Cache cache = getCache(); assertNotNull(cache); Region<Object, Object> region = cache.getRegion(REGION_NAME); Assert.assertNotNull(region); LuceneService service = LuceneServiceProvider.get(cache); - LuceneIndex index = service.getIndex(INDEX_NAME, REGION_NAME); - LuceneQueryProvider provider = new StringQueryProvider("text:world"); - - LuceneFunctionContext<TopEntriesCollector> context = new LuceneFunctionContext<>(provider, index.getName(), - new TopEntriesCollectorManager()); - TopEntriesFunctionCollector collector = new TopEntriesFunctionCollector(); - - ResultCollector<TopEntriesCollector, TopEntries> rc = (ResultCollector<TopEntriesCollector, TopEntries>) FunctionService.onRegion(region).withArgs(context).withCollector(collector).execute(LuceneFunction.ID); - TopEntries entries; - try { - entries = rc.getResult(30, TimeUnit.SECONDS); - assertNotNull(entries); - assertEquals(2, entries.getHits().size()); - } catch (Exception e) { - fail("failed", e); - } + LuceneQuery query = service.createLuceneQueryFactory().create(INDEX_NAME, REGION_NAME, "text:world"); + LuceneQueryResults results = query.search(); + assertEquals(2, results.size()); + + return null; } };
