LUCENE-7617: Grouping collector API cleanup

This commit is contained in:
Alan Woodward 2017-01-03 11:00:47 +00:00
parent 52f2a77b78
commit da30f21f5d
36 changed files with 523 additions and 356 deletions

View File

@ -68,6 +68,12 @@ API Changes
* LUCENE-7607: LeafFieldComparator.setScorer and SimpleFieldComparator.setScorer
are declared as throwing IOException (Alan Woodward)
* LUCENE-7617: Collector construction for two-pass grouping queries is
abstracted into a new Grouper class, which can be passed as a constructor
parameter to GroupingSearch. The abstract base classes for the different
grouping Collectors are renamed to remove the Abstract* prefix.
(Alan Woodward, Martijn van Groningen)
New features
* LUCENE-5867: Added BooleanSimilarity. (Robert Muir, Adrien Grand)

View File

@ -29,13 +29,13 @@ import org.apache.lucene.util.FixedBitSet;
* @lucene.experimental
*/
@SuppressWarnings({"unchecked","rawtypes"})
public abstract class AbstractAllGroupHeadsCollector<GH extends AbstractAllGroupHeadsCollector.GroupHead> extends SimpleCollector {
public abstract class AllGroupHeadsCollector<T> extends SimpleCollector {
protected final int[] reversed;
protected final int compIDXEnd;
protected final TemporalResult temporalResult;
protected AbstractAllGroupHeadsCollector(int numberOfSorts) {
protected AllGroupHeadsCollector(int numberOfSorts) {
this.reversed = new int[numberOfSorts];
this.compIDXEnd = numberOfSorts - 1;
temporalResult = new TemporalResult();
@ -48,7 +48,7 @@ public abstract class AbstractAllGroupHeadsCollector<GH extends AbstractAllGroup
public FixedBitSet retrieveGroupHeads(int maxDoc) {
FixedBitSet bitSet = new FixedBitSet(maxDoc);
Collection<GH> groupHeads = getCollectedGroupHeads();
Collection<? extends GroupHead<T>> groupHeads = getCollectedGroupHeads();
for (GroupHead groupHead : groupHeads) {
bitSet.set(groupHead.doc);
}
@ -60,7 +60,7 @@ public abstract class AbstractAllGroupHeadsCollector<GH extends AbstractAllGroup
* @return an int array containing all group heads. The size of the array is equal to number of collected unique groups.
*/
public int[] retrieveGroupHeads() {
Collection<GH> groupHeads = getCollectedGroupHeads();
Collection<? extends GroupHead<T>> groupHeads = getCollectedGroupHeads();
int[] docHeads = new int[groupHeads.size()];
int i = 0;
@ -96,7 +96,7 @@ public abstract class AbstractAllGroupHeadsCollector<GH extends AbstractAllGroup
*
* @return the collected group heads
*/
protected abstract Collection<GH> getCollectedGroupHeads();
protected abstract Collection<? extends GroupHead<T>> getCollectedGroupHeads();
@Override
public void collect(int doc) throws IOException {
@ -104,7 +104,7 @@ public abstract class AbstractAllGroupHeadsCollector<GH extends AbstractAllGroup
if (temporalResult.stop) {
return;
}
GH groupHead = temporalResult.groupHead;
GroupHead<T> groupHead = temporalResult.groupHead;
// Ok now we need to check if the current doc is more relevant then current doc for this group
for (int compIDX = 0; ; compIDX++) {
@ -131,7 +131,7 @@ public abstract class AbstractAllGroupHeadsCollector<GH extends AbstractAllGroup
*/
protected class TemporalResult {
public GH groupHead;
public GroupHead<T> groupHead;
public boolean stop;
}
@ -142,12 +142,12 @@ public abstract class AbstractAllGroupHeadsCollector<GH extends AbstractAllGroup
*
* The group head contains a group value with its associated most relevant document id.
*/
public static abstract class GroupHead<GROUP_VALUE_TYPE> {
public static abstract class GroupHead<T> {
public final GROUP_VALUE_TYPE groupValue;
public final T groupValue;
public int doc;
protected GroupHead(GROUP_VALUE_TYPE groupValue, int doc) {
protected GroupHead(T groupValue, int doc) {
this.groupValue = groupValue;
this.doc = doc;
}

View File

@ -34,7 +34,7 @@ import org.apache.lucene.util.BytesRef;
*
* @lucene.experimental
*/
public abstract class AbstractAllGroupsCollector<GROUP_VALUE_TYPE> extends SimpleCollector {
public abstract class AllGroupsCollector<T> extends SimpleCollector {
/**
* Returns the total number of groups for the executed search.
@ -54,7 +54,7 @@ public abstract class AbstractAllGroupsCollector<GROUP_VALUE_TYPE> extends Simpl
*
* @return the group values
*/
public abstract Collection<GROUP_VALUE_TYPE> getGroups();
public abstract Collection<T> getGroups();
// Empty not necessary
@Override

View File

@ -19,7 +19,7 @@ package org.apache.lucene.search.grouping;
import org.apache.lucene.search.FieldComparator; // javadocs
/**
* Expert: representation of a group in {@link AbstractFirstPassGroupingCollector},
* Expert: representation of a group in {@link FirstPassGroupingCollector},
* tracking the top doc and {@link FieldComparator} slot.
* @lucene.internal */
public class CollectedSearchGroup<T> extends SearchGroup<T> {

View File

@ -27,25 +27,25 @@ import org.apache.lucene.search.SimpleCollector;
*
* @lucene.experimental
*/
public abstract class AbstractDistinctValuesCollector<GC extends AbstractDistinctValuesCollector.GroupCount<?>> extends SimpleCollector {
public abstract class DistinctValuesCollector<T> extends SimpleCollector {
/**
* Returns all unique values for each top N group.
*
* @return all unique values for each top N group
*/
public abstract List<GC> getGroups();
public abstract List<GroupCount<T>> getGroups();
/**
* Returned by {@link AbstractDistinctValuesCollector#getGroups()},
* Returned by {@link DistinctValuesCollector#getGroups()},
* representing the value and set of distinct values for the group.
*/
public abstract static class GroupCount<GROUP_VALUE_TYPE> {
public static class GroupCount<T> {
public final GROUP_VALUE_TYPE groupValue;
public final Set<GROUP_VALUE_TYPE> uniqueValues;
public final T groupValue;
public final Set<T> uniqueValues;
public GroupCount(GROUP_VALUE_TYPE groupValue) {
public GroupCount(T groupValue) {
this.groupValue = groupValue;
this.uniqueValues = new HashSet<>();
}

View File

@ -16,11 +16,20 @@
*/
package org.apache.lucene.search.grouping;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.*;
import java.io.IOException;
import java.util.*;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.TreeSet;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.LeafFieldComparator;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.SimpleCollector;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
/** FirstPassGroupingCollector is the first of two passes necessary
* to collect grouped hits. This pass gathers the top N sorted
@ -32,19 +41,19 @@ import java.util.*;
*
* @lucene.experimental
*/
abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> extends SimpleCollector {
abstract public class FirstPassGroupingCollector<T> extends SimpleCollector {
private final FieldComparator<?>[] comparators;
private final LeafFieldComparator[] leafComparators;
private final int[] reversed;
private final int topNGroups;
private final boolean needsScores;
private final HashMap<GROUP_VALUE_TYPE, CollectedSearchGroup<GROUP_VALUE_TYPE>> groupMap;
private final HashMap<T, CollectedSearchGroup<T>> groupMap;
private final int compIDXEnd;
// Set once we reach topNGroups unique groups:
/** @lucene.internal */
protected TreeSet<CollectedSearchGroup<GROUP_VALUE_TYPE>> orderedGroups;
protected TreeSet<CollectedSearchGroup<T>> orderedGroups;
private int docBase;
private int spareSlot;
@ -61,7 +70,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
* @throws IOException If I/O related errors occur
*/
@SuppressWarnings({"unchecked", "rawtypes"})
public AbstractFirstPassGroupingCollector(Sort groupSort, int topNGroups) throws IOException {
public FirstPassGroupingCollector(Sort groupSort, int topNGroups) throws IOException {
if (topNGroups < 1) {
throw new IllegalArgumentException("topNGroups must be >= 1 (got " + topNGroups + ")");
}
@ -102,7 +111,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
* @param fillFields Whether to fill to {@link SearchGroup#sortValues}
* @return top groups, starting from offset
*/
public Collection<SearchGroup<GROUP_VALUE_TYPE>> getTopGroups(int groupOffset, boolean fillFields) throws IOException {
public Collection<SearchGroup<T>> getTopGroups(int groupOffset, boolean fillFields) throws IOException {
//System.out.println("FP.getTopGroups groupOffset=" + groupOffset + " fillFields=" + fillFields + " groupMap.size()=" + groupMap.size());
@ -118,15 +127,15 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
buildSortedSet();
}
final Collection<SearchGroup<GROUP_VALUE_TYPE>> result = new ArrayList<>();
final Collection<SearchGroup<T>> result = new ArrayList<>();
int upto = 0;
final int sortFieldCount = comparators.length;
for(CollectedSearchGroup<GROUP_VALUE_TYPE> group : orderedGroups) {
for(CollectedSearchGroup<T> group : orderedGroups) {
if (upto++ < groupOffset) {
continue;
}
//System.out.println(" group=" + (group.groupValue == null ? "null" : group.groupValue.utf8ToString()));
SearchGroup<GROUP_VALUE_TYPE> searchGroup = new SearchGroup<>();
SearchGroup<T> searchGroup = new SearchGroup<>();
searchGroup.groupValue = group.groupValue;
if (fillFields) {
searchGroup.sortValues = new Object[sortFieldCount];
@ -181,9 +190,9 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
// TODO: should we add option to mean "ignore docs that
// don't have the group field" (instead of stuffing them
// under null group)?
final GROUP_VALUE_TYPE groupValue = getDocGroupValue(doc);
final T groupValue = getDocGroupValue(doc);
final CollectedSearchGroup<GROUP_VALUE_TYPE> group = groupMap.get(groupValue);
final CollectedSearchGroup<T> group = groupMap.get(groupValue);
if (group == null) {
@ -198,7 +207,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
// just keep collecting them
// Add a new CollectedSearchGroup:
CollectedSearchGroup<GROUP_VALUE_TYPE> sg = new CollectedSearchGroup<>();
CollectedSearchGroup<T> sg = new CollectedSearchGroup<>();
sg.groupValue = copyDocGroupValue(groupValue, null);
sg.comparatorSlot = groupMap.size();
sg.topDoc = docBase + doc;
@ -219,7 +228,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
// We already tested that the document is competitive, so replace
// the bottom group with this new group.
final CollectedSearchGroup<GROUP_VALUE_TYPE> bottomGroup = orderedGroups.pollLast();
final CollectedSearchGroup<T> bottomGroup = orderedGroups.pollLast();
assert orderedGroups.size() == topNGroups -1;
groupMap.remove(bottomGroup.groupValue);
@ -269,7 +278,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
// Remove before updating the group since lookup is done via comparators
// TODO: optimize this
final CollectedSearchGroup<GROUP_VALUE_TYPE> prevLast;
final CollectedSearchGroup<T> prevLast;
if (orderedGroups != null) {
prevLast = orderedGroups.last();
orderedGroups.remove(group);
@ -338,7 +347,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
* @param doc The specified doc
* @return the group value for the specified doc
*/
protected abstract GROUP_VALUE_TYPE getDocGroupValue(int doc) throws IOException;
protected abstract T getDocGroupValue(int doc) throws IOException;
/**
* Returns a copy of the specified group value by creating a new instance and copying the value from the specified
@ -348,7 +357,7 @@ abstract public class AbstractFirstPassGroupingCollector<GROUP_VALUE_TYPE> exten
* @param reuse Optionally a reuse instance to prevent a new instance creation
* @return a copy of the specified group value
*/
protected abstract GROUP_VALUE_TYPE copyDocGroupValue(GROUP_VALUE_TYPE groupValue, GROUP_VALUE_TYPE reuse);
protected abstract T copyDocGroupValue(T groupValue, T reuse);
}

View File

@ -21,10 +21,10 @@ import org.apache.lucene.search.ScoreDoc;
/** Represents one group in the results.
*
* @lucene.experimental */
public class GroupDocs<GROUP_VALUE_TYPE> {
public class GroupDocs<T> {
/** The groupField value for all docs in this group; this
* may be null if hits did not have the groupField. */
public final GROUP_VALUE_TYPE groupValue;
public final T groupValue;
/** Max score in this group */
public final float maxScore;
@ -42,14 +42,14 @@ public class GroupDocs<GROUP_VALUE_TYPE> {
public final int totalHits;
/** Matches the groupSort passed to {@link
* AbstractFirstPassGroupingCollector}. */
* FirstPassGroupingCollector}. */
public final Object[] groupSortValues;
public GroupDocs(float score,
float maxScore,
int totalHits,
ScoreDoc[] scoreDocs,
GROUP_VALUE_TYPE groupValue,
T groupValue,
Object[] groupSortValues) {
this.score = score;
this.maxScore = maxScore;

View File

@ -16,20 +16,25 @@
*/
package org.apache.lucene.search.grouping;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
import java.util.NavigableSet;
import java.util.TreeSet;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.SimpleCollector;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.PriorityQueue;
import java.io.IOException;
import java.util.*;
/**
* Base class for computing grouped facets.
*
* @lucene.experimental
*/
public abstract class AbstractGroupFacetCollector extends SimpleCollector {
public abstract class GroupFacetCollector extends SimpleCollector {
protected final String groupField;
protected final String facetField;
@ -41,7 +46,7 @@ public abstract class AbstractGroupFacetCollector extends SimpleCollector {
protected int startFacetOrd;
protected int endFacetOrd;
protected AbstractGroupFacetCollector(String groupField, String facetField, BytesRef facetPrefix) {
protected GroupFacetCollector(String groupField, String facetField, BytesRef facetPrefix) {
this.groupField = groupField;
this.facetField = facetField;
this.facetPrefix = facetPrefix;

View File

@ -0,0 +1,56 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.lucene.search.grouping;
import java.io.IOException;
import java.util.Collection;
import org.apache.lucene.search.Sort;
/**
* A factory object to create first and second-pass collectors, run by a {@link GroupingSearch}
* @param <T> the type the group value
*/
public abstract class Grouper<T> {
/**
* Create a first-pass collector
* @param sort the order in which groups should be returned
* @param count how many groups to return
*/
public abstract FirstPassGroupingCollector<T> getFirstPassCollector(Sort sort, int count) throws IOException;
/**
* Create an {@link AllGroupsCollector}
*/
public abstract AllGroupsCollector<T> getAllGroupsCollector();
/**
* Create an {@link AllGroupHeadsCollector}
* @param sort a within-group sort order to determine which doc is the group head
*/
public abstract AllGroupHeadsCollector<T> getGroupHeadsCollector(Sort sort);
/**
* Create a second-pass collector
*/
public abstract SecondPassGroupingCollector<T> getSecondPassCollector(
Collection<SearchGroup<T>> groups, Sort groupSort, Sort withinGroupSort,
int maxDocsPerGroup, boolean getScores, boolean getMaxScores, boolean fillSortFields) throws IOException;
}

View File

@ -16,6 +16,11 @@
*/
package org.apache.lucene.search.grouping;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.CachingCollector;
import org.apache.lucene.search.Collector;
@ -25,25 +30,12 @@ import org.apache.lucene.search.Query;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.Weight;
import org.apache.lucene.search.grouping.function.FunctionAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.function.FunctionAllGroupsCollector;
import org.apache.lucene.search.grouping.function.FunctionFirstPassGroupingCollector;
import org.apache.lucene.search.grouping.function.FunctionSecondPassGroupingCollector;
import org.apache.lucene.search.grouping.term.TermAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.term.TermAllGroupsCollector;
import org.apache.lucene.search.grouping.term.TermFirstPassGroupingCollector;
import org.apache.lucene.search.grouping.term.TermSecondPassGroupingCollector;
import org.apache.lucene.search.grouping.function.FunctionGrouper;
import org.apache.lucene.search.grouping.term.TermGrouper;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.mutable.MutableValue;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* Convenience class to perform grouping in a non distributed environment.
*
@ -51,9 +43,7 @@ import java.util.Map;
*/
public class GroupingSearch {
private final String groupField;
private final ValueSource groupFunction;
private final Map<?, ?> valueSourceContext;
private final Grouper grouper;
private final Query groupEndDocs;
private Sort groupSort = Sort.RELEVANCE;
@ -70,7 +60,6 @@ public class GroupingSearch {
private boolean cacheScores;
private boolean allGroups;
private boolean allGroupHeads;
private int initialSize = 128;
private Collection<?> matchingGroups;
private Bits matchingGroupHeads;
@ -82,7 +71,11 @@ public class GroupingSearch {
* @param groupField The name of the field to group by.
*/
public GroupingSearch(String groupField) {
this(groupField, null, null, null);
this(new TermGrouper(groupField, 128), null);
}
public GroupingSearch(String groupField, int initialSize) {
this(new TermGrouper(groupField, initialSize), null);
}
/**
@ -93,7 +86,7 @@ public class GroupingSearch {
* @param valueSourceContext The context of the specified groupFunction
*/
public GroupingSearch(ValueSource groupFunction, Map<?, ?> valueSourceContext) {
this(null, groupFunction, valueSourceContext, null);
this(new FunctionGrouper(groupFunction, valueSourceContext), null);
}
/**
@ -103,13 +96,11 @@ public class GroupingSearch {
* @param groupEndDocs The query that marks the last document in all doc blocks
*/
public GroupingSearch(Query groupEndDocs) {
this(null, null, null, groupEndDocs);
this(null, groupEndDocs);
}
private GroupingSearch(String groupField, ValueSource groupFunction, Map<?, ?> valueSourceContext, Query groupEndDocs) {
this.groupField = groupField;
this.groupFunction = groupFunction;
this.valueSourceContext = valueSourceContext;
private GroupingSearch(Grouper grouper, Query groupEndDocs) {
this.grouper = grouper;
this.groupEndDocs = groupEndDocs;
}
@ -125,7 +116,7 @@ public class GroupingSearch {
*/
@SuppressWarnings("unchecked")
public <T> TopGroups<T> search(IndexSearcher searcher, Query query, int groupOffset, int groupLimit) throws IOException {
if (groupField != null || groupFunction != null) {
if (grouper != null) {
return groupByFieldOrFunction(searcher, query, groupOffset, groupLimit);
} else if (groupEndDocs != null) {
return (TopGroups<T>) groupByDocBlock(searcher, query, groupOffset, groupLimit);
@ -137,49 +128,13 @@ public class GroupingSearch {
@SuppressWarnings({"unchecked", "rawtypes"})
protected TopGroups groupByFieldOrFunction(IndexSearcher searcher, Query query, int groupOffset, int groupLimit) throws IOException {
int topN = groupOffset + groupLimit;
final AbstractFirstPassGroupingCollector firstPassCollector;
final AbstractAllGroupsCollector allGroupsCollector;
final AbstractAllGroupHeadsCollector allGroupHeadsCollector;
if (groupFunction != null) {
firstPassCollector = new FunctionFirstPassGroupingCollector(groupFunction, valueSourceContext, groupSort, topN);
if (allGroups) {
allGroupsCollector = new FunctionAllGroupsCollector(groupFunction, valueSourceContext);
} else {
allGroupsCollector = null;
}
if (allGroupHeads) {
allGroupHeadsCollector = new FunctionAllGroupHeadsCollector(groupFunction, valueSourceContext, sortWithinGroup);
} else {
allGroupHeadsCollector = null;
}
} else {
firstPassCollector = new TermFirstPassGroupingCollector(groupField, groupSort, topN);
if (allGroups) {
allGroupsCollector = new TermAllGroupsCollector(groupField, initialSize);
} else {
allGroupsCollector = null;
}
if (allGroupHeads) {
allGroupHeadsCollector = TermAllGroupHeadsCollector.create(groupField, sortWithinGroup, initialSize);
} else {
allGroupHeadsCollector = null;
}
}
final Collector firstRound;
if (allGroupHeads || allGroups) {
List<Collector> collectors = new ArrayList<>();
collectors.add(firstPassCollector);
if (allGroups) {
collectors.add(allGroupsCollector);
}
if (allGroupHeads) {
collectors.add(allGroupHeadsCollector);
}
firstRound = MultiCollector.wrap(collectors.toArray(new Collector[collectors.size()]));
} else {
firstRound = firstPassCollector;
}
final FirstPassGroupingCollector firstPassCollector = grouper.getFirstPassCollector(groupSort, topN);
final AllGroupsCollector allGroupsCollector = allGroups ? grouper.getAllGroupsCollector() : null;
final AllGroupHeadsCollector allGroupHeadsCollector
= allGroupHeads ? grouper.getGroupHeadsCollector(sortWithinGroup) : null;
final Collector firstRound = MultiCollector.wrap(firstPassCollector, allGroupsCollector, allGroupHeadsCollector);
CachingCollector cachedCollector = null;
if (maxCacheRAMMB != null || maxDocsToCache != null) {
@ -193,16 +148,9 @@ public class GroupingSearch {
searcher.search(query, firstRound);
}
if (allGroups) {
matchingGroups = allGroupsCollector.getGroups();
} else {
matchingGroups = Collections.emptyList();
}
if (allGroupHeads) {
matchingGroupHeads = allGroupHeadsCollector.retrieveGroupHeads(searcher.getIndexReader().maxDoc());
} else {
matchingGroupHeads = new Bits.MatchNoBits(searcher.getIndexReader().maxDoc());
}
matchingGroups = allGroups ? allGroupsCollector.getGroups() : Collections.emptyList();
matchingGroupHeads = allGroupHeads ? allGroupHeadsCollector.retrieveGroupHeads(searcher.getIndexReader().maxDoc())
: new Bits.MatchNoBits(searcher.getIndexReader().maxDoc());
Collection<SearchGroup> topSearchGroups = firstPassCollector.getTopGroups(groupOffset, fillSortFields);
if (topSearchGroups == null) {
@ -210,12 +158,9 @@ public class GroupingSearch {
}
int topNInsideGroup = groupDocsOffset + groupDocsLimit;
AbstractSecondPassGroupingCollector secondPassCollector;
if (groupFunction != null) {
secondPassCollector = new FunctionSecondPassGroupingCollector((Collection) topSearchGroups, groupSort, sortWithinGroup, topNInsideGroup, includeScores, includeMaxScore, fillSortFields, groupFunction, valueSourceContext);
} else {
secondPassCollector = new TermSecondPassGroupingCollector(groupField, (Collection) topSearchGroups, groupSort, sortWithinGroup, topNInsideGroup, includeScores, includeMaxScore, fillSortFields);
}
SecondPassGroupingCollector secondPassCollector
= grouper.getSecondPassCollector(topSearchGroups, groupSort, sortWithinGroup, topNInsideGroup,
includeScores, includeMaxScore, fillSortFields);
if (cachedCollector != null && cachedCollector.isCached()) {
cachedCollector.replay(secondPassCollector);
@ -411,19 +356,4 @@ public class GroupingSearch {
return matchingGroupHeads;
}
/**
* Sets the initial size of some internal used data structures.
* This prevents growing data structures many times. This can improve the performance of the grouping at the cost of
* more initial RAM.
* <p>
* The {@link #setAllGroups} and {@link #setAllGroupHeads} features use this option.
* Defaults to 128.
*
* @param initialSize The initial size of some internal used data structures
* @return <code>this</code>
*/
public GroupingSearch setInitialSize(int initialSize) {
this.initialSize = initialSize;
return this;
}
}

View File

@ -16,28 +16,37 @@
*/
package org.apache.lucene.search.grouping;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.NavigableSet;
import java.util.TreeSet;
import org.apache.lucene.search.FieldComparator;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import java.io.IOException;
import java.util.*;
/**
* Represents a group that is found during the first pass search.
*
* @lucene.experimental
*/
public class SearchGroup<GROUP_VALUE_TYPE> {
public class SearchGroup<T> {
/** The value that defines this group */
public GROUP_VALUE_TYPE groupValue;
public T groupValue;
/** The sort values used during sorting. These are the
* groupSort field values of the highest rank document
* (by the groupSort) within the group. Can be
* <code>null</code> if <code>fillFields=false</code> had
* been passed to {@link AbstractFirstPassGroupingCollector#getTopGroups} */
* been passed to {@link FirstPassGroupingCollector#getTopGroups} */
public Object[] sortValues;
@Override
@ -327,7 +336,7 @@ public class SearchGroup<GROUP_VALUE_TYPE> {
* groupSort must match how the groups were sorted, and
* the provided SearchGroups must have been computed
* with fillFields=true passed to {@link
* AbstractFirstPassGroupingCollector#getTopGroups}.
* FirstPassGroupingCollector#getTopGroups}.
*
* <p>NOTE: this returns null if the topGroups is empty.
*/

View File

@ -16,15 +16,22 @@
*/
package org.apache.lucene.search.grouping;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.*;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.search.LeafCollector;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.SimpleCollector;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopDocsCollector;
import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.search.TopScoreDocCollector;
/**
* SecondPassGroupingCollector is the second of two passes
* necessary to collect grouped docs. This pass gathers the
@ -37,22 +44,22 @@ import java.util.Objects;
*
* @lucene.experimental
*/
public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> extends SimpleCollector {
public abstract class SecondPassGroupingCollector<T> extends SimpleCollector {
private final Collection<SearchGroup<GROUP_VALUE_TYPE>> groups;
private final Collection<SearchGroup<T>> groups;
private final Sort groupSort;
private final Sort withinGroupSort;
private final int maxDocsPerGroup;
private final boolean needsScores;
protected final Map<GROUP_VALUE_TYPE, SearchGroupDocs<GROUP_VALUE_TYPE>> groupMap;
protected final Map<T, SearchGroupDocs<T>> groupMap;
protected SearchGroupDocs<GROUP_VALUE_TYPE>[] groupDocs;
protected SearchGroupDocs<T>[] groupDocs;
private int totalHitCount;
private int totalGroupedHitCount;
public AbstractSecondPassGroupingCollector(Collection<SearchGroup<GROUP_VALUE_TYPE>> groups, Sort groupSort, Sort withinGroupSort,
int maxDocsPerGroup, boolean getScores, boolean getMaxScores, boolean fillSortFields)
public SecondPassGroupingCollector(Collection<SearchGroup<T>> groups, Sort groupSort, Sort withinGroupSort,
int maxDocsPerGroup, boolean getScores, boolean getMaxScores, boolean fillSortFields)
throws IOException {
//System.out.println("SP init");
@ -67,7 +74,7 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
this.needsScores = getScores || getMaxScores || withinGroupSort.needsScores();
this.groupMap = new HashMap<>(groups.size());
for (SearchGroup<GROUP_VALUE_TYPE> group : groups) {
for (SearchGroup<T> group : groups) {
//System.out.println(" prep group=" + (group.groupValue == null ? "null" : group.groupValue.utf8ToString()));
final TopDocsCollector<?> collector;
if (withinGroupSort.equals(Sort.RELEVANCE)) { // optimize to use TopScoreDocCollector
@ -88,7 +95,7 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
@Override
public void setScorer(Scorer scorer) throws IOException {
for (SearchGroupDocs<GROUP_VALUE_TYPE> group : groupMap.values()) {
for (SearchGroupDocs<T> group : groupMap.values()) {
group.leafCollector.setScorer(scorer);
}
}
@ -96,7 +103,7 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
@Override
public void collect(int doc) throws IOException {
totalHitCount++;
SearchGroupDocs<GROUP_VALUE_TYPE> group = retrieveGroup(doc);
SearchGroupDocs<T> group = retrieveGroup(doc);
if (group != null) {
totalGroupedHitCount++;
group.leafCollector.collect(doc);
@ -110,24 +117,24 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
* @return the group the specified doc belongs to or <code>null</code> if no group could be retrieved
* @throws IOException If an I/O related error occurred
*/
protected abstract SearchGroupDocs<GROUP_VALUE_TYPE> retrieveGroup(int doc) throws IOException;
protected abstract SearchGroupDocs<T> retrieveGroup(int doc) throws IOException;
@Override
protected void doSetNextReader(LeafReaderContext readerContext) throws IOException {
//System.out.println("SP.setNextReader");
for (SearchGroupDocs<GROUP_VALUE_TYPE> group : groupMap.values()) {
for (SearchGroupDocs<T> group : groupMap.values()) {
group.leafCollector = group.collector.getLeafCollector(readerContext);
}
}
public TopGroups<GROUP_VALUE_TYPE> getTopGroups(int withinGroupOffset) {
public TopGroups<T> getTopGroups(int withinGroupOffset) {
@SuppressWarnings({"unchecked","rawtypes"})
final GroupDocs<GROUP_VALUE_TYPE>[] groupDocsResult = (GroupDocs<GROUP_VALUE_TYPE>[]) new GroupDocs[groups.size()];
final GroupDocs<T>[] groupDocsResult = (GroupDocs<T>[]) new GroupDocs[groups.size()];
int groupIDX = 0;
float maxScore = Float.MIN_VALUE;
for(SearchGroup<?> group : groups) {
final SearchGroupDocs<GROUP_VALUE_TYPE> groupDocs = groupMap.get(group.groupValue);
final SearchGroupDocs<T> groupDocs = groupMap.get(group.groupValue);
final TopDocs topDocs = groupDocs.collector.topDocs(withinGroupOffset, maxDocsPerGroup);
groupDocsResult[groupIDX++] = new GroupDocs<>(Float.NaN,
topDocs.getMaxScore(),
@ -148,13 +155,13 @@ public abstract class AbstractSecondPassGroupingCollector<GROUP_VALUE_TYPE> exte
// TODO: merge with SearchGroup or not?
// ad: don't need to build a new hashmap
// disad: blows up the size of SearchGroup if we need many of them, and couples implementations
public class SearchGroupDocs<GROUP_VALUE_TYPE> {
public class SearchGroupDocs<T> {
public final GROUP_VALUE_TYPE groupValue;
public final T groupValue;
public final TopDocsCollector<?> collector;
public LeafCollector leafCollector;
public SearchGroupDocs(GROUP_VALUE_TYPE groupValue, TopDocsCollector<?> collector) {
public SearchGroupDocs(T groupValue, TopDocsCollector<?> collector) {
this.groupValue = groupValue;
this.collector = collector;
}

View File

@ -16,18 +16,18 @@
*/
package org.apache.lucene.search.grouping;
import java.io.IOException;
import org.apache.lucene.search.ScoreDoc;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.TopDocs;
import org.apache.lucene.search.TopFieldDocs;
import java.io.IOException;
/** Represents result returned by a grouping search.
*
* @lucene.experimental */
public class TopGroups<GROUP_VALUE_TYPE> {
public class TopGroups<T> {
/** Number of documents matching the search */
public final int totalHitCount;
@ -38,7 +38,7 @@ public class TopGroups<GROUP_VALUE_TYPE> {
public final Integer totalGroupCount;
/** Group results in groupSort order */
public final GroupDocs<GROUP_VALUE_TYPE>[] groups;
public final GroupDocs<T>[] groups;
/** How groups are sorted against each other */
public final SortField[] groupSort;
@ -50,7 +50,7 @@ public class TopGroups<GROUP_VALUE_TYPE> {
* <code>Float.NaN</code> if scores were not computed. */
public final float maxScore;
public TopGroups(SortField[] groupSort, SortField[] withinGroupSort, int totalHitCount, int totalGroupedHitCount, GroupDocs<GROUP_VALUE_TYPE>[] groups, float maxScore) {
public TopGroups(SortField[] groupSort, SortField[] withinGroupSort, int totalHitCount, int totalGroupedHitCount, GroupDocs<T>[] groups, float maxScore) {
this.groupSort = groupSort;
this.withinGroupSort = withinGroupSort;
this.totalHitCount = totalHitCount;
@ -60,7 +60,7 @@ public class TopGroups<GROUP_VALUE_TYPE> {
this.maxScore = maxScore;
}
public TopGroups(TopGroups<GROUP_VALUE_TYPE> oldTopGroups, Integer totalGroupCount) {
public TopGroups(TopGroups<T> oldTopGroups, Integer totalGroupCount) {
this.groupSort = oldTopGroups.groupSort;
this.withinGroupSort = oldTopGroups.withinGroupSort;
this.totalHitCount = oldTopGroups.totalHitCount;

View File

@ -16,6 +16,11 @@
*/
package org.apache.lucene.search.grouping.function;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
@ -24,25 +29,20 @@ import org.apache.lucene.search.LeafFieldComparator;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.grouping.AbstractAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.AllGroupHeadsCollector;
import org.apache.lucene.util.mutable.MutableValue;
import java.io.IOException;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
/**
* An implementation of {@link AbstractAllGroupHeadsCollector} for retrieving the most relevant groups when grouping
* An implementation of {@link AllGroupHeadsCollector} for retrieving the most relevant groups when grouping
* by {@link ValueSource}.
*
* @lucene.experimental
*/
public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollector<FunctionAllGroupHeadsCollector.GroupHead> {
public class FunctionAllGroupHeadsCollector extends AllGroupHeadsCollector<MutableValue> {
private final ValueSource groupBy;
private final Map<?, ?> vsContext;
private final Map<MutableValue, GroupHead> groups;
private final Map<MutableValue, FunctionGroupHead> groups;
private final Sort sortWithinGroup;
private FunctionValues.ValueFiller filler;
@ -73,10 +73,10 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect
@Override
protected void retrieveGroupHeadAndAddIfNotExist(int doc) throws IOException {
filler.fillValue(doc);
GroupHead groupHead = groups.get(mval);
FunctionGroupHead groupHead = groups.get(mval);
if (groupHead == null) {
MutableValue groupValue = mval.duplicate();
groupHead = new GroupHead(groupValue, sortWithinGroup, doc);
groupHead = new FunctionGroupHead(groupValue, sortWithinGroup, doc);
groups.put(groupValue, groupHead);
temporalResult.stop = true;
} else {
@ -86,14 +86,14 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect
}
@Override
protected Collection<GroupHead> getCollectedGroupHeads() {
protected Collection<FunctionGroupHead> getCollectedGroupHeads() {
return groups.values();
}
@Override
public void setScorer(Scorer scorer) throws IOException {
this.scorer = scorer;
for (GroupHead groupHead : groups.values()) {
for (FunctionGroupHead groupHead : groups.values()) {
for (LeafFieldComparator comparator : groupHead.leafComparators) {
comparator.setScorer(scorer);
}
@ -107,7 +107,7 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect
filler = values.getValueFiller();
mval = filler.getValue();
for (GroupHead groupHead : groups.values()) {
for (FunctionGroupHead groupHead : groups.values()) {
for (int i = 0; i < groupHead.comparators.length; i++) {
groupHead.leafComparators[i] = groupHead.comparators[i].getLeafComparator(context);
}
@ -117,13 +117,13 @@ public class FunctionAllGroupHeadsCollector extends AbstractAllGroupHeadsCollect
/** Holds current head document for a single group.
*
* @lucene.experimental */
public class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<MutableValue> {
public class FunctionGroupHead extends AllGroupHeadsCollector.GroupHead<MutableValue> {
final FieldComparator<?>[] comparators;
final LeafFieldComparator[] leafComparators;
@SuppressWarnings({"unchecked","rawtypes"})
private GroupHead(MutableValue groupValue, Sort sort, int doc) throws IOException {
private FunctionGroupHead(MutableValue groupValue, Sort sort, int doc) throws IOException {
super(groupValue, doc + readerContext.docBase);
final SortField[] sortFields = sort.getSort();
comparators = new FieldComparator[sortFields.length];

View File

@ -19,7 +19,7 @@ package org.apache.lucene.search.grouping.function;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.grouping.AbstractAllGroupsCollector;
import org.apache.lucene.search.grouping.AllGroupsCollector;
import org.apache.lucene.util.mutable.MutableValue;
import java.io.IOException;
@ -39,7 +39,7 @@ import java.util.TreeSet;
*
* @lucene.experimental
*/
public class FunctionAllGroupsCollector extends AbstractAllGroupsCollector<MutableValue> {
public class FunctionAllGroupsCollector extends AllGroupsCollector<MutableValue> {
private final Map<?, ?> vsContext;
private final ValueSource groupBy;

View File

@ -16,27 +16,31 @@
*/
package org.apache.lucene.search.grouping.function;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.grouping.AbstractDistinctValuesCollector;
import org.apache.lucene.search.grouping.DistinctValuesCollector;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.util.mutable.MutableValue;
import java.io.IOException;
import java.util.*;
/**
* Function based implementation of {@link org.apache.lucene.search.grouping.AbstractDistinctValuesCollector}.
* Function based implementation of {@link DistinctValuesCollector}.
*
* @lucene.experimental
*/
public class FunctionDistinctValuesCollector extends AbstractDistinctValuesCollector<FunctionDistinctValuesCollector.GroupCount> {
public class FunctionDistinctValuesCollector extends DistinctValuesCollector<MutableValue> {
private final Map<?, ?> vsContext;
private final ValueSource groupSource;
private final ValueSource countSource;
private final Map<MutableValue, GroupCount> groupMap;
private final Map<MutableValue, GroupCount<MutableValue>> groupMap;
private FunctionValues.ValueFiller groupFiller;
private FunctionValues.ValueFiller countFiller;
@ -49,19 +53,19 @@ public class FunctionDistinctValuesCollector extends AbstractDistinctValuesColle
this.countSource = countSource;
groupMap = new LinkedHashMap<>();
for (SearchGroup<MutableValue> group : groups) {
groupMap.put(group.groupValue, new GroupCount(group.groupValue));
groupMap.put(group.groupValue, new GroupCount<>(group.groupValue));
}
}
@Override
public List<GroupCount> getGroups() {
public List<GroupCount<MutableValue>> getGroups() {
return new ArrayList<>(groupMap.values());
}
@Override
public void collect(int doc) throws IOException {
groupFiller.fillValue(doc);
GroupCount groupCount = groupMap.get(groupMval);
GroupCount<MutableValue> groupCount = groupMap.get(groupMval);
if (groupCount != null) {
countFiller.fillValue(doc);
groupCount.uniqueValues.add(countMval.duplicate());
@ -78,15 +82,4 @@ public class FunctionDistinctValuesCollector extends AbstractDistinctValuesColle
countMval = countFiller.getValue();
}
/** Holds distinct values for a single group.
*
* @lucene.experimental */
public static class GroupCount extends AbstractDistinctValuesCollector.GroupCount<MutableValue> {
GroupCount(MutableValue groupValue) {
super(groupValue);
}
}
}

View File

@ -20,19 +20,19 @@ import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AbstractFirstPassGroupingCollector;
import org.apache.lucene.search.grouping.FirstPassGroupingCollector;
import org.apache.lucene.util.mutable.MutableValue;
import java.io.IOException;
import java.util.Map;
/**
* Concrete implementation of {@link AbstractFirstPassGroupingCollector} that groups based on
* Concrete implementation of {@link FirstPassGroupingCollector} that groups based on
* {@link ValueSource} instances.
*
* @lucene.experimental
*/
public class FunctionFirstPassGroupingCollector extends AbstractFirstPassGroupingCollector<MutableValue> {
public class FunctionFirstPassGroupingCollector extends FirstPassGroupingCollector<MutableValue> {
private final ValueSource groupByVS;
private final Map<?, ?> vsContext;

View File

@ -0,0 +1,69 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.lucene.search.grouping.function;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AllGroupHeadsCollector;
import org.apache.lucene.search.grouping.AllGroupsCollector;
import org.apache.lucene.search.grouping.FirstPassGroupingCollector;
import org.apache.lucene.search.grouping.SecondPassGroupingCollector;
import org.apache.lucene.search.grouping.Grouper;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.util.mutable.MutableValue;
/**
* Collector factory for grouping by ValueSource
*/
public class FunctionGrouper extends Grouper<MutableValue> {
private final ValueSource valueSource;
private final Map<?, ?> context;
/**
* Create a Grouper for the provided ValueSource and context
*/
public FunctionGrouper(ValueSource valueSource, Map<?, ?> context) {
this.valueSource = valueSource;
this.context = context;
}
@Override
public FirstPassGroupingCollector<MutableValue> getFirstPassCollector(Sort sort, int count) throws IOException {
return new FunctionFirstPassGroupingCollector(valueSource, context, sort, count);
}
@Override
public AllGroupHeadsCollector<MutableValue> getGroupHeadsCollector(Sort sort) {
return new FunctionAllGroupHeadsCollector(valueSource, context, sort);
}
@Override
public AllGroupsCollector<MutableValue> getAllGroupsCollector() {
return new FunctionAllGroupsCollector(valueSource, context);
}
@Override
public SecondPassGroupingCollector<MutableValue> getSecondPassCollector(Collection<SearchGroup<MutableValue>> searchGroups, Sort groupSort, Sort withinGroupSort, int maxDocsPerGroup, boolean getScores, boolean getMaxScores, boolean fillSortFields) throws IOException {
return new FunctionSecondPassGroupingCollector(searchGroups, groupSort, withinGroupSort, maxDocsPerGroup, getScores, getMaxScores, fillSortFields, valueSource, context);
}
}

View File

@ -20,7 +20,7 @@ import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AbstractSecondPassGroupingCollector;
import org.apache.lucene.search.grouping.SecondPassGroupingCollector;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.util.mutable.MutableValue;
import org.apache.lucene.search.grouping.TopGroups; //javadoc
@ -30,12 +30,12 @@ import java.util.Collection;
import java.util.Map;
/**
* Concrete implementation of {@link AbstractSecondPassGroupingCollector} that groups based on
* Concrete implementation of {@link SecondPassGroupingCollector} that groups based on
* {@link ValueSource} instances.
*
* @lucene.experimental
*/
public class FunctionSecondPassGroupingCollector extends AbstractSecondPassGroupingCollector<MutableValue> {
public class FunctionSecondPassGroupingCollector extends SecondPassGroupingCollector<MutableValue> {
private final ValueSource groupByVS;
private final Map<?, ?> vsContext;

View File

@ -31,19 +31,19 @@ import org.apache.lucene.search.LeafFieldComparator;
import org.apache.lucene.search.Scorer;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.SortField;
import org.apache.lucene.search.grouping.AbstractAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.AllGroupHeadsCollector;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.SentinelIntSet;
/**
* A base implementation of {@link org.apache.lucene.search.grouping.AbstractAllGroupHeadsCollector} for retrieving the most relevant groups when grouping
* A base implementation of {@link AllGroupHeadsCollector} for retrieving the most relevant groups when grouping
* on a string based group field. More specifically this all concrete implementations of this base implementation
* use {@link SortedDocValues}.
*
* @lucene.experimental
*/
public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHeadsCollector.GroupHead<?>> extends AbstractAllGroupHeadsCollector<GH> {
public abstract class TermAllGroupHeadsCollector extends AllGroupHeadsCollector<BytesRef> {
private static final int DEFAULT_INITIAL_SIZE = 128;
@ -67,7 +67,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
* @param sortWithinGroup The sort within each group
* @return an <code>AbstractAllGroupHeadsCollector</code> instance based on the supplied arguments
*/
public static AbstractAllGroupHeadsCollector<?> create(String groupField, Sort sortWithinGroup) {
public static AllGroupHeadsCollector<BytesRef> create(String groupField, Sort sortWithinGroup) {
return create(groupField, sortWithinGroup, DEFAULT_INITIAL_SIZE);
}
@ -82,7 +82,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
* 4 bytes * initialSize.
* @return an <code>AbstractAllGroupHeadsCollector</code> instance based on the supplied arguments
*/
public static AbstractAllGroupHeadsCollector<?> create(String groupField, Sort sortWithinGroup, int initialSize) {
public static AllGroupHeadsCollector<BytesRef> create(String groupField, Sort sortWithinGroup, int initialSize) {
boolean sortAllScore = true;
boolean sortAllFieldValue = true;
@ -113,7 +113,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
}
// A general impl that works for any group sort.
static class GeneralAllGroupHeadsCollector extends TermAllGroupHeadsCollector<GeneralAllGroupHeadsCollector.GroupHead> {
static class GeneralAllGroupHeadsCollector extends TermAllGroupHeadsCollector {
private final Sort sortWithinGroup;
private final Map<BytesRef, GroupHead> groups;
@ -199,7 +199,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
}
}
class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<BytesRef> {
class GroupHead extends AllGroupHeadsCollector.GroupHead<BytesRef> {
@SuppressWarnings({"unchecked", "rawtypes"})
final FieldComparator[] comparators;
@ -239,7 +239,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
// AbstractAllGroupHeadsCollector optimized for ord fields and scores.
static class OrdScoreAllGroupHeadsCollector extends TermAllGroupHeadsCollector<OrdScoreAllGroupHeadsCollector.GroupHead> {
static class OrdScoreAllGroupHeadsCollector extends TermAllGroupHeadsCollector {
private final SentinelIntSet ordSet;
private final List<GroupHead> collectedGroups;
@ -365,7 +365,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
}
}
class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<BytesRef> {
class GroupHead extends AllGroupHeadsCollector.GroupHead<BytesRef> {
BytesRefBuilder[] sortValues;
int[] sortOrds;
@ -452,7 +452,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
// AbstractAllGroupHeadsCollector optimized for ord fields.
static class OrdAllGroupHeadsCollector extends TermAllGroupHeadsCollector<OrdAllGroupHeadsCollector.GroupHead> {
static class OrdAllGroupHeadsCollector extends TermAllGroupHeadsCollector {
private final SentinelIntSet ordSet;
private final List<GroupHead> collectedGroups;
@ -566,7 +566,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
}
}
class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<BytesRef> {
class GroupHead extends AllGroupHeadsCollector.GroupHead<BytesRef> {
BytesRefBuilder[] sortValues;
int[] sortOrds;
@ -635,7 +635,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
// AbstractAllGroupHeadsCollector optimized for scores.
static class ScoreAllGroupHeadsCollector extends TermAllGroupHeadsCollector<ScoreAllGroupHeadsCollector.GroupHead> {
static class ScoreAllGroupHeadsCollector extends TermAllGroupHeadsCollector {
final SentinelIntSet ordSet;
final List<GroupHead> collectedGroups;
@ -727,7 +727,7 @@ public abstract class TermAllGroupHeadsCollector<GH extends AbstractAllGroupHead
}
}
class GroupHead extends AbstractAllGroupHeadsCollector.GroupHead<BytesRef> {
class GroupHead extends AllGroupHeadsCollector.GroupHead<BytesRef> {
float[] scores;

View File

@ -24,7 +24,7 @@ import java.util.List;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.search.grouping.AbstractAllGroupsCollector;
import org.apache.lucene.search.grouping.AllGroupsCollector;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.SentinelIntSet;
@ -42,7 +42,7 @@ import org.apache.lucene.util.SentinelIntSet;
*
* @lucene.experimental
*/
public class TermAllGroupsCollector extends AbstractAllGroupsCollector<BytesRef> {
public class TermAllGroupsCollector extends AllGroupsCollector<BytesRef> {
private static final int DEFAULT_INITIAL_SIZE = 128;
@ -53,7 +53,7 @@ public class TermAllGroupsCollector extends AbstractAllGroupsCollector<BytesRef>
private SortedDocValues index;
/**
* Expert: Constructs a {@link AbstractAllGroupsCollector}
* Expert: Constructs a {@link AllGroupsCollector}
*
* @param groupField The field to group by
* @param initialSize The initial allocation size of the
@ -69,7 +69,7 @@ public class TermAllGroupsCollector extends AbstractAllGroupsCollector<BytesRef>
}
/**
* Constructs a {@link AbstractAllGroupsCollector}. This sets the
* Constructs a {@link AllGroupsCollector}. This sets the
* initial allocation size for the internal int set and group
* list to 128.
*

View File

@ -25,24 +25,24 @@ import java.util.List;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.search.grouping.AbstractDistinctValuesCollector;
import org.apache.lucene.search.grouping.DistinctValuesCollector;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.SentinelIntSet;
/**
* A term based implementation of {@link org.apache.lucene.search.grouping.AbstractDistinctValuesCollector} that relies
* A term based implementation of {@link DistinctValuesCollector} that relies
* on {@link SortedDocValues} to count the distinct values per group.
*
* @lucene.experimental
*/
public class TermDistinctValuesCollector extends AbstractDistinctValuesCollector<TermDistinctValuesCollector.GroupCount> {
public class TermDistinctValuesCollector extends DistinctValuesCollector<BytesRef> {
private final String groupField;
private final String countField;
private final List<GroupCount> groups;
private final List<TermGroupCount> groups;
private final SentinelIntSet ordSet;
private final GroupCount groupCounts[];
private final TermGroupCount groupCounts[];
private SortedDocValues groupFieldTermIndex;
private SortedDocValues countFieldTermIndex;
@ -59,10 +59,10 @@ public class TermDistinctValuesCollector extends AbstractDistinctValuesCollector
this.countField = countField;
this.groups = new ArrayList<>(groups.size());
for (SearchGroup<BytesRef> group : groups) {
this.groups.add(new GroupCount(group.groupValue));
this.groups.add(new TermGroupCount(group.groupValue));
}
ordSet = new SentinelIntSet(groups.size(), -2);
groupCounts = new GroupCount[ordSet.keys.length];
groupCounts = new TermGroupCount[ordSet.keys.length];
}
@Override
@ -81,7 +81,7 @@ public class TermDistinctValuesCollector extends AbstractDistinctValuesCollector
return;
}
GroupCount gc = groupCounts[slot];
TermGroupCount gc = groupCounts[slot];
if (doc > countFieldTermIndex.docID()) {
countFieldTermIndex.advance(doc);
}
@ -119,8 +119,8 @@ public class TermDistinctValuesCollector extends AbstractDistinctValuesCollector
}
@Override
public List<GroupCount> getGroups() {
return groups;
public List<GroupCount<BytesRef>> getGroups() {
return new ArrayList<>(groups);
}
@Override
@ -128,7 +128,7 @@ public class TermDistinctValuesCollector extends AbstractDistinctValuesCollector
groupFieldTermIndex = DocValues.getSorted(context.reader(), groupField);
countFieldTermIndex = DocValues.getSorted(context.reader(), countField);
ordSet.clear();
for (GroupCount group : groups) {
for (TermGroupCount group : groups) {
int groupOrd = group.groupValue == null ? -1 : groupFieldTermIndex.lookupTerm(group.groupValue);
if (group.groupValue != null && groupOrd < 0) {
continue;
@ -150,11 +150,11 @@ public class TermDistinctValuesCollector extends AbstractDistinctValuesCollector
/** Holds distinct values for a single group.
*
* @lucene.experimental */
public static class GroupCount extends AbstractDistinctValuesCollector.GroupCount<BytesRef> {
public static class TermGroupCount extends DistinctValuesCollector.GroupCount<BytesRef> {
int[] ords;
GroupCount(BytesRef groupValue) {
TermGroupCount(BytesRef groupValue) {
super(groupValue);
}
}

View File

@ -22,18 +22,18 @@ import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AbstractFirstPassGroupingCollector;
import org.apache.lucene.search.grouping.FirstPassGroupingCollector;
import org.apache.lucene.util.ArrayUtil;
import org.apache.lucene.util.BytesRef;
/**
* Concrete implementation of {@link org.apache.lucene.search.grouping.AbstractFirstPassGroupingCollector} that groups based on
* Concrete implementation of {@link FirstPassGroupingCollector} that groups based on
* field values and more specifically uses {@link SortedDocValues}
* to collect groups.
*
* @lucene.experimental
*/
public class TermFirstPassGroupingCollector extends AbstractFirstPassGroupingCollector<BytesRef> {
public class TermFirstPassGroupingCollector extends FirstPassGroupingCollector<BytesRef> {
private SortedDocValues index;

View File

@ -25,19 +25,19 @@ import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.index.SortedSetDocValues;
import org.apache.lucene.index.TermsEnum;
import org.apache.lucene.search.grouping.AbstractGroupFacetCollector;
import org.apache.lucene.search.grouping.GroupFacetCollector;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.BytesRefBuilder;
import org.apache.lucene.util.SentinelIntSet;
import org.apache.lucene.util.UnicodeUtil;
/**
* An implementation of {@link AbstractGroupFacetCollector} that computes grouped facets based on the indexed terms
* An implementation of {@link GroupFacetCollector} that computes grouped facets based on the indexed terms
* from DocValues.
*
* @lucene.experimental
*/
public abstract class TermGroupFacetCollector extends AbstractGroupFacetCollector {
public abstract class TermGroupFacetCollector extends GroupFacetCollector {
final List<GroupedFacetHit> groupedFacetHits;
final SentinelIntSet segmentGroupedFacetHits;
@ -190,7 +190,7 @@ public abstract class TermGroupFacetCollector extends AbstractGroupFacetCollecto
return new SegmentResult(segmentFacetCounts, segmentTotalCount, facetFieldTermsIndex.termsEnum(), startFacetOrd, endFacetOrd);
}
private static class SegmentResult extends AbstractGroupFacetCollector.SegmentResult {
private static class SegmentResult extends GroupFacetCollector.SegmentResult {
final TermsEnum tenum;
@ -380,7 +380,7 @@ public abstract class TermGroupFacetCollector extends AbstractGroupFacetCollecto
return new SegmentResult(segmentFacetCounts, segmentTotalCount, facetFieldNumTerms, facetOrdTermsEnum, startFacetOrd, endFacetOrd);
}
private static class SegmentResult extends AbstractGroupFacetCollector.SegmentResult {
private static class SegmentResult extends GroupFacetCollector.SegmentResult {
final TermsEnum tenum;

View File

@ -0,0 +1,81 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.apache.lucene.search.grouping.term;
import java.io.IOException;
import java.util.Collection;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AllGroupHeadsCollector;
import org.apache.lucene.search.grouping.AllGroupsCollector;
import org.apache.lucene.search.grouping.FirstPassGroupingCollector;
import org.apache.lucene.search.grouping.SecondPassGroupingCollector;
import org.apache.lucene.search.grouping.Grouper;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.util.BytesRef;
/**
* Collector factory for grouping by term
*/
public class TermGrouper extends Grouper<BytesRef> {
private final String field;
private final int initialSize;
/**
* Create a new TermGrouper
* @param field the field to group on
*/
public TermGrouper(String field) {
this(field, 128);
}
/**
* Create a new TermGrouper
* @param field the field to group on
* @param initialSize the initial size of various internal datastructures
*/
public TermGrouper(String field, int initialSize) {
this.field = field;
this.initialSize = initialSize;
}
@Override
public FirstPassGroupingCollector<BytesRef> getFirstPassCollector(Sort sort, int count) throws IOException {
return new TermFirstPassGroupingCollector(field, sort, count);
}
@Override
public AllGroupHeadsCollector<BytesRef> getGroupHeadsCollector(Sort sort) {
return TermAllGroupHeadsCollector.create(field, sort, initialSize);
}
@Override
public AllGroupsCollector<BytesRef> getAllGroupsCollector() {
return new TermAllGroupsCollector(field, initialSize);
}
@Override
public SecondPassGroupingCollector<BytesRef> getSecondPassCollector(
Collection<SearchGroup<BytesRef>> groups, Sort groupSort, Sort withinGroupSort,
int maxDocsPerGroup, boolean getScores, boolean getMaxScores, boolean fillSortFields) throws IOException {
return new TermSecondPassGroupingCollector(field, groups, groupSort, withinGroupSort, maxDocsPerGroup, getScores, getMaxScores, fillSortFields);
}
}

View File

@ -23,19 +23,19 @@ import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.index.SortedDocValues;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AbstractSecondPassGroupingCollector;
import org.apache.lucene.search.grouping.SecondPassGroupingCollector;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.SentinelIntSet;
/**
* Concrete implementation of {@link org.apache.lucene.search.grouping.AbstractSecondPassGroupingCollector} that groups based on
* Concrete implementation of {@link SecondPassGroupingCollector} that groups based on
* field values and more specifically uses {@link SortedDocValues}
* to collect grouped docs.
*
* @lucene.experimental
*/
public class TermSecondPassGroupingCollector extends AbstractSecondPassGroupingCollector<BytesRef> {
public class TermSecondPassGroupingCollector extends SecondPassGroupingCollector<BytesRef> {
private final String groupField;
private final SentinelIntSet ordSet;

View File

@ -52,6 +52,7 @@ import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.grouping.function.FunctionAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.term.TermAllGroupHeadsCollector;
import org.apache.lucene.store.Directory;
import org.apache.lucene.util.Bits;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.FixedBitSet;
import org.apache.lucene.util.LuceneTestCase;
@ -138,7 +139,7 @@ public class AllGroupHeadsCollectorTest extends LuceneTestCase {
int maxDoc = reader.maxDoc();
Sort sortWithinGroup = new Sort(new SortField("id_1", SortField.Type.INT, true));
AbstractAllGroupHeadsCollector<?> allGroupHeadsCollector = createRandomCollector(groupField, sortWithinGroup);
AllGroupHeadsCollector<?> allGroupHeadsCollector = createRandomCollector(groupField, sortWithinGroup);
indexSearcher.search(new TermQuery(new Term("content", "random")), allGroupHeadsCollector);
assertTrue(arrayContains(new int[]{2, 3, 5, 7}, allGroupHeadsCollector.retrieveGroupHeads()));
assertTrue(openBitSetContains(new int[]{2, 3, 5, 7}, allGroupHeadsCollector.retrieveGroupHeads(maxDoc), maxDoc));
@ -326,7 +327,7 @@ public class AllGroupHeadsCollectorTest extends LuceneTestCase {
final String searchTerm = "real" + random().nextInt(3);
boolean sortByScoreOnly = random().nextBoolean();
Sort sortWithinGroup = getRandomSort(sortByScoreOnly);
AbstractAllGroupHeadsCollector<?> allGroupHeadsCollector = createRandomCollector("group", sortWithinGroup);
AllGroupHeadsCollector<?> allGroupHeadsCollector = createRandomCollector("group", sortWithinGroup);
s.search(new TermQuery(new Term("content", searchTerm)), allGroupHeadsCollector);
int[] expectedGroupHeads = createExpectedGroupHeads(searchTerm, groupDocs, sortWithinGroup, sortByScoreOnly, fieldIdToDocID);
int[] actualGroupHeads = allGroupHeadsCollector.retrieveGroupHeads();
@ -402,8 +403,9 @@ public class AllGroupHeadsCollectorTest extends LuceneTestCase {
return true;
}
private boolean openBitSetContains(int[] expectedDocs, FixedBitSet actual, int maxDoc) throws IOException {
if (expectedDocs.length != actual.cardinality()) {
private boolean openBitSetContains(int[] expectedDocs, Bits actual, int maxDoc) throws IOException {
assert actual instanceof FixedBitSet;
if (expectedDocs.length != ((FixedBitSet)actual).cardinality()) {
return false;
}
@ -510,8 +512,8 @@ public class AllGroupHeadsCollectorTest extends LuceneTestCase {
}
@SuppressWarnings({"unchecked","rawtypes"})
private AbstractAllGroupHeadsCollector<?> createRandomCollector(String groupField, Sort sortWithinGroup) {
AbstractAllGroupHeadsCollector<? extends AbstractAllGroupHeadsCollector.GroupHead> collector;
private AllGroupHeadsCollector<?> createRandomCollector(String groupField, Sort sortWithinGroup) {
AllGroupHeadsCollector<?> collector;
if (random().nextBoolean()) {
ValueSource vs = new BytesRefFieldSource(groupField);
collector = new FunctionAllGroupHeadsCollector(vs, new HashMap<>(), sortWithinGroup);

View File

@ -102,7 +102,7 @@ public class AllGroupsCollectorTest extends LuceneTestCase {
IndexSearcher indexSearcher = newSearcher(w.getReader());
w.close();
AbstractAllGroupsCollector<?> allGroupsCollector = createRandomCollector(groupField);
AllGroupsCollector<?> allGroupsCollector = createRandomCollector(groupField);
indexSearcher.search(new TermQuery(new Term("content", "random")), allGroupsCollector);
assertEquals(4, allGroupsCollector.getGroupCount());
@ -123,8 +123,8 @@ public class AllGroupsCollectorTest extends LuceneTestCase {
doc.add(new SortedDocValuesField(groupField, new BytesRef(value)));
}
private AbstractAllGroupsCollector<?> createRandomCollector(String groupField) {
AbstractAllGroupsCollector<?> selected;
private AllGroupsCollector<?> createRandomCollector(String groupField) {
AllGroupsCollector<?> selected;
if (random().nextBoolean()) {
selected = new TermAllGroupsCollector(groupField);
} else {

View File

@ -126,10 +126,10 @@ public class DistinctValuesCollectorTest extends AbstractGroupingTestCase {
IndexSearcher indexSearcher = newSearcher(w.getReader());
w.close();
Comparator<AbstractDistinctValuesCollector.GroupCount<Comparable<Object>>> cmp = new Comparator<AbstractDistinctValuesCollector.GroupCount<Comparable<Object>>>() {
Comparator<DistinctValuesCollector.GroupCount<Comparable<Object>>> cmp = new Comparator<DistinctValuesCollector.GroupCount<Comparable<Object>>>() {
@Override
public int compare(AbstractDistinctValuesCollector.GroupCount<Comparable<Object>> groupCount1, AbstractDistinctValuesCollector.GroupCount<Comparable<Object>> groupCount2) {
public int compare(DistinctValuesCollector.GroupCount<Comparable<Object>> groupCount1, DistinctValuesCollector.GroupCount<Comparable<Object>> groupCount2) {
if (groupCount1.groupValue == null) {
if (groupCount2.groupValue == null) {
return 0;
@ -145,13 +145,13 @@ public class DistinctValuesCollectorTest extends AbstractGroupingTestCase {
};
// === Search for content:random
AbstractFirstPassGroupingCollector<Comparable<Object>> firstCollector = createRandomFirstPassCollector(new Sort(), groupField, 10);
FirstPassGroupingCollector<Comparable<Object>> firstCollector = createRandomFirstPassCollector(new Sort(), groupField, 10);
indexSearcher.search(new TermQuery(new Term("content", "random")), firstCollector);
AbstractDistinctValuesCollector<? extends AbstractDistinctValuesCollector.GroupCount<Comparable<Object>>> distinctValuesCollector
DistinctValuesCollector<Comparable<Object>> distinctValuesCollector
= createDistinctCountCollector(firstCollector, groupField, countField);
indexSearcher.search(new TermQuery(new Term("content", "random")), distinctValuesCollector);
List<? extends AbstractDistinctValuesCollector.GroupCount<Comparable<Object>>> gcs = distinctValuesCollector.getGroups();
List<DistinctValuesCollector.GroupCount<Comparable<Object>>> gcs = distinctValuesCollector.getGroups();
Collections.sort(gcs, cmp);
assertEquals(4, gcs.size());
@ -240,15 +240,15 @@ public class DistinctValuesCollectorTest extends AbstractGroupingTestCase {
Sort groupSort = new Sort(new SortField("id", SortField.Type.STRING));
int topN = 1 + random.nextInt(10);
List<AbstractDistinctValuesCollector.GroupCount<Comparable<?>>> expectedResult = createExpectedResult(context, term, groupSort, topN);
List<DistinctValuesCollector.GroupCount<Comparable<?>>> expectedResult = createExpectedResult(context, term, groupSort, topN);
AbstractFirstPassGroupingCollector<Comparable<?>> firstCollector = createRandomFirstPassCollector(groupSort, groupField, topN);
FirstPassGroupingCollector<Comparable<?>> firstCollector = createRandomFirstPassCollector(groupSort, groupField, topN);
searcher.search(new TermQuery(new Term("content", term)), firstCollector);
AbstractDistinctValuesCollector<? extends AbstractDistinctValuesCollector.GroupCount<Comparable<?>>> distinctValuesCollector
DistinctValuesCollector<Comparable<?>> distinctValuesCollector
= createDistinctCountCollector(firstCollector, groupField, countField);
searcher.search(new TermQuery(new Term("content", term)), distinctValuesCollector);
@SuppressWarnings("unchecked")
List<AbstractDistinctValuesCollector.GroupCount<Comparable<?>>> actualResult = (List<AbstractDistinctValuesCollector.GroupCount<Comparable<?>>>) distinctValuesCollector.getGroups();
List<DistinctValuesCollector.GroupCount<Comparable<?>>> actualResult = distinctValuesCollector.getGroups();
if (VERBOSE) {
System.out.println("Index iter=" + indexIter);
@ -265,8 +265,8 @@ public class DistinctValuesCollectorTest extends AbstractGroupingTestCase {
assertEquals(expectedResult.size(), actualResult.size());
for (int i = 0; i < expectedResult.size(); i++) {
AbstractDistinctValuesCollector.GroupCount<Comparable<?>> expected = expectedResult.get(i);
AbstractDistinctValuesCollector.GroupCount<Comparable<?>> actual = actualResult.get(i);
DistinctValuesCollector.GroupCount<Comparable<?>> expected = expectedResult.get(i);
DistinctValuesCollector.GroupCount<Comparable<?>> actual = actualResult.get(i);
assertValues(expected.groupValue, actual.groupValue);
assertEquals(expected.uniqueValues.size(), actual.uniqueValues.size());
List<Comparable<?>> expectedUniqueValues = new ArrayList<>(expected.uniqueValues);
@ -283,9 +283,9 @@ public class DistinctValuesCollectorTest extends AbstractGroupingTestCase {
}
}
private void printGroups(List<AbstractDistinctValuesCollector.GroupCount<Comparable<?>>> results) {
private void printGroups(List<? extends DistinctValuesCollector.GroupCount<Comparable<?>>> results) {
for(int i=0;i<results.size();i++) {
AbstractDistinctValuesCollector.GroupCount<Comparable<?>> group = results.get(i);
DistinctValuesCollector.GroupCount<Comparable<?>> group = results.get(i);
Object gv = group.groupValue;
if (gv instanceof BytesRef) {
System.out.println(i + ": groupValue=" + ((BytesRef) gv).utf8ToString());
@ -350,31 +350,31 @@ public class DistinctValuesCollectorTest extends AbstractGroupingTestCase {
}
@SuppressWarnings({"unchecked","rawtypes"})
private <T extends Comparable> AbstractDistinctValuesCollector<AbstractDistinctValuesCollector.GroupCount<T>> createDistinctCountCollector(AbstractFirstPassGroupingCollector<T> firstPassGroupingCollector,
String groupField,
String countField) throws IOException {
private <T extends Comparable> DistinctValuesCollector<T> createDistinctCountCollector(FirstPassGroupingCollector<T> firstPassGroupingCollector,
String groupField,
String countField) throws IOException {
Random random = random();
Collection<SearchGroup<T>> searchGroups = firstPassGroupingCollector.getTopGroups(0, false);
if (FunctionFirstPassGroupingCollector.class.isAssignableFrom(firstPassGroupingCollector.getClass())) {
return (AbstractDistinctValuesCollector) new FunctionDistinctValuesCollector(new HashMap<>(), new BytesRefFieldSource(groupField), new BytesRefFieldSource(countField), (Collection) searchGroups);
return (DistinctValuesCollector) new FunctionDistinctValuesCollector(new HashMap<>(), new BytesRefFieldSource(groupField), new BytesRefFieldSource(countField), (Collection) searchGroups);
} else {
return (AbstractDistinctValuesCollector) new TermDistinctValuesCollector(groupField, countField, (Collection) searchGroups);
return (DistinctValuesCollector) new TermDistinctValuesCollector(groupField, countField, (Collection) searchGroups);
}
}
@SuppressWarnings({"unchecked","rawtypes"})
private <T> AbstractFirstPassGroupingCollector<T> createRandomFirstPassCollector(Sort groupSort, String groupField, int topNGroups) throws IOException {
private <T> FirstPassGroupingCollector<T> createRandomFirstPassCollector(Sort groupSort, String groupField, int topNGroups) throws IOException {
Random random = random();
if (random.nextBoolean()) {
return (AbstractFirstPassGroupingCollector<T>) new FunctionFirstPassGroupingCollector(new BytesRefFieldSource(groupField), new HashMap<>(), groupSort, topNGroups);
return (FirstPassGroupingCollector<T>) new FunctionFirstPassGroupingCollector(new BytesRefFieldSource(groupField), new HashMap<>(), groupSort, topNGroups);
} else {
return (AbstractFirstPassGroupingCollector<T>) new TermFirstPassGroupingCollector(groupField, groupSort, topNGroups);
return (FirstPassGroupingCollector<T>) new TermFirstPassGroupingCollector(groupField, groupSort, topNGroups);
}
}
@SuppressWarnings({"unchecked","rawtypes"})
private List<AbstractDistinctValuesCollector.GroupCount<Comparable<?>>> createExpectedResult(IndexContext context, String term, Sort groupSort, int topN) {
class GroupCount extends AbstractDistinctValuesCollector.GroupCount<BytesRef> {
private List<DistinctValuesCollector.GroupCount<Comparable<?>>> createExpectedResult(IndexContext context, String term, Sort groupSort, int topN) {
class GroupCount extends DistinctValuesCollector.GroupCount<BytesRef> {
GroupCount(BytesRef groupValue, Collection<BytesRef> uniqueValues) {
super(groupValue);
this.uniqueValues.addAll(uniqueValues);

View File

@ -103,7 +103,7 @@ public class GroupFacetCollectorTest extends AbstractGroupingTestCase {
IndexSearcher indexSearcher = newSearcher(w.getReader());
List<TermGroupFacetCollector.FacetEntry> entries;
AbstractGroupFacetCollector groupedAirportFacetCollector;
GroupFacetCollector groupedAirportFacetCollector;
TermGroupFacetCollector.GroupedFacetResult airportResult;
for (int limit : new int[] { 2, 10, 100, Integer.MAX_VALUE }) {
@ -136,7 +136,7 @@ public class GroupFacetCollectorTest extends AbstractGroupingTestCase {
assertEquals(1, entries.get(0).getCount());
}
AbstractGroupFacetCollector groupedDurationFacetCollector = createRandomCollector(useDv ? "hotel_dv" : "hotel", useDv ? "duration_dv" : "duration", null, false);
GroupFacetCollector groupedDurationFacetCollector = createRandomCollector(useDv ? "hotel_dv" : "hotel", useDv ? "duration_dv" : "duration", null, false);
indexSearcher.search(new MatchAllDocsQuery(), groupedDurationFacetCollector);
TermGroupFacetCollector.GroupedFacetResult durationResult = groupedDurationFacetCollector.mergeSegmentResults(10, 0, false);
assertEquals(4, durationResult.getTotalCount());
@ -344,7 +344,7 @@ public class GroupFacetCollectorTest extends AbstractGroupingTestCase {
w.close();
IndexSearcher indexSearcher = newSearcher(DirectoryReader.open(dir));
AbstractGroupFacetCollector groupedAirportFacetCollector = createRandomCollector(groupField + "_dv", "airport", null, true);
GroupFacetCollector groupedAirportFacetCollector = createRandomCollector(groupField + "_dv", "airport", null, true);
indexSearcher.search(new MatchAllDocsQuery(), groupedAirportFacetCollector);
TermGroupFacetCollector.GroupedFacetResult airportResult = groupedAirportFacetCollector.mergeSegmentResults(10, 0, false);
assertEquals(3, airportResult.getTotalCount());
@ -404,7 +404,7 @@ public class GroupFacetCollectorTest extends AbstractGroupingTestCase {
}
GroupedFacetResult expectedFacetResult = createExpectedFacetResult(searchTerm, context, offset, limit, minCount, orderByCount, facetPrefix);
AbstractGroupFacetCollector groupFacetCollector = createRandomCollector("group", "facet", facetPrefix, multipleFacetsPerDocument);
GroupFacetCollector groupFacetCollector = createRandomCollector("group", "facet", facetPrefix, multipleFacetsPerDocument);
searcher.search(new TermQuery(new Term("content", searchTerm)), groupFacetCollector);
TermGroupFacetCollector.GroupedFacetResult actualFacetResult = groupFacetCollector.mergeSegmentResults(size, minCount, orderByCount);
@ -704,7 +704,7 @@ public class GroupFacetCollectorTest extends AbstractGroupingTestCase {
return new GroupedFacetResult(totalCount, totalMissCount, entriesResult);
}
private AbstractGroupFacetCollector createRandomCollector(String groupField, String facetField, String facetPrefix, boolean multipleFacetsPerDocument) {
private GroupFacetCollector createRandomCollector(String groupField, String facetField, String facetPrefix, boolean multipleFacetsPerDocument) {
BytesRef facetPrefixBR = facetPrefix == null ? null : new BytesRef(facetPrefix);
return TermGroupFacetCollector.createTermGroupFacetCollector(groupField, facetField, multipleFacetsPerDocument, facetPrefixBR, random().nextInt(1024));
}

View File

@ -144,10 +144,10 @@ public class TestGrouping extends LuceneTestCase {
final Sort groupSort = Sort.RELEVANCE;
final AbstractFirstPassGroupingCollector<?> c1 = createRandomFirstPassCollector(groupField, groupSort, 10);
final FirstPassGroupingCollector<?> c1 = createRandomFirstPassCollector(groupField, groupSort, 10);
indexSearcher.search(new TermQuery(new Term("content", "random")), c1);
final AbstractSecondPassGroupingCollector<?> c2 = createSecondPassCollector(c1, groupField, groupSort, Sort.RELEVANCE, 0, 5, true, true, true);
final SecondPassGroupingCollector<?> c2 = createSecondPassCollector(c1, groupField, groupSort, Sort.RELEVANCE, 0, 5, true, true, true);
indexSearcher.search(new TermQuery(new Term("content", "random")), c2);
final TopGroups<?> groups = c2.getTopGroups(0);
@ -195,8 +195,8 @@ public class TestGrouping extends LuceneTestCase {
doc.add(new SortedDocValuesField(groupField, new BytesRef(value)));
}
private AbstractFirstPassGroupingCollector<?> createRandomFirstPassCollector(String groupField, Sort groupSort, int topDocs) throws IOException {
AbstractFirstPassGroupingCollector<?> selected;
private FirstPassGroupingCollector<?> createRandomFirstPassCollector(String groupField, Sort groupSort, int topDocs) throws IOException {
FirstPassGroupingCollector<?> selected;
if (random().nextBoolean()) {
ValueSource vs = new BytesRefFieldSource(groupField);
selected = new FunctionFirstPassGroupingCollector(vs, new HashMap<>(), groupSort, topDocs);
@ -209,7 +209,7 @@ public class TestGrouping extends LuceneTestCase {
return selected;
}
private AbstractFirstPassGroupingCollector<?> createFirstPassCollector(String groupField, Sort groupSort, int topDocs, AbstractFirstPassGroupingCollector<?> firstPassGroupingCollector) throws IOException {
private FirstPassGroupingCollector<?> createFirstPassCollector(String groupField, Sort groupSort, int topDocs, FirstPassGroupingCollector<?> firstPassGroupingCollector) throws IOException {
if (TermFirstPassGroupingCollector.class.isAssignableFrom(firstPassGroupingCollector.getClass())) {
ValueSource vs = new BytesRefFieldSource(groupField);
return new FunctionFirstPassGroupingCollector(vs, new HashMap<>(), groupSort, topDocs);
@ -219,37 +219,37 @@ public class TestGrouping extends LuceneTestCase {
}
@SuppressWarnings({"unchecked","rawtypes"})
private <T> AbstractSecondPassGroupingCollector<T> createSecondPassCollector(AbstractFirstPassGroupingCollector firstPassGroupingCollector,
String groupField,
Sort groupSort,
Sort sortWithinGroup,
int groupOffset,
int maxDocsPerGroup,
boolean getScores,
boolean getMaxScores,
boolean fillSortFields) throws IOException {
private <T> SecondPassGroupingCollector<T> createSecondPassCollector(FirstPassGroupingCollector firstPassGroupingCollector,
String groupField,
Sort groupSort,
Sort sortWithinGroup,
int groupOffset,
int maxDocsPerGroup,
boolean getScores,
boolean getMaxScores,
boolean fillSortFields) throws IOException {
if (TermFirstPassGroupingCollector.class.isAssignableFrom(firstPassGroupingCollector.getClass())) {
Collection<SearchGroup<BytesRef>> searchGroups = firstPassGroupingCollector.getTopGroups(groupOffset, fillSortFields);
return (AbstractSecondPassGroupingCollector) new TermSecondPassGroupingCollector(groupField, searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup , getScores, getMaxScores, fillSortFields);
return (SecondPassGroupingCollector) new TermSecondPassGroupingCollector(groupField, searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup , getScores, getMaxScores, fillSortFields);
} else {
ValueSource vs = new BytesRefFieldSource(groupField);
Collection<SearchGroup<MutableValue>> searchGroups = firstPassGroupingCollector.getTopGroups(groupOffset, fillSortFields);
return (AbstractSecondPassGroupingCollector) new FunctionSecondPassGroupingCollector(searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup, getScores, getMaxScores, fillSortFields, vs, new HashMap());
return (SecondPassGroupingCollector) new FunctionSecondPassGroupingCollector(searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup, getScores, getMaxScores, fillSortFields, vs, new HashMap());
}
}
// Basically converts searchGroups from MutableValue to BytesRef if grouping by ValueSource
@SuppressWarnings("unchecked")
private AbstractSecondPassGroupingCollector<?> createSecondPassCollector(AbstractFirstPassGroupingCollector<?> firstPassGroupingCollector,
String groupField,
Collection<SearchGroup<BytesRef>> searchGroups,
Sort groupSort,
Sort sortWithinGroup,
int maxDocsPerGroup,
boolean getScores,
boolean getMaxScores,
boolean fillSortFields) throws IOException {
private SecondPassGroupingCollector<?> createSecondPassCollector(FirstPassGroupingCollector<?> firstPassGroupingCollector,
String groupField,
Collection<SearchGroup<BytesRef>> searchGroups,
Sort groupSort,
Sort sortWithinGroup,
int maxDocsPerGroup,
boolean getScores,
boolean getMaxScores,
boolean fillSortFields) throws IOException {
if (firstPassGroupingCollector.getClass().isAssignableFrom(TermFirstPassGroupingCollector.class)) {
return new TermSecondPassGroupingCollector(groupField, searchGroups, groupSort, sortWithinGroup, maxDocsPerGroup , getScores, getMaxScores, fillSortFields);
} else {
@ -272,8 +272,8 @@ public class TestGrouping extends LuceneTestCase {
}
}
private AbstractAllGroupsCollector<?> createAllGroupsCollector(AbstractFirstPassGroupingCollector<?> firstPassGroupingCollector,
String groupField) {
private AllGroupsCollector<?> createAllGroupsCollector(FirstPassGroupingCollector<?> firstPassGroupingCollector,
String groupField) {
if (firstPassGroupingCollector.getClass().isAssignableFrom(TermFirstPassGroupingCollector.class)) {
return new TermAllGroupsCollector(groupField);
} else {
@ -305,7 +305,7 @@ public class TestGrouping extends LuceneTestCase {
}
}
private Collection<SearchGroup<BytesRef>> getSearchGroups(AbstractFirstPassGroupingCollector<?> c, int groupOffset, boolean fillFields) throws IOException {
private Collection<SearchGroup<BytesRef>> getSearchGroups(FirstPassGroupingCollector<?> c, int groupOffset, boolean fillFields) throws IOException {
if (TermFirstPassGroupingCollector.class.isAssignableFrom(c.getClass())) {
return ((TermFirstPassGroupingCollector) c).getTopGroups(groupOffset, fillFields);
} else if (FunctionFirstPassGroupingCollector.class.isAssignableFrom(c.getClass())) {
@ -328,7 +328,7 @@ public class TestGrouping extends LuceneTestCase {
}
@SuppressWarnings({"unchecked", "rawtypes"})
private TopGroups<BytesRef> getTopGroups(AbstractSecondPassGroupingCollector c, int withinGroupOffset) {
private TopGroups<BytesRef> getTopGroups(SecondPassGroupingCollector c, int withinGroupOffset) {
if (c.getClass().isAssignableFrom(TermSecondPassGroupingCollector.class)) {
return ((TermSecondPassGroupingCollector) c).getTopGroups(withinGroupOffset);
} else if (c.getClass().isAssignableFrom(FunctionSecondPassGroupingCollector.class)) {
@ -874,11 +874,11 @@ public class TestGrouping extends LuceneTestCase {
if (VERBOSE) {
System.out.println(" groupField=" + groupField);
}
final AbstractFirstPassGroupingCollector<?> c1 = createRandomFirstPassCollector(groupField, groupSort, groupOffset+topNGroups);
final FirstPassGroupingCollector<?> c1 = createRandomFirstPassCollector(groupField, groupSort, groupOffset+topNGroups);
final CachingCollector cCache;
final Collector c;
final AbstractAllGroupsCollector<?> allGroupsCollector;
final AllGroupsCollector<?> allGroupsCollector;
if (doAllGroups) {
allGroupsCollector = createAllGroupsCollector(c1, groupField);
} else {
@ -953,7 +953,7 @@ public class TestGrouping extends LuceneTestCase {
final TopGroups<BytesRef> topGroupsShards = searchShards(s, shards.subSearchers, query, groupSort, docSort,
groupOffset, topNGroups, docOffset, docsPerGroup, getScores, getMaxScores, true, false);
final AbstractSecondPassGroupingCollector<?> c2;
final SecondPassGroupingCollector<?> c2;
if (topGroups != null) {
if (VERBOSE) {
@ -1172,8 +1172,8 @@ public class TestGrouping extends LuceneTestCase {
// Run 1st pass collector to get top groups per shard
final Weight w = topSearcher.createNormalizedWeight(query, getScores);
final List<Collection<SearchGroup<BytesRef>>> shardGroups = new ArrayList<>();
List<AbstractFirstPassGroupingCollector<?>> firstPassGroupingCollectors = new ArrayList<>();
AbstractFirstPassGroupingCollector<?> firstPassCollector = null;
List<FirstPassGroupingCollector<?>> firstPassGroupingCollectors = new ArrayList<>();
FirstPassGroupingCollector<?> firstPassCollector = null;
boolean shardsCanUseIDV = canUseIDV;
String groupField = "group";
@ -1223,7 +1223,7 @@ public class TestGrouping extends LuceneTestCase {
@SuppressWarnings({"unchecked","rawtypes"})
final TopGroups<BytesRef>[] shardTopGroups = new TopGroups[subSearchers.length];
for(int shardIDX=0;shardIDX<subSearchers.length;shardIDX++) {
final AbstractSecondPassGroupingCollector<?> secondPassCollector = createSecondPassCollector(firstPassGroupingCollectors.get(shardIDX),
final SecondPassGroupingCollector<?> secondPassCollector = createSecondPassCollector(firstPassGroupingCollectors.get(shardIDX),
groupField, mergedTopGroups, groupSort, docSort, docOffset + topNDocs, getScores, getMaxScores, true);
subSearchers[shardIDX].search(w, secondPassCollector);
shardTopGroups[shardIDX] = getTopGroups(secondPassCollector, 0);

View File

@ -51,7 +51,7 @@ import org.apache.lucene.search.FilterCollector;
import org.apache.lucene.search.LeafCollector;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TermQuery;
import org.apache.lucene.search.grouping.AbstractAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.AllGroupHeadsCollector;
import org.apache.lucene.search.grouping.term.TermAllGroupsCollector;
import org.apache.lucene.search.grouping.term.TermGroupFacetCollector;
import org.apache.lucene.util.BytesRef;
@ -282,7 +282,7 @@ public class SimpleFacets {
} else {
return base;
}
AbstractAllGroupHeadsCollector allGroupHeadsCollector = grouping.getCommands().get(0).createAllGroupCollector();
AllGroupHeadsCollector allGroupHeadsCollector = grouping.getCommands().get(0).createAllGroupCollector();
searcher.search(base.getTopFilter(), allGroupHeadsCollector);
return new BitDocSet(allGroupHeadsCollector.retrieveGroupHeads(searcher.maxDoc()));
} else {

View File

@ -46,7 +46,7 @@ import org.apache.lucene.search.TopDocsCollector;
import org.apache.lucene.search.TopFieldCollector;
import org.apache.lucene.search.TopScoreDocCollector;
import org.apache.lucene.search.TotalHitCountCollector;
import org.apache.lucene.search.grouping.AbstractAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.AllGroupHeadsCollector;
import org.apache.lucene.search.grouping.GroupDocs;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.search.grouping.TopGroups;
@ -323,7 +323,7 @@ public class Grouping {
cmd.prepare();
}
AbstractAllGroupHeadsCollector<?> allGroupHeadsCollector = null;
AllGroupHeadsCollector<?> allGroupHeadsCollector = null;
List<Collector> collectors = new ArrayList<>(commands.size());
for (Command cmd : commands) {
Collector collector = cmd.createFirstPassCollector();
@ -513,7 +513,7 @@ public class Grouping {
* Note: Maybe the creating the response structure should be done in something like a ReponseBuilder???
* Warning NOT thread save!
*/
public abstract class Command<GROUP_VALUE_TYPE> {
public abstract class Command<T> {
public String key; // the name to use for this group in the response
public Sort withinGroupSort; // the sort of the documents *within* a single group.
@ -527,7 +527,7 @@ public class Grouping {
public boolean main; // use as the main result in simple format (grouped.main=true param)
public TotalCount totalCount = TotalCount.ungrouped;
TopGroups<GROUP_VALUE_TYPE> result;
TopGroups<T> result;
/**
@ -565,7 +565,7 @@ public class Grouping {
* @return a collector that is able to return the most relevant document of all groups.
* @throws IOException If I/O related errors occur
*/
public AbstractAllGroupHeadsCollector<?> createAllGroupCollector() throws IOException {
public AllGroupHeadsCollector<?> createAllGroupCollector() throws IOException {
return null;
}
@ -774,7 +774,7 @@ public class Grouping {
* {@inheritDoc}
*/
@Override
public AbstractAllGroupHeadsCollector<?> createAllGroupCollector() throws IOException {
public AllGroupHeadsCollector<?> createAllGroupCollector() throws IOException {
Sort sortWithinGroup = withinGroupSort != null ? withinGroupSort : Sort.RELEVANCE;
return TermAllGroupHeadsCollector.create(groupBy, sortWithinGroup);
}
@ -992,7 +992,7 @@ public class Grouping {
}
@Override
public AbstractAllGroupHeadsCollector<?> createAllGroupCollector() throws IOException {
public AllGroupHeadsCollector<?> createAllGroupCollector() throws IOException {
Sort sortWithinGroup = withinGroupSort != null ? withinGroupSort : Sort.RELEVANCE;
return new FunctionAllGroupHeadsCollector(groupBy, context, sortWithinGroup);
}

View File

@ -31,7 +31,7 @@ import org.apache.lucene.search.MultiCollector;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.TimeLimitingCollector;
import org.apache.lucene.search.TotalHitCountCollector;
import org.apache.lucene.search.grouping.AbstractAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.AllGroupHeadsCollector;
import org.apache.lucene.search.grouping.function.FunctionAllGroupHeadsCollector;
import org.apache.lucene.search.grouping.term.TermAllGroupHeadsCollector;
import org.apache.solr.common.util.NamedList;
@ -170,7 +170,7 @@ public class CommandHandler {
SchemaField sf = searcher.getSchema().getField(field);
FieldType fieldType = sf.getType();
final AbstractAllGroupHeadsCollector allGroupHeadsCollector;
final AllGroupHeadsCollector allGroupHeadsCollector;
if (fieldType.getNumericType() != null) {
ValueSource vs = fieldType.getValueSource(sf, null);
allGroupHeadsCollector = new FunctionAllGroupHeadsCollector(vs, new HashMap(), firstCommand.getSortWithinGroup());

View File

@ -19,8 +19,8 @@ package org.apache.solr.search.grouping.distributed.command;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AbstractAllGroupsCollector;
import org.apache.lucene.search.grouping.AbstractFirstPassGroupingCollector;
import org.apache.lucene.search.grouping.AllGroupsCollector;
import org.apache.lucene.search.grouping.FirstPassGroupingCollector;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.search.grouping.function.FunctionAllGroupsCollector;
import org.apache.lucene.search.grouping.function.FunctionFirstPassGroupingCollector;
@ -81,8 +81,8 @@ public class SearchGroupsFieldCommand implements Command<SearchGroupsFieldComman
private final int topNGroups;
private final boolean includeGroupCount;
private AbstractFirstPassGroupingCollector firstPassGroupingCollector;
private AbstractAllGroupsCollector allGroupsCollector;
private FirstPassGroupingCollector firstPassGroupingCollector;
private AllGroupsCollector allGroupsCollector;
private SearchGroupsFieldCommand(SchemaField field, Sort groupSort, int topNGroups, boolean includeGroupCount) {
this.field = field;

View File

@ -19,7 +19,7 @@ package org.apache.solr.search.grouping.distributed.command;
import org.apache.lucene.queries.function.ValueSource;
import org.apache.lucene.search.Collector;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.AbstractSecondPassGroupingCollector;
import org.apache.lucene.search.grouping.SecondPassGroupingCollector;
import org.apache.lucene.search.grouping.GroupDocs;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.search.grouping.TopGroups;
@ -106,7 +106,7 @@ public class TopGroupsFieldCommand implements Command<TopGroups<BytesRef>> {
private final int maxDocPerGroup;
private final boolean needScores;
private final boolean needMaxScore;
private AbstractSecondPassGroupingCollector secondPassCollector;
private SecondPassGroupingCollector secondPassCollector;
private TopGroupsFieldCommand(SchemaField field,
Sort groupSort,