You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@solr.apache.org by kr...@apache.org on 2022/09/21 16:07:09 UTC
[solr] branch branch_9x updated: SOLR-16418: Introduce SolrResponseUtil to handle NPE during query timeout or exception when parsing SolrResponse (#1026)
This is an automated email from the ASF dual-hosted git repository.
krisden pushed a commit to branch branch_9x
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/branch_9x by this push:
new 6f5f8369e2d SOLR-16418: Introduce SolrResponseUtil to handle NPE during query timeout or exception when parsing SolrResponse (#1026)
6f5f8369e2d is described below
commit 6f5f8369e2d2a4ce7e4df023ced85534d8e9ccc3
Author: Kevin Risden <ri...@users.noreply.github.com>
AuthorDate: Wed Sep 21 12:04:35 2022 -0400
SOLR-16418: Introduce SolrResponseUtil to handle NPE during query timeout or exception when parsing SolrResponse (#1026)
---
solr/CHANGES.txt | 2 +
.../solr/handler/component/DebugComponent.java | 6 +-
.../solr/handler/component/ExpandComponent.java | 9 ++-
.../solr/handler/component/FacetComponent.java | 55 ++++------------
.../solr/handler/component/HighlightComponent.java | 8 ++-
.../solr/handler/component/QueryComponent.java | 39 +++++++++--
.../handler/component/SpellCheckComponent.java | 21 ++----
.../solr/handler/component/StatsComponent.java | 22 +++----
.../solr/handler/component/SuggestComponent.java | 22 ++++---
.../handler/component/TermVectorComponent.java | 21 +++---
.../solr/handler/component/TermsComponent.java | 7 +-
.../SearchGroupShardResponseProcessor.java | 44 +++++++------
.../StoredFieldsShardResponseProcessor.java | 15 +++--
.../TopGroupsShardResponseProcessor.java | 8 ++-
.../org/apache/solr/util/SolrResponseUtil.java | 77 ++++++++++++++++++++++
.../apache/solr/search/RankQueryTestPlugin.java | 41 +++++++++---
16 files changed, 255 insertions(+), 142 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index b3ebc3bb9c1..71ab6fbffe1 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -133,6 +133,8 @@ Bug Fixes
* SOLR-16414 : Race condition in PRS state updates (noble, Justin Sweeney, Patson Luk, Hitesh Khamesra, Ishan Chattopadhyaya)
+* SOLR-16418: Introduce SolrResponseUtil to handle NPE during query timeout or exception when parsing SolrResponse (Kevin Risden)
+
Other Changes
---------------------
* SOLR-16351: Upgrade Carrot2 to 4.4.3, upgrade randomizedtesting to 2.8.0. (Dawid Weiss)
diff --git a/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java b/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java
index b46b0f4260e..7212fc309d3 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/DebugComponent.java
@@ -41,6 +41,7 @@ import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.facet.FacetDebugInfo;
import org.apache.solr.search.stats.StatsCache;
import org.apache.solr.util.SolrPluginUtils;
+import org.apache.solr.util.SolrResponseUtil;
/**
* Adds debugging information to a request.
@@ -219,12 +220,13 @@ public class DebugComponent extends SearchComponent {
continue;
}
NamedList<Object> sdebug =
- (NamedList<Object>) srsp.getSolrResponse().getResponse().get("debug");
+ (NamedList<Object>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "debug", true);
info = (NamedList<Object>) merge(sdebug, info, EXCLUDE_SET);
if ((sreq.purpose & ShardRequest.PURPOSE_GET_DEBUG) != 0) {
hasGetDebugResponses = true;
- if (rb.isDebugResults()) {
+ if (rb.isDebugResults() && sdebug != null) {
NamedList<Object> sexplain = (NamedList<Object>) sdebug.get("explain");
SolrPluginUtils.copyNamedListIntoArrayByDocPosInResponse(sexplain, rb.resultIds, arr);
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
index 4430f0c781e..de5dcb7b9f8 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/ExpandComponent.java
@@ -84,6 +84,7 @@ import org.apache.solr.search.ReturnFields;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SortSpecParsing;
import org.apache.solr.search.SyntaxError;
+import org.apache.solr.util.SolrResponseUtil;
import org.apache.solr.util.plugin.PluginInfoInitialized;
/**
@@ -479,8 +480,12 @@ public class ExpandComponent extends SearchComponent implements PluginInfoInitia
}
for (ShardResponse srsp : sreq.responses) {
- NamedList<Object> response = srsp.getSolrResponse().getResponse();
- NamedList<?> ex = (NamedList<?>) response.get("expanded");
+ NamedList<?> ex =
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "expanded", false);
+ if (ex == null) {
+ continue;
+ }
for (int i = 0; i < ex.size(); i++) {
String name = ex.getName(i);
SolrDocumentList val = (SolrDocumentList) ex.getVal(i);
diff --git a/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java b/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java
index 868441f67d5..77c0d426c32 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/FacetComponent.java
@@ -34,21 +34,18 @@ import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.lucene.util.BytesRef;
import org.apache.lucene.util.FixedBitSet;
-import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.FacetParams;
import org.apache.solr.common.params.ModifiableSolrParams;
-import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.request.SimpleFacets;
import org.apache.solr.request.SolrQueryRequest;
-import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.PointField;
import org.apache.solr.search.DocSet;
@@ -56,6 +53,7 @@ import org.apache.solr.search.QueryParsing;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.search.facet.FacetDebugInfo;
import org.apache.solr.util.RTimer;
+import org.apache.solr.util.SolrResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -715,7 +713,9 @@ public class FacetComponent extends SearchComponent {
for (ShardResponse srsp : sreq.responses) {
int shardNum = rb.getShardNum(srsp.getShard());
- NamedList<?> facet_counts = getFacetCountsFromShardResponse(rb, srsp);
+ NamedList<?> facet_counts =
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, FACET_COUNTS_KEY, false);
if (facet_counts == null) {
continue; // looks like a shard did not return anything
}
@@ -839,42 +839,6 @@ public class FacetComponent extends SearchComponent {
removeQueryFacetsUnderLimits(rb);
}
- private static NamedList<?> getFacetCountsFromShardResponse(
- ResponseBuilder rb, ShardResponse srsp) {
- NamedList<?> facet_counts;
- try {
- SolrResponse solrResponse = srsp.getSolrResponse();
- NamedList<Object> response = solrResponse.getResponse();
- facet_counts = (NamedList<?>) response.get(FACET_COUNTS_KEY);
- if (facet_counts != null) {
- return facet_counts;
- } else {
- NamedList<?> responseHeader =
- (NamedList<?>) response.get(SolrQueryResponse.RESPONSE_HEADER_KEY);
- if (responseHeader.getBooleanArg(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY)) {
- return null;
- } else {
- log.warn("corrupted response on {} : {}", srsp.getShardRequest(), solrResponse);
- throw new SolrException(
- ErrorCode.SERVER_ERROR,
- FACET_COUNTS_KEY
- + " is absent in response from "
- + srsp.getNodeName()
- + ", but "
- + SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY
- + " isn't set in the response.");
- }
- }
- } catch (Exception ex) {
- if (ShardParams.getShardsTolerantAsBool(rb.req.getParams())) {
- return null;
- } else {
- throw new SolrException(
- ErrorCode.SERVER_ERROR, "Unable to read facet info for shard: " + srsp.getShard(), ex);
- }
- }
- }
-
private void removeQueryFacetsUnderLimits(ResponseBuilder rb) {
if (rb.stage != ResponseBuilder.STAGE_EXECUTE_QUERY) {
return;
@@ -1011,7 +975,9 @@ public class FacetComponent extends SearchComponent {
FacetInfo fi = rb._facetInfo;
for (ShardResponse srsp : sreq.responses) {
- NamedList<?> facet_counts = getFacetCountsFromShardResponse(rb, srsp);
+ NamedList<?> facet_counts =
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, FACET_COUNTS_KEY, false);
if (facet_counts == null) {
continue; // looks like a shard did not return anything
}
@@ -1051,11 +1017,14 @@ public class FacetComponent extends SearchComponent {
// This is after the shard has returned the refinement request
FacetInfo fi = rb._facetInfo;
for (ShardResponse srsp : sreq.responses) {
-
int shardNumber = rb.getShardNum(srsp.getShard());
NamedList<?> facetCounts =
- (NamedList<?>) srsp.getSolrResponse().getResponse().get(FACET_COUNTS_KEY);
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, FACET_COUNTS_KEY, false);
+ if (facetCounts == null) {
+ continue;
+ }
@SuppressWarnings("unchecked")
NamedList<List<NamedList<Object>>> pivotFacetResponsesFromShard =
diff --git a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
index 9c109fd34f2..918a036e787 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/HighlightComponent.java
@@ -43,6 +43,7 @@ import org.apache.solr.search.QParserPlugin;
import org.apache.solr.search.QueryParsing;
import org.apache.solr.search.SyntaxError;
import org.apache.solr.util.SolrPluginUtils;
+import org.apache.solr.util.SolrResponseUtil;
import org.apache.solr.util.plugin.PluginInfoInitialized;
import org.apache.solr.util.plugin.SolrCoreAware;
@@ -224,7 +225,12 @@ public class HighlightComponent extends SearchComponent
// this should only happen when using shards.tolerant=true
continue;
}
- Object hl = srsp.getSolrResponse().getResponse().get(highlightingResponseField);
+ Object hl =
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ rb, srsp, highlightingResponseField, false);
+ if (hl == null) {
+ continue;
+ }
addHighlights(objArr, hl, rb.resultIds);
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
index 3624423c003..12c3d3f2812 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/QueryComponent.java
@@ -32,6 +32,7 @@ import java.util.LinkedHashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
+import java.util.Objects;
import org.apache.lucene.index.ExitableDirectoryReader;
import org.apache.lucene.index.IndexReaderContext;
import org.apache.lucene.index.LeafReaderContext;
@@ -114,6 +115,7 @@ import org.apache.solr.search.grouping.endresulttransformer.MainEndResultTransfo
import org.apache.solr.search.grouping.endresulttransformer.SimpleEndResultTransformer;
import org.apache.solr.search.stats.StatsCache;
import org.apache.solr.util.SolrPluginUtils;
+import org.apache.solr.util.SolrResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -914,13 +916,23 @@ public class QueryComponent extends SearchComponent {
}
} else {
responseHeader =
- (NamedList<?>) srsp.getSolrResponse().getResponse().get("responseHeader");
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ rb, srsp, "responseHeader", false);
+ if (responseHeader == null) {
+ continue;
+ }
final Object rhste =
responseHeader.get(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY);
if (rhste != null) {
nl.add(SolrQueryResponse.RESPONSE_HEADER_SEGMENT_TERMINATED_EARLY_KEY, rhste);
}
- docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
+ docs =
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "response", false);
+ if (docs == null) {
+ continue;
+ }
nl.add("numFound", docs.getNumFound());
nl.add("numFoundExact", docs.getNumFoundExact());
nl.add("maxScore", docs.getMaxScore());
@@ -939,11 +951,18 @@ public class QueryComponent extends SearchComponent {
}
if (docs == null) { // could have been initialized in the shards info block above
- docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
+ docs =
+ Objects.requireNonNull(
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "response", false));
}
if (responseHeader == null) { // could have been initialized in the shards info block above
- responseHeader = (NamedList<?>) srsp.getSolrResponse().getResponse().get("responseHeader");
+ responseHeader =
+ Objects.requireNonNull(
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ rb, srsp, "responseHeader", false));
}
final boolean thisResponseIsPartial;
@@ -974,7 +993,8 @@ public class QueryComponent extends SearchComponent {
@SuppressWarnings("unchecked")
NamedList<List<Object>> sortFieldValues =
- (NamedList<List<Object>>) (srsp.getSolrResponse().getResponse().get("sort_values"));
+ (NamedList<List<Object>>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "sort_values", true);
if (null == sortFieldValues) {
sortFieldValues = new NamedList<>();
}
@@ -1287,7 +1307,10 @@ public class QueryComponent extends SearchComponent {
}
{
NamedList<?> responseHeader =
- (NamedList<?>) srsp.getSolrResponse().getResponse().get("responseHeader");
+ Objects.requireNonNull(
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ rb, srsp, "responseHeader", false));
if (Boolean.TRUE.equals(
responseHeader.getBooleanArg(
SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY))) {
@@ -1298,7 +1321,9 @@ public class QueryComponent extends SearchComponent {
}
}
SolrDocumentList docs =
- (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
+ Objects.requireNonNull(
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "response", false));
for (SolrDocument doc : docs) {
Object id = doc.getFieldValue(keyFieldName);
ShardDoc sdoc = rb.resultIds.get(id.toString());
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
index d7eb2676803..03311aebaa2 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SpellCheckComponent.java
@@ -71,6 +71,7 @@ import org.apache.solr.spelling.SpellingOptions;
import org.apache.solr.spelling.SpellingQueryConverter;
import org.apache.solr.spelling.SpellingResult;
import org.apache.solr.spelling.Token;
+import org.apache.solr.util.SolrResponseUtil;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -263,10 +264,7 @@ public class SpellCheckComponent extends SearchComponent implements SolrCoreAwar
}
}
}
- } catch (IOException e) {
- log.error("Error", e);
- return null;
- } catch (SyntaxError e) {
+ } catch (IOException | SyntaxError e) {
log.error("Error", e);
return null;
}
@@ -407,18 +405,9 @@ public class SpellCheckComponent extends SearchComponent implements SolrCoreAwar
if (maxResultsForSuggest == null || !isCorrectlySpelled) {
for (ShardRequest sreq : rb.finished) {
for (ShardResponse srsp : sreq.responses) {
- NamedList<?> nl = null;
- try {
- nl = (NamedList<?>) srsp.getSolrResponse().getResponse().get("spellcheck");
- } catch (Exception e) {
- if (ShardParams.getShardsTolerantAsBool(rb.req.getParams())) {
- continue; // looks like a shard did not return anything
- }
- throw new SolrException(
- SolrException.ErrorCode.SERVER_ERROR,
- "Unable to read spelling info for shard: " + srsp.getShard(),
- e);
- }
+ NamedList<?> nl =
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "spellcheck", true);
if (log.isDebugEnabled()) {
log.debug("{} {}", srsp.getShard(), nl);
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java b/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java
index 920c19d6533..1ef317d30c5 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/StatsComponent.java
@@ -20,11 +20,11 @@ import java.io.IOException;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.solr.common.SolrException;
-import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.params.StatsParams;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.search.DocSet;
+import org.apache.solr.util.SolrResponseUtil;
/**
* Stats component calculates simple statistics on numeric field values
@@ -86,25 +86,19 @@ public class StatsComponent extends SearchComponent {
}
@Override
- @SuppressWarnings("unchecked")
public void handleResponses(ResponseBuilder rb, ShardRequest sreq) {
if (!rb.doStats || (sreq.purpose & ShardRequest.PURPOSE_GET_STATS) == 0) return;
Map<String, StatsValues> allStatsValues = rb._statsInfo.getAggregateStatsValues();
for (ShardResponse srsp : sreq.responses) {
- NamedList<NamedList<NamedList<?>>> stats = null;
- try {
- stats =
- (NamedList<NamedList<NamedList<?>>>) srsp.getSolrResponse().getResponse().get("stats");
- } catch (Exception e) {
- if (ShardParams.getShardsTolerantAsBool(rb.req.getParams())) {
- continue; // looks like a shard did not return anything
- }
- throw new SolrException(
- SolrException.ErrorCode.SERVER_ERROR,
- "Unable to read stats info for shard: " + srsp.getShard(),
- e);
+ @SuppressWarnings("unchecked")
+ NamedList<NamedList<NamedList<?>>> stats =
+ (NamedList<NamedList<NamedList<?>>>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "stats", false);
+ ;
+ if (stats == null) {
+ continue;
}
NamedList<NamedList<?>> stats_fields = unwrapStats(stats);
diff --git a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
index 58c4530e204..608d15bdc17 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/SuggestComponent.java
@@ -56,6 +56,7 @@ import org.apache.solr.spelling.suggest.SolrSuggester;
import org.apache.solr.spelling.suggest.SuggesterOptions;
import org.apache.solr.spelling.suggest.SuggesterParams;
import org.apache.solr.spelling.suggest.SuggesterResult;
+import org.apache.solr.util.SolrResponseUtil;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -294,17 +295,18 @@ public class SuggestComponent extends SearchComponent
// Collect Shard responses
for (ShardRequest sreq : rb.finished) {
for (ShardResponse srsp : sreq.responses) {
- NamedList<Object> resp;
- if ((resp = srsp.getSolrResponse().getResponse()) != null) {
- @SuppressWarnings("unchecked")
- SimpleOrderedMap<SimpleOrderedMap<NamedList<Object>>> namedList =
- (SimpleOrderedMap<SimpleOrderedMap<NamedList<Object>>>)
- resp.get(SuggesterResultLabels.SUGGEST);
- if (log.isInfoEnabled()) {
- log.info("{} : {}", srsp.getShard(), namedList);
- }
- suggesterResults.add(toSuggesterResult(namedList));
+ @SuppressWarnings("unchecked")
+ SimpleOrderedMap<SimpleOrderedMap<NamedList<Object>>> namedList =
+ (SimpleOrderedMap<SimpleOrderedMap<NamedList<Object>>>)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ rb, srsp, SuggesterResultLabels.SUGGEST, false);
+ if (namedList == null) {
+ continue;
+ }
+ if (log.isInfoEnabled()) {
+ log.info("{} : {}", srsp.getShard(), namedList);
}
+ suggesterResults.add(toSuggesterResult(namedList));
}
}
diff --git a/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java b/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java
index 7f8b987bbcc..5ef1571d403 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/TermVectorComponent.java
@@ -52,6 +52,7 @@ import org.apache.solr.search.SolrDocumentFetcher;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.SolrReturnFields;
import org.apache.solr.util.SolrPluginUtils;
+import org.apache.solr.util.SolrResponseUtil;
/**
* Return term vectors for the documents in a query result set.
@@ -430,17 +431,19 @@ public class TermVectorComponent extends SearchComponent {
for (ShardResponse srsp : sreq.responses) {
@SuppressWarnings({"unchecked"})
NamedList<Object> nl =
- (NamedList<Object>) srsp.getSolrResponse().getResponse().get(TERM_VECTORS);
+ (NamedList<Object>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, TERM_VECTORS, false);
+ if (nl != null) {
+ // Add metadata (that which isn't a uniqueKey value):
+ Object warningsNL = nl.get(TV_KEY_WARNINGS);
+ // assume if that if warnings is already present; we don't need to merge.
+ if (warningsNL != null && termVectorsNL.indexOf(TV_KEY_WARNINGS, 0) < 0) {
+ termVectorsNL.add(TV_KEY_WARNINGS, warningsNL);
+ }
- // Add metadata (that which isn't a uniqueKey value):
- Object warningsNL = nl.get(TV_KEY_WARNINGS);
- // assume if that if warnings is already present; we don't need to merge.
- if (warningsNL != null && termVectorsNL.indexOf(TV_KEY_WARNINGS, 0) < 0) {
- termVectorsNL.add(TV_KEY_WARNINGS, warningsNL);
+ // UniqueKey data
+ SolrPluginUtils.copyNamedListIntoArrayByDocPosInResponse(nl, rb.resultIds, arr);
}
-
- // UniqueKey data
- SolrPluginUtils.copyNamedListIntoArrayByDocPosInResponse(nl, rb.resultIds, arr);
}
}
// remove nulls in case not all docs were able to be retrieved
diff --git a/solr/core/src/java/org/apache/solr/handler/component/TermsComponent.java b/solr/core/src/java/org/apache/solr/handler/component/TermsComponent.java
index 68718bf4714..7d45a885855 100644
--- a/solr/core/src/java/org/apache/solr/handler/component/TermsComponent.java
+++ b/solr/core/src/java/org/apache/solr/handler/component/TermsComponent.java
@@ -53,6 +53,7 @@ import org.apache.solr.schema.StrField;
import org.apache.solr.search.PointMerger;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.util.BoundedTreeSet;
+import org.apache.solr.util.SolrResponseUtil;
/**
* Return TermEnum information, useful for things like auto suggest.
@@ -383,12 +384,14 @@ public class TermsComponent extends SearchComponent {
for (ShardResponse srsp : sreq.responses) {
@SuppressWarnings("unchecked")
NamedList<NamedList<Object>> terms =
- (NamedList<NamedList<Object>>) srsp.getSolrResponse().getResponse().get("terms");
+ (NamedList<NamedList<Object>>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "terms", false);
th.parse(terms);
@SuppressWarnings({"unchecked"})
NamedList<Number> stats =
- (NamedList<Number>) srsp.getSolrResponse().getResponse().get("indexstats");
+ (NamedList<Number>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "indexstats", true);
if (stats != null) {
th.numDocs += stats.get("numDocs").longValue();
th.stats = true;
diff --git a/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java b/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java
index be351dd5770..a748f917977 100644
--- a/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java
+++ b/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/SearchGroupShardResponseProcessor.java
@@ -28,6 +28,7 @@ import java.util.Set;
import org.apache.lucene.search.Sort;
import org.apache.lucene.search.grouping.SearchGroup;
import org.apache.lucene.util.BytesRef;
+import org.apache.solr.client.solrj.SolrResponse;
import org.apache.solr.client.solrj.SolrServerException;
import org.apache.solr.common.params.ShardParams;
import org.apache.solr.common.util.NamedList;
@@ -40,12 +41,12 @@ import org.apache.solr.search.SortSpec;
import org.apache.solr.search.grouping.distributed.ShardResponseProcessor;
import org.apache.solr.search.grouping.distributed.command.SearchGroupsFieldCommandResult;
import org.apache.solr.search.grouping.distributed.shardresultserializer.SearchGroupsResultTransformer;
+import org.apache.solr.util.SolrResponseUtil;
/** Concrete implementation for merging {@link SearchGroup} instances from shard responses. */
public class SearchGroupShardResponseProcessor implements ShardResponseProcessor {
@Override
- @SuppressWarnings("unchecked")
public void process(ResponseBuilder rb, ShardRequest shardRequest) {
SortSpec groupSortSpec = rb.getGroupingSpec().getGroupSortSpec();
Sort groupSort = rb.getGroupingSpec().getGroupSortSpec().getSort();
@@ -58,17 +59,16 @@ public class SearchGroupShardResponseProcessor implements ShardResponseProcessor
final Map<String, Map<SearchGroup<BytesRef>, Set<String>>> tempSearchGroupToShards =
new HashMap<>(fields.length, 1.0f);
for (String field : fields) {
- commandSearchGroups.put(
- field, new ArrayList<Collection<SearchGroup<BytesRef>>>(shardRequest.responses.size()));
- tempSearchGroupToShards.put(field, new HashMap<SearchGroup<BytesRef>, Set<String>>());
+ commandSearchGroups.put(field, new ArrayList<>(shardRequest.responses.size()));
+ tempSearchGroupToShards.put(field, new HashMap<>());
if (!rb.searchGroupToShards.containsKey(field)) {
- rb.searchGroupToShards.put(field, new HashMap<SearchGroup<BytesRef>, Set<String>>());
+ rb.searchGroupToShards.put(field, new HashMap<>());
}
}
SearchGroupsResultTransformer serializer =
new SearchGroupsResultTransformer(rb.req.getSearcher());
- int maxElapsedTime = 0;
+ long maxElapsedTime = 0;
int hitCountDuringFirstPhase = 0;
NamedList<Object> shardInfo = null;
@@ -78,24 +78,26 @@ public class SearchGroupShardResponseProcessor implements ShardResponseProcessor
}
for (ShardResponse srsp : shardRequest.responses) {
+ SolrResponse solrResponse = srsp.getSolrResponse();
+ NamedList<?> response = solrResponse.getResponse();
if (shardInfo != null) {
SimpleOrderedMap<Object> nl = new SimpleOrderedMap<>(4);
if (srsp.getException() != null) {
Throwable t = srsp.getException();
if (t instanceof SolrServerException) {
- t = ((SolrServerException) t).getCause();
+ t = t.getCause();
}
nl.add("error", t.toString());
StringWriter trace = new StringWriter();
t.printStackTrace(new PrintWriter(trace));
nl.add("trace", trace.toString());
} else {
- nl.add("numFound", (Integer) srsp.getSolrResponse().getResponse().get("totalHitCount"));
- }
- if (srsp.getSolrResponse() != null) {
- nl.add("time", srsp.getSolrResponse().getElapsedTime());
+ nl.add("numFound", response.get("totalHitCount"));
}
+
+ nl.add("time", solrResponse.getElapsedTime());
+
if (srsp.getShardAddress() != null) {
nl.add("shardAddress", srsp.getShardAddress());
}
@@ -108,9 +110,14 @@ public class SearchGroupShardResponseProcessor implements ShardResponseProcessor
.put(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY, Boolean.TRUE);
continue; // continue if there was an error and we're tolerant.
}
- maxElapsedTime = (int) Math.max(maxElapsedTime, srsp.getSolrResponse().getElapsedTime());
+ maxElapsedTime = Math.max(maxElapsedTime, solrResponse.getElapsedTime());
+ @SuppressWarnings("unchecked")
NamedList<NamedList<?>> firstPhaseResult =
- (NamedList<NamedList<?>>) srsp.getSolrResponse().getResponse().get("firstPhase");
+ (NamedList<NamedList<?>>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "firstPhase", false);
+ if (firstPhaseResult == null) {
+ continue; // looks like a shard did not return anything
+ }
final Map<String, SearchGroupsFieldCommandResult> result =
serializer.transformToNative(
firstPhaseResult, groupSort, withinGroupSort, srsp.getShard());
@@ -139,19 +146,14 @@ public class SearchGroupShardResponseProcessor implements ShardResponseProcessor
entry.getValue().add(searchGroups);
for (SearchGroup<BytesRef> searchGroup : searchGroups) {
Map<SearchGroup<BytesRef>, Set<String>> map = tempSearchGroupToShards.get(field);
- Set<String> shards = map.get(searchGroup);
- if (shards == null) {
- shards = new HashSet<>();
- map.put(searchGroup, shards);
- }
+ Set<String> shards = map.computeIfAbsent(searchGroup, k -> new HashSet<>());
shards.add(srsp.getShard());
}
}
- hitCountDuringFirstPhase +=
- (Integer) srsp.getSolrResponse().getResponse().get("totalHitCount");
+ hitCountDuringFirstPhase += (Integer) response.get("totalHitCount");
}
rb.totalHitCount = hitCountDuringFirstPhase;
- rb.firstPhaseElapsedTime = maxElapsedTime;
+ rb.firstPhaseElapsedTime = (int) maxElapsedTime;
for (Map.Entry<String, List<Collection<SearchGroup<BytesRef>>>> entry :
commandSearchGroups.entrySet()) {
String groupField = entry.getKey();
diff --git a/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java b/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java
index 243d9201c96..31cfb11ec39 100644
--- a/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java
+++ b/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/StoredFieldsShardResponseProcessor.java
@@ -16,7 +16,6 @@
*/
package org.apache.solr.search.grouping.distributed.responseprocessor;
-import org.apache.lucene.search.FieldDoc;
import org.apache.solr.common.SolrDocument;
import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.handler.component.ResponseBuilder;
@@ -25,6 +24,7 @@ import org.apache.solr.handler.component.ShardRequest;
import org.apache.solr.handler.component.ShardResponse;
import org.apache.solr.search.SolrIndexSearcher;
import org.apache.solr.search.grouping.distributed.ShardResponseProcessor;
+import org.apache.solr.util.SolrResponseUtil;
/** Concrete implementation for processing the stored field values from shard responses. */
public class StoredFieldsShardResponseProcessor implements ShardResponseProcessor {
@@ -33,20 +33,25 @@ public class StoredFieldsShardResponseProcessor implements ShardResponseProcesso
public void process(ResponseBuilder rb, ShardRequest shardRequest) {
boolean returnScores = (rb.getFieldFlags() & SolrIndexSearcher.GET_SCORES) != 0;
ShardResponse srsp = shardRequest.responses.get(0);
- SolrDocumentList docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
String uniqueIdFieldName = rb.req.getSchema().getUniqueKeyField().getName();
if (rb.rsp.getReturnFields().getFieldRenames().get(uniqueIdFieldName) != null) {
// if id was renamed we need to use the new name
uniqueIdFieldName = rb.rsp.getReturnFields().getFieldRenames().get(uniqueIdFieldName);
}
+
+ SolrDocumentList docs =
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "response", false);
+ if (docs == null) {
+ return;
+ }
for (SolrDocument doc : docs) {
Object id = doc.getFieldValue(uniqueIdFieldName).toString();
ShardDoc shardDoc = rb.resultIds.get(id);
- FieldDoc fieldDoc = (FieldDoc) shardDoc;
if (shardDoc != null) {
- if (returnScores && !Float.isNaN(fieldDoc.score)) {
- doc.setField("score", fieldDoc.score);
+ if (returnScores && !Float.isNaN(shardDoc.score)) {
+ doc.setField("score", shardDoc.score);
}
rb.retrievedDocuments.put(id, doc);
}
diff --git a/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java b/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java
index 665ca95236f..39060f60782 100644
--- a/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java
+++ b/solr/core/src/java/org/apache/solr/search/grouping/distributed/responseprocessor/TopGroupsShardResponseProcessor.java
@@ -44,6 +44,7 @@ import org.apache.solr.search.SortSpec;
import org.apache.solr.search.grouping.distributed.ShardResponseProcessor;
import org.apache.solr.search.grouping.distributed.command.QueryCommandResult;
import org.apache.solr.search.grouping.distributed.shardresultserializer.TopGroupsResultTransformer;
+import org.apache.solr.util.SolrResponseUtil;
/** Concrete implementation for merging {@link TopGroups} instances from shard responses. */
public class TopGroupsShardResponseProcessor implements ShardResponseProcessor {
@@ -122,8 +123,11 @@ public class TopGroupsShardResponseProcessor implements ShardResponseProcessor {
continue; // continue if there was an error and we're tolerant.
}
NamedList<NamedList<?>> secondPhaseResult =
- (NamedList<NamedList<?>>) srsp.getSolrResponse().getResponse().get("secondPhase");
- if (secondPhaseResult == null) continue;
+ (NamedList<NamedList<?>>)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "secondPhase", false);
+ if (secondPhaseResult == null) {
+ continue;
+ }
Map<String, ?> result =
serializer.transformToNative(
secondPhaseResult, groupSort, withinGroupSort, srsp.getShard());
diff --git a/solr/core/src/java/org/apache/solr/util/SolrResponseUtil.java b/solr/core/src/java/org/apache/solr/util/SolrResponseUtil.java
new file mode 100644
index 00000000000..eb12dc9d779
--- /dev/null
+++ b/solr/core/src/java/org/apache/solr/util/SolrResponseUtil.java
@@ -0,0 +1,77 @@
+/*
+ * 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.solr.util;
+
+import java.lang.invoke.MethodHandles;
+import java.util.Objects;
+import org.apache.solr.client.solrj.SolrResponse;
+import org.apache.solr.common.SolrException;
+import org.apache.solr.common.params.ShardParams;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.handler.component.ResponseBuilder;
+import org.apache.solr.handler.component.ShardResponse;
+import org.apache.solr.response.SolrQueryResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+public class SolrResponseUtil {
+ private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
+
+ private SolrResponseUtil() {}
+
+ public static Object getSubsectionFromShardResponse(
+ ResponseBuilder rb, ShardResponse srsp, String shardResponseKey, boolean subSectionOptional) {
+ Object shardResponseSubsection;
+ try {
+ SolrResponse solrResponse = srsp.getSolrResponse();
+ NamedList<Object> response = solrResponse.getResponse();
+ shardResponseSubsection = response.get(shardResponseKey);
+ if (shardResponseSubsection != null) {
+ return shardResponseSubsection;
+ } else {
+ NamedList<?> responseHeader =
+ Objects.requireNonNull(
+ (NamedList<?>) response.get(SolrQueryResponse.RESPONSE_HEADER_KEY));
+ if (subSectionOptional
+ || Boolean.TRUE.equals(
+ responseHeader.getBooleanArg(
+ SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY))) {
+ return null;
+ } else {
+ log.warn("corrupted response on {} : {}", srsp.getShardRequest(), solrResponse);
+ throw new SolrException(
+ SolrException.ErrorCode.SERVER_ERROR,
+ shardResponseKey
+ + " is absent in response from "
+ + srsp.getNodeName()
+ + ", but "
+ + SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY
+ + " isn't set in the response.");
+ }
+ }
+ } catch (Exception ex) {
+ if (rb != null && ShardParams.getShardsTolerantAsBool(rb.req.getParams())) {
+ return null;
+ } else {
+ throw new SolrException(
+ SolrException.ErrorCode.SERVER_ERROR,
+ "Unable to read " + shardResponseKey + " info for shard: " + srsp.getShard(),
+ ex);
+ }
+ }
+ }
+}
diff --git a/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java b/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java
index fb37c243b95..6ea1e0d899c 100644
--- a/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java
+++ b/solr/core/src/test/org/apache/solr/search/RankQueryTestPlugin.java
@@ -25,6 +25,7 @@ import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.Objects;
import org.apache.lucene.index.DocValues;
import org.apache.lucene.index.IndexReaderContext;
import org.apache.lucene.index.LeafReaderContext;
@@ -64,6 +65,7 @@ import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.schema.FieldType;
import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
+import org.apache.solr.util.SolrResponseUtil;
public class RankQueryTestPlugin extends QParserPlugin {
@@ -158,7 +160,6 @@ public class RankQueryTestPlugin extends QParserPlugin {
public void handleMergeFields(ResponseBuilder rb, SolrIndexSearcher searcher) {}
- @SuppressWarnings({"unchecked"})
public void merge(ResponseBuilder rb, ShardRequest sreq) {
// id to shard mapping, to eliminate any accidental dups
@@ -197,7 +198,11 @@ public class RankQueryTestPlugin extends QParserPlugin {
nl.add("shardAddress", srsp.getShardAddress());
}
} else {
- docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
+ docs =
+ Objects.requireNonNull(
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ null, srsp, "response", false));
nl.add("numFound", docs.getNumFound());
nl.add("maxScore", docs.getMaxScore());
nl.add("shardAddress", srsp.getShardAddress());
@@ -215,11 +220,17 @@ public class RankQueryTestPlugin extends QParserPlugin {
}
if (docs == null) { // could have been initialized in the 'shardInfo' block above
- docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
+ docs =
+ Objects.requireNonNull(
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ null, srsp, "response", false));
}
NamedList<?> responseHeader =
- (NamedList<?>) srsp.getSolrResponse().getResponse().get("responseHeader");
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ null, srsp, "responseHeader", false);
if (responseHeader != null
&& Boolean.TRUE.equals(
responseHeader.get(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY))) {
@@ -499,7 +510,11 @@ public class RankQueryTestPlugin extends QParserPlugin {
nl.add("shardAddress", srsp.getShardAddress());
}
} else {
- docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
+ docs =
+ Objects.requireNonNull(
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ null, srsp, "response", false));
nl.add("numFound", docs.getNumFound());
nl.add("maxScore", docs.getMaxScore());
nl.add("shardAddress", srsp.getShardAddress());
@@ -517,11 +532,17 @@ public class RankQueryTestPlugin extends QParserPlugin {
}
if (docs == null) { // could have been initialized in the 'shardInfo' block above
- docs = (SolrDocumentList) srsp.getSolrResponse().getResponse().get("response");
+ docs =
+ Objects.requireNonNull(
+ (SolrDocumentList)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ null, srsp, "response", false));
}
NamedList<?> responseHeader =
- (NamedList<?>) srsp.getSolrResponse().getResponse().get("responseHeader");
+ (NamedList<?>)
+ SolrResponseUtil.getSubsectionFromShardResponse(
+ null, srsp, "responseHeader", false);
if (responseHeader != null
&& Boolean.TRUE.equals(
responseHeader.get(SolrQueryResponse.RESPONSE_HEADER_PARTIAL_RESULTS_KEY))) {
@@ -538,7 +559,11 @@ public class RankQueryTestPlugin extends QParserPlugin {
@SuppressWarnings({"rawtypes"})
NamedList sortFieldValues =
- (NamedList) (srsp.getSolrResponse().getResponse().get("merge_values"));
+ (NamedList)
+ SolrResponseUtil.getSubsectionFromShardResponse(rb, srsp, "merge_values", false);
+ if (sortFieldValues == null) {
+ continue;
+ }
@SuppressWarnings({"rawtypes"})
NamedList unmarshalledSortFieldValues = unmarshalSortValues(ss, sortFieldValues);
@SuppressWarnings({"rawtypes"})