in solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java [54:224]
public void process(ResponseBuilder rb, ShardRequest shardRequest) {
Sort groupSort = rb.getGroupingSpec().getGroupSortSpec().getSort();
String[] fields = rb.getGroupingSpec().getFields();
String[] queries = rb.getGroupingSpec().getQueries();
SortSpec withinGroupSortSpec = rb.getGroupingSpec().getWithinGroupSortSpec();
Sort withinGroupSort = withinGroupSortSpec.getSort();
assert withinGroupSort != null;
boolean simpleOrMain =
rb.getGroupingSpec().getResponseFormat() == Grouping.Format.simple
|| rb.getGroupingSpec().isMain();
// If group.format=simple group.offset doesn't make sense
int groupOffsetDefault;
if (simpleOrMain) {
groupOffsetDefault = 0;
} else {
groupOffsetDefault = withinGroupSortSpec.getOffset();
}
int docsPerGroupDefault = withinGroupSortSpec.getCount();
Map<String, List<TopGroups<BytesRef>>> commandTopGroups = new HashMap<>();
for (String field : fields) {
commandTopGroups.put(field, new ArrayList<>());
}
Map<String, List<QueryCommandResult>> commandTopDocs = new HashMap<>();
for (String query : queries) {
commandTopDocs.put(query, new ArrayList<>());
}
TopGroupsResultTransformer serializer = new TopGroupsResultTransformer(rb);
NamedList<Object> shardInfo = null;
if (rb.req.getParams().getBool(ShardParams.SHARDS_INFO, false)) {
shardInfo = new SimpleOrderedMap<>();
rb.rsp.getValues().add(ShardParams.SHARDS_INFO, shardInfo);
}
for (ShardResponse srsp : shardRequest.responses) {
SimpleOrderedMap<Object> individualShardInfo = null;
if (shardInfo != null) {
individualShardInfo = new SimpleOrderedMap<>();
if (srsp.getException() != null) {
Throwable t = srsp.getException();
if (t instanceof SolrServerException && ((SolrServerException) t).getCause() != null) {
t = ((SolrServerException) t).getCause();
}
individualShardInfo.add("error", t.toString());
if (!rb.req.getCore().getCoreContainer().hideStackTrace()) {
StringWriter trace = new StringWriter();
t.printStackTrace(new PrintWriter(trace));
individualShardInfo.add("trace", trace.toString());
}
} else {
// summary for successful shard response is added down below
}
if (srsp.getSolrResponse() != null) {
individualShardInfo.add("time", srsp.getSolrResponse().getElapsedTime());
}
if (srsp.getShardAddress() != null) {
individualShardInfo.add("shardAddress", srsp.getShardAddress());
}
shardInfo.add(srsp.getShard(), individualShardInfo);
}
if (HttpShardHandler.getShardsTolerantAsBool(rb.req) && srsp.getException() != null) {
rb.rsp.setPartialResults(rb.req);
continue; // continue if there was an error and we're tolerant.
}
NamedList<NamedList<?>> secondPhaseResult =
(NamedList<NamedList<?>>)
SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "secondPhase", false);
if (secondPhaseResult == null) {
continue;
}
Map<String, ?> result =
serializer.transformToNative(
secondPhaseResult, groupSort, withinGroupSort, srsp.getShard());
int numFound = 0;
float maxScore = Float.NaN;
for (Map.Entry<String, List<TopGroups<BytesRef>>> entry : commandTopGroups.entrySet()) {
TopGroups<BytesRef> topGroups = (TopGroups<BytesRef>) result.get(entry.getKey());
if (topGroups == null) {
continue;
}
if (individualShardInfo != null) { // keep track of this when shards.info=true
numFound += topGroups.totalHitCount;
if (Float.isNaN(maxScore) || topGroups.maxScore > maxScore) maxScore = topGroups.maxScore;
}
entry.getValue().add(topGroups);
}
for (String query : queries) {
QueryCommandResult queryCommandResult = (QueryCommandResult) result.get(query);
if (individualShardInfo != null) { // keep track of this when shards.info=true
numFound += queryCommandResult.getMatches();
float thisMax = queryCommandResult.getMaxScore();
if (Float.isNaN(maxScore) || thisMax > maxScore) maxScore = thisMax;
}
commandTopDocs.get(query).add(queryCommandResult);
}
if (individualShardInfo != null) { // when shards.info=true
individualShardInfo.add("numFound", numFound);
individualShardInfo.add("maxScore", maxScore);
}
}
for (Map.Entry<String, List<TopGroups<BytesRef>>> entry : commandTopGroups.entrySet()) {
List<TopGroups<BytesRef>> topGroups = entry.getValue();
if (topGroups.isEmpty()) {
continue;
}
TopGroups<BytesRef>[] topGroupsArr =
(TopGroups<BytesRef>[]) Array.newInstance(TopGroups.class, topGroups.size());
int docsPerGroup = docsPerGroupDefault;
if (docsPerGroup < 0) {
docsPerGroup = 0;
for (TopGroups<?> subTopGroups : topGroups) {
docsPerGroup += subTopGroups.totalGroupedHitCount;
}
}
rb.mergedTopGroups.put(
entry.getKey(),
TopGroups.merge(
topGroups.toArray(topGroupsArr),
groupSort,
withinGroupSort,
groupOffsetDefault,
docsPerGroup,
TopGroups.ScoreMergeMode.None));
}
// calculate topN and start for group.query
int topN = docsPerGroupDefault >= 0 ? docsPerGroupDefault : Integer.MAX_VALUE;
int start = groupOffsetDefault;
if (simpleOrMain) {
// use start and rows here
start = rb.getGroupingSpec().getGroupSortSpec().getOffset();
int limit = rb.getGroupingSpec().getGroupSortSpec().getCount();
topN = limit >= 0 ? limit : Integer.MAX_VALUE;
}
for (Map.Entry<String, List<QueryCommandResult>> entry : commandTopDocs.entrySet()) {
List<QueryCommandResult> queryCommandResults = entry.getValue();
List<TopDocs> topDocs = new ArrayList<>(queryCommandResults.size());
int mergedMatches = 0;
float maxScore = Float.NaN;
for (QueryCommandResult queryCommandResult : queryCommandResults) {
TopDocs thisTopDocs = queryCommandResult.getTopDocs();
topDocs.add(thisTopDocs);
mergedMatches += queryCommandResult.getMatches();
if (thisTopDocs.scoreDocs.length > 0) {
float thisMaxScore = queryCommandResult.getMaxScore();
if (Float.isNaN(maxScore) || thisMaxScore > maxScore) {
maxScore = thisMaxScore;
}
}
}
final TopDocs mergedTopDocs;
if (withinGroupSort.equals(Sort.RELEVANCE)) {
mergedTopDocs = TopDocs.merge(start, topN, topDocs.toArray(new TopDocs[0]));
} else {
mergedTopDocs =
TopDocs.merge(withinGroupSort, start, topN, topDocs.toArray(new TopFieldDocs[0]));
}
rb.mergedQueryCommandResults.put(
entry.getKey(), new QueryCommandResult(mergedTopDocs, mergedMatches, maxScore));
}
fillResultIds(rb);
}