diff --git a/changelog/unreleased/SOLR-18181-ValueSourceAugmenter-npe.yml b/changelog/unreleased/SOLR-18181-ValueSourceAugmenter-npe.yml new file mode 100644 index 000000000000..83a8be7c2506 --- /dev/null +++ b/changelog/unreleased/SOLR-18181-ValueSourceAugmenter-npe.yml @@ -0,0 +1,7 @@ +title: Fix NPE in ValueSourceAugmenter when rows exceed prefetch limit with scores requested +type: fixed +authors: + - name: Matthew Biscocho +links: + - name: SOLR-18181 + url: https://issues.apache.org/jira/browse/SOLR-18181 diff --git a/solr/core/src/java/org/apache/solr/response/transform/ValueSourceAugmenter.java b/solr/core/src/java/org/apache/solr/response/transform/ValueSourceAugmenter.java index 825c1b405a60..613246a588e2 100644 --- a/solr/core/src/java/org/apache/solr/response/transform/ValueSourceAugmenter.java +++ b/solr/core/src/java/org/apache/solr/response/transform/ValueSourceAugmenter.java @@ -30,6 +30,7 @@ import org.apache.solr.common.SolrDocument; import org.apache.solr.common.SolrException; import org.apache.solr.response.ResultContext; +import org.apache.solr.search.DocIterationInfo; import org.apache.solr.search.QParser; import org.apache.solr.search.SolrIndexSearcher; @@ -142,7 +143,7 @@ public float score() throws IOException { IntObjectHashMap cachedValuesById; @Override - public void transform(SolrDocument doc, int docid) { + public void transform(SolrDocument doc, int docid, DocIterationInfo docIterationInfo) { Object cacheValue = (cachedValuesById != null) ? cachedValuesById.get(docid) : null; if (cacheValue != null) { setValue(doc, cacheValue != NULL_SENTINEL ? cacheValue : null); @@ -153,8 +154,8 @@ public void transform(SolrDocument doc, int docid) { LeafReaderContext rcontext = readerContexts.get(idx); int localId = docid - rcontext.docBase; - if (context.wantsScores()) { - fcontext.put("scorer", new ScoreAndDoc(localId, (float) doc.get("score"))); + if (context.wantsScores() && docIterationInfo != null) { + fcontext.put("scorer", new ScoreAndDoc(localId, docIterationInfo.score())); } FunctionValues values = valueSource.getValues(fcontext, rcontext); @@ -168,6 +169,11 @@ public void transform(SolrDocument doc, int docid) { } } + @Override + public void transform(SolrDocument doc, int docid) { + transform(doc, docid, null); + } + private abstract static class MutableScorable extends Scorable { int docBase; diff --git a/solr/core/src/test/org/apache/solr/response/transform/TestValueSourceAugmenterPrefetchLimit.java b/solr/core/src/test/org/apache/solr/response/transform/TestValueSourceAugmenterPrefetchLimit.java new file mode 100644 index 000000000000..7da9bcb76cf4 --- /dev/null +++ b/solr/core/src/test/org/apache/solr/response/transform/TestValueSourceAugmenterPrefetchLimit.java @@ -0,0 +1,71 @@ +/* + * 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.response.transform; + +import org.apache.solr.SolrTestCaseJ4; +import org.junit.BeforeClass; + +public class TestValueSourceAugmenterPrefetchLimit extends SolrTestCaseJ4 { + + private static final int MAX_PREFETCH_SIZE = 1000; + + @BeforeClass + public static void beforeTests() throws Exception { + initCore("solrconfig.xml", "schema.xml"); + + // Index enough documents to exceed the prefetch limit + final int numDocs = MAX_PREFETCH_SIZE + 10; + for (int i = 0; i < numDocs; i++) { + assertU(adoc("id", Integer.toString(i))); + } + assertU(commit()); + } + + public void testWithScoreBelowPrefetchLimit() { + assertQ( + "fl=foo:field(id),score with rows within prefetch limit", + req( + "q", "*:*", + "fl", "foo:field(id),score", + "rows", String.valueOf(MAX_PREFETCH_SIZE)), + "//result[@numFound='" + (MAX_PREFETCH_SIZE + 10) + "']", + "//result/doc/float[@name='score']"); + } + + public void testWithScoreAbovePrefetchLimit() { + assertQ( + "fl=foo:field(id),score with rows exceeding prefetch limit", + req( + "q", "*:*", + "fl", "foo:field(id),score", + "rows", String.valueOf(MAX_PREFETCH_SIZE + 10)), + "//result[@numFound='" + (MAX_PREFETCH_SIZE + 10) + "']", + "//result/doc/float[@name='score']"); + } + + public void testWithScoreAbovePrefetchLimitUsingPreFetchDocsParam() { + assertQ( + "fl=foo:field(id),score with custom preFetchDocs", + req( + "q", "*:*", + "fl", "foo:field(id),score", + "rows", String.valueOf(MAX_PREFETCH_SIZE + 10), + "preFetchDocs", "2000"), // Set to 2000 + "//result[@numFound='" + (MAX_PREFETCH_SIZE + 10) + "']", + "//result/doc/float[@name='score']"); + } +}