You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@geode.apache.org by up...@apache.org on 2015/09/22 02:42:54 UTC
incubator-geode git commit: Adding an implementation of
LuceneQueryResults
Repository: incubator-geode
Updated Branches:
refs/heads/feature/GEODE-11 74d293d17 -> 6bb17b531
Adding an implementation of LuceneQueryResults
This implementation does not support project fields yet, but it does
provide pagination by holding a set of all matching keys and fetching
the next set of values using the keys.
Project: http://git-wip-us.apache.org/repos/asf/incubator-geode/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-geode/commit/6bb17b53
Tree: http://git-wip-us.apache.org/repos/asf/incubator-geode/tree/6bb17b53
Diff: http://git-wip-us.apache.org/repos/asf/incubator-geode/diff/6bb17b53
Branch: refs/heads/feature/GEODE-11
Commit: 6bb17b531f321debc502c9d0d57fb185bf98ecd0
Parents: 74d293d
Author: Dan Smith <up...@apache.org>
Authored: Mon Sep 21 17:21:39 2015 -0700
Committer: Dan Smith <up...@apache.org>
Committed: Mon Sep 21 17:35:45 2015 -0700
----------------------------------------------------------------------
.../cache/lucene/LuceneQueryResults.java | 22 ++--
.../cache/lucene/LuceneResultStruct.java | 6 +-
.../lucene/internal/LuceneQueryResultsImpl.java | 127 +++++++++++--------
.../lucene/internal/LuceneResultStructImpl.java | 64 ++++++++--
.../lucene/internal/distributed/EntryScore.java | 2 +-
.../LuceneQueryResultsImplJUnitTest.java | 92 ++++++++++++++
6 files changed, 230 insertions(+), 83 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6bb17b53/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java
----------------------------------------------------------------------
diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java
index d597b66..62aada2 100644
--- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java
+++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneQueryResults.java
@@ -8,14 +8,12 @@ import java.util.List;
*
* @author Xiaojian Zhou
* @since 8.5
+ *
+ * @param <K> The type of the key
+ * @param <V> The type of the value
*/
-public interface LuceneQueryResults {
- /**
- * @return query result identifier. The identifier can be used to trace the origin of this result
- */
- public Object getID();
-
+public interface LuceneQueryResults<K, V> {
/**
* @return total number of hits for this query
*/
@@ -26,11 +24,15 @@ public interface LuceneQueryResults {
*/
public float getMaxScore();
- /*
- * get next page of result if pagesize is specified in query, otherwise, return null
+ /**
+ * Get the next page of results.
+ *
+ * @return a page of results, or null if there are no more pages
*/
- public List<LuceneResultStruct> getNextPage();
+ public List<LuceneResultStruct<K, V>> getNextPage();
- /* Is next page of result available */
+ /**
+ * True if there another page of results.
+ */
public boolean hasNextPage();
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6bb17b53/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java
----------------------------------------------------------------------
diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java
index 139fbd4..75ac0a1 100644
--- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java
+++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/LuceneResultStruct.java
@@ -8,7 +8,7 @@ package com.gemstone.gemfire.cache.lucene;
* @author Xiaojian Zhou
* @since 8.5
*/
-public interface LuceneResultStruct {
+public interface LuceneResultStruct<K, V> {
/**
* Return the value associated with the given field name
*
@@ -24,7 +24,7 @@ public interface LuceneResultStruct {
* @return key
* @throws IllegalArgumentException If this struct does not contain key
*/
- public Object getKey();
+ public K getKey();
/**
* Return value of the entry
@@ -32,7 +32,7 @@ public interface LuceneResultStruct {
* @return value the whole domain object
* @throws IllegalArgumentException If this struct does not contain value
*/
- public Object getValue();
+ public V getValue();
/**
* Return score of the query
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6bb17b53/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java
index 11200c2..93a7f9d 100644
--- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java
+++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImpl.java
@@ -2,64 +2,85 @@ package com.gemstone.gemfire.cache.lucene.internal;
import java.util.ArrayList;
import java.util.List;
-import java.util.concurrent.TimeUnit;
+import java.util.Map;
-import com.gemstone.gemfire.cache.execute.FunctionException;
-import com.gemstone.gemfire.cache.execute.ResultCollector;
+import com.gemstone.gemfire.cache.Region;
import com.gemstone.gemfire.cache.lucene.LuceneQueryResults;
import com.gemstone.gemfire.cache.lucene.LuceneResultStruct;
-import com.gemstone.gemfire.distributed.DistributedMember;
+import com.gemstone.gemfire.cache.lucene.internal.distributed.EntryScore;
-public class LuceneQueryResultsImpl implements LuceneQueryResults,
- ResultCollector<LuceneQueryResults, List<LuceneQueryResults>> {
+/**
+ * Implementation of LuceneQueryResults that fetchs a page at a time
+ * from the server, given a set of EntryScores (key and score).
+ *
+ * @param <K> The type of the key
+ * @param <V> The type of the value
+ */
+public class LuceneQueryResultsImpl<K,V> implements LuceneQueryResults<K,V> {
- // list of docs matching search query
- private List<LuceneResultStruct> hits = new ArrayList<>();
+ /**
+ * list of docs matching search query
+ */
+ private final List<EntryScore> hits;
+
+ /**
+ * The maximum score. Lazily evaluated
+ */
private float maxScore = Float.MIN_VALUE;
-
- @Override
- public List<LuceneQueryResults> getResult() throws FunctionException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public List<LuceneQueryResults> getResult(long timeout, TimeUnit unit) throws FunctionException, InterruptedException {
- // TODO Auto-generated method stub
- return null;
- }
-
- @Override
- public void addResult(DistributedMember memberID, LuceneQueryResults resultOfSingleExecution) {
- // results.add(resultOfSingleExecution);
- }
-
- @Override
- public void endResults() {
- // TODO Auto-generated method stub
-
+
+ /**
+ * The user region where values are stored.
+ */
+ private final Region<K, V> userRegion;
+
+ /**
+ * The start of the next page of results we want to fetch
+ */
+ private int currentHit = 0;
+
+ /**
+ * The page size the user wants.
+ */
+ private int pageSize;
+
+ public LuceneQueryResultsImpl(List<EntryScore> hits, Region<K,V> userRegion, int pageSize) {
+ this.hits = hits;
+ this.userRegion = userRegion;
+ this.pageSize = pageSize;
}
@Override
- public void clearResults() {
- // TODO Auto-generated method stub
-
- }
+ public List<LuceneResultStruct<K,V>> getNextPage() {
+ if(!hasNextPage()) {
+ return null;
+ }
+
+ int end = currentHit + pageSize;
+ end = end > hits.size() ? hits.size() : end;
+ List<EntryScore> scores = hits.subList(currentHit, end);
+
+ ArrayList<K> keys = new ArrayList<K>(hits.size());
+ for(EntryScore score : scores) {
+ keys.add((K) score.getKey());
+ }
+
+ Map<K,V> values = userRegion.getAll(keys);
+
+ ArrayList<LuceneResultStruct<K,V>> results = new ArrayList<LuceneResultStruct<K,V>>(hits.size());
+ for(EntryScore score : scores) {
+ V value = values.get(score.getKey());
+ results.add(new LuceneResultStructImpl(score.getKey(), value, score.getScore()));
+ }
+
- @Override
- public List<LuceneResultStruct> getNextPage() {
- return null;
+ currentHit = end;
+
+ return results;
}
@Override
public boolean hasNextPage() {
- return false;
- }
-
- @Override
- public Object getID() {
- // TODO Auto-generated method stub
- return null;
+ return hits.size() > currentHit;
}
@Override
@@ -69,18 +90,12 @@ public class LuceneQueryResultsImpl implements LuceneQueryResults,
@Override
public float getMaxScore() {
- return maxScore;
- }
-
- /**
- * Adds a result hit to the result set
- *
- * @param hit
- */
- public void addHit(LuceneResultStruct hit) {
- hits.add(hit);
- if (hit.getScore() > maxScore) {
- maxScore = hit.getScore();
+ if(maxScore == Float.MIN_VALUE) {
+ for(EntryScore score : hits) {
+ maxScore = Math.max(maxScore, score.getScore());
+ }
}
+
+ return maxScore;
}
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6bb17b53/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java
----------------------------------------------------------------------
diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java
index 430496a..6417675 100644
--- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java
+++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/LuceneResultStructImpl.java
@@ -2,30 +2,30 @@ package com.gemstone.gemfire.cache.lucene.internal;
import com.gemstone.gemfire.cache.lucene.LuceneResultStruct;
-public class LuceneResultStructImpl implements LuceneResultStruct {
- Object key;
+public class LuceneResultStructImpl<K,V> implements LuceneResultStruct<K,V> {
+ K key;
+ V value;
float score;
- public LuceneResultStructImpl(Object key, float score) {
+ public LuceneResultStructImpl(K key, V value, float score) {
this.key = key;
+ this.value = value;
this.score = score;
}
@Override
public Object getProjectedField(String fieldName) {
- // TODO Auto-generated method stub
- return null;
+ throw new UnsupportedOperationException();
}
@Override
- public Object getKey() {
+ public K getKey() {
return key;
}
@Override
- public Object getValue() {
- // TODO Auto-generated method stub
- return null;
+ public V getValue() {
+ return value;
}
@Override
@@ -35,13 +35,51 @@ public class LuceneResultStructImpl implements LuceneResultStruct {
@Override
public Object[] getNames() {
- // TODO Auto-generated method stub
- return null;
+ throw new UnsupportedOperationException();
}
@Override
public Object[] getResultValues() {
- // TODO Auto-generated method stub
- return null;
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((key == null) ? 0 : key.hashCode());
+ result = prime * result + Float.floatToIntBits(score);
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LuceneResultStructImpl other = (LuceneResultStructImpl) obj;
+ if (key == null) {
+ if (other.key != null)
+ return false;
+ } else if (!key.equals(other.key))
+ return false;
+ if (Float.floatToIntBits(score) != Float.floatToIntBits(other.score))
+ return false;
+ if (value == null) {
+ if (other.value != null)
+ return false;
+ } else if (!value.equals(other.value))
+ return false;
+ return true;
+ }
+
+ @Override
+ public String toString() {
+ return "LuceneResultStructImpl [key=" + key + ", value=" + value
+ + ", score=" + score + "]";
}
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6bb17b53/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/distributed/EntryScore.java
----------------------------------------------------------------------
diff --git a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/distributed/EntryScore.java b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/distributed/EntryScore.java
index 1c80204..456b3ba 100644
--- a/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/distributed/EntryScore.java
+++ b/gemfire-lucene/src/main/java/com/gemstone/gemfire/cache/lucene/internal/distributed/EntryScore.java
@@ -25,7 +25,7 @@ public class EntryScore implements DataSerializableFixedID {
this.key = key;
this.score = score;
}
-
+
public Object getKey() {
return key;
}
http://git-wip-us.apache.org/repos/asf/incubator-geode/blob/6bb17b53/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImplJUnitTest.java
----------------------------------------------------------------------
diff --git a/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImplJUnitTest.java b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImplJUnitTest.java
new file mode 100644
index 0000000..000c01e
--- /dev/null
+++ b/gemfire-lucene/src/test/java/com/gemstone/gemfire/cache/lucene/internal/LuceneQueryResultsImplJUnitTest.java
@@ -0,0 +1,92 @@
+package com.gemstone.gemfire.cache.lucene.internal;
+
+import static org.junit.Assert.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.experimental.categories.Category;
+import org.mockito.Mockito;
+import org.mockito.internal.stubbing.defaultanswers.ForwardsInvocations;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
+
+import com.gemstone.gemfire.cache.Region;
+import com.gemstone.gemfire.cache.lucene.LuceneResultStruct;
+import com.gemstone.gemfire.cache.lucene.internal.distributed.EntryScore;
+import com.gemstone.gemfire.test.junit.categories.UnitTest;
+
+@Category(UnitTest.class)
+public class LuceneQueryResultsImplJUnitTest {
+
+ private List<EntryScore> hits;
+ private List<LuceneResultStruct> expected = new ArrayList<LuceneResultStruct>();
+
+ @Before
+ public void setUp() {
+ hits = new ArrayList<EntryScore>();
+
+ for(int i =0; i < 23; i++) {
+ hits.add(new EntryScore("key_" + i, i));
+ expected.add(new LuceneResultStructImpl<String, String>("key_" + i, "value_" + i, i));
+ }
+ }
+
+ @Test
+ public void testMaxStore() {
+
+ hits.set(5, new EntryScore("key_5", 502));
+
+ LuceneQueryResultsImpl<String, String> results = new LuceneQueryResultsImpl<String, String>(hits, null, 5);
+
+ assertEquals(502, results.getMaxScore(), 0.1f);
+ }
+
+ @Test
+ public void testPagination() {
+ Region<String, String> userRegion = Mockito.mock(Region.class);
+
+ Mockito.when(userRegion.getAll(Mockito.anyCollection())).thenAnswer(new Answer() {
+
+ @Override
+ public Map answer(InvocationOnMock invocation) throws Throwable {
+ Collection<String> keys = invocation.getArgumentAt(0, Collection.class);
+ Map<String, String> results = new HashMap<String, String>();
+ for(String key : keys) {
+ results.put(key, key.replace("key_", "value_"));
+ }
+
+ return results;
+ }
+ });
+
+
+ LuceneQueryResultsImpl<String, String> results = new LuceneQueryResultsImpl<String, String>(hits, userRegion, 10);
+
+ assertEquals(23, results.size());
+
+ assertTrue(results.hasNextPage());
+
+ List<LuceneResultStruct<String, String>> next = results.getNextPage();
+ assertEquals(expected.subList(0, 10), next);
+
+ assertTrue(results.hasNextPage());
+ next = results.getNextPage();
+ assertEquals(expected.subList(10, 20), next);
+
+ assertTrue(results.hasNextPage());
+ next = results.getNextPage();
+ assertEquals(expected.subList(20, 23), next);
+
+
+ assertFalse(results.hasNextPage());
+ assertNull(results.getNextPage());
+ }
+
+}