From 9728f4ef201db0b8b7bce1e909efee83593dede7 Mon Sep 17 00:00:00 2001 From: Tomas Fernandez Lobbe Date: Wed, 10 Jun 2020 14:59:50 -0700 Subject: [PATCH] SOLR-14552: Add BMW support to ReRank queries (#1559) --- solr/CHANGES.txt | 2 + .../apache/solr/search/ReRankCollector.java | 9 +- .../solr/search/TestReRankQParserPlugin.java | 95 +++++++++++++++++++ 3 files changed, 101 insertions(+), 5 deletions(-) diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index ee44d1b4d3f..8182f82d214 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -163,6 +163,8 @@ Optimizations * SOLR-14472: Autoscaling "cores" preference now retrieves the core count more efficiently, and counts all cores. (David Smiley) +* SOLR-14552: Add BlockMax-WAND support to ReRank queries (Tomás Fernández Löbbe) + Bug Fixes --------------------- * SOLR-13264: IndexSizeTrigger aboveOp / belowOp properties not in valid properties. diff --git a/solr/core/src/java/org/apache/solr/search/ReRankCollector.java b/solr/core/src/java/org/apache/solr/search/ReRankCollector.java index 27b07ba7b46..427ac8f0517 100644 --- a/solr/core/src/java/org/apache/solr/search/ReRankCollector.java +++ b/solr/core/src/java/org/apache/solr/search/ReRankCollector.java @@ -45,8 +45,7 @@ import org.apache.solr.request.SolrRequestInfo; @SuppressWarnings({"rawtypes"}) public class ReRankCollector extends TopDocsCollector { - @SuppressWarnings({"rawtypes"}) - final private TopDocsCollector mainCollector; + final private TopDocsCollector mainCollector; final private IndexSearcher searcher; final private int reRankDocs; final private int length; @@ -71,11 +70,11 @@ public class ReRankCollector extends TopDocsCollector { Sort sort = cmd.getSort(); if(sort == null) { this.sort = null; - this.mainCollector = TopScoreDocCollector.create(Math.max(this.reRankDocs, length), Integer.MAX_VALUE); + this.mainCollector = TopScoreDocCollector.create(Math.max(this.reRankDocs, length), cmd.getMinExactCount()); } else { this.sort = sort = sort.rewrite(searcher); //scores are needed for Rescorer (regardless of whether sort needs it) - this.mainCollector = TopFieldCollector.create(sort, Math.max(this.reRankDocs, length), Integer.MAX_VALUE); + this.mainCollector = TopFieldCollector.create(sort, Math.max(this.reRankDocs, length), cmd.getMinExactCount()); } this.searcher = searcher; this.reRankQueryRescorer = reRankQueryRescorer; @@ -92,7 +91,7 @@ public class ReRankCollector extends TopDocsCollector { @Override public ScoreMode scoreMode() { - return sort == null || sort.needsScores() ? ScoreMode.COMPLETE : ScoreMode.COMPLETE_NO_SCORES; + return this.mainCollector.scoreMode(); } @SuppressWarnings({"unchecked"}) diff --git a/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java b/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java index b3e01f27843..96ccee2d41c 100644 --- a/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java +++ b/solr/core/src/test/org/apache/solr/search/TestReRankQParserPlugin.java @@ -17,9 +17,12 @@ package org.apache.solr.search; import java.util.Map; +import java.util.stream.Collectors; +import java.util.stream.IntStream; import org.apache.solr.SolrTestCaseJ4; import org.apache.solr.common.SolrException; +import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.ModifiableSolrParams; import org.apache.solr.metrics.MetricsMap; import org.apache.solr.metrics.SolrMetricManager; @@ -598,10 +601,12 @@ public class TestReRankQParserPlugin extends SolrTestCaseJ4 { params.add("start", "0"); params.add("rows", "2"); + ignoreException("reRankQuery parameter is mandatory"); SolrException se = expectThrows(SolrException.class, "A syntax error should be thrown when "+ReRankQParserPlugin.RERANK_QUERY+" parameter is not specified", () -> h.query(req(params)) ); assertTrue(se.code() == SolrException.ErrorCode.BAD_REQUEST.code); + unIgnoreException("reRankQuery parameter is mandatory"); } @@ -645,5 +650,95 @@ public class TestReRankQParserPlugin extends SolrTestCaseJ4 { ); } } + + @Test + public void testMinExactCount() throws Exception { + + assertU(delQ("*:*")); + assertU(commit()); + + int numDocs = 200; + + for (int i = 0 ; i < numDocs ; i ++) { + assertU(adoc( + "id", String.valueOf(i), + "id_p_i", String.valueOf(i), + "field_t", IntStream.range(0, numDocs).mapToObj(val -> Integer.toString(val)).collect(Collectors.joining(" ")))); + } + assertU(commit()); + + ModifiableSolrParams params = new ModifiableSolrParams(); + params.add("q", "field_t:0"); + params.add("start", "0"); + params.add("rows", "10"); + params.add("fl", "id"); + assertQ(req(params), + "*[count(//doc)=10]", + "//result[@numFound='" + numDocs + "']", + "//result[@numFoundExact='true']", + "//result/doc[1]/str[@name='id'][.='0']", + "//result/doc[2]/str[@name='id'][.='1']", + "//result/doc[3]/str[@name='id'][.='2']", + "//result/doc[4]/str[@name='id'][.='3']", + "//result/doc[5]/str[@name='id'][.='4']", + "//result/doc[6]/str[@name='id'][.='5']", + "//result/doc[7]/str[@name='id'][.='6']", + "//result/doc[8]/str[@name='id'][.='7']", + "//result/doc[9]/str[@name='id'][.='8']", + "//result/doc[10]/str[@name='id'][.='9']" + ); + + params.add("rq", "{!"+ReRankQParserPlugin.NAME+" "+ReRankQParserPlugin.RERANK_QUERY+"=$rrq "+ReRankQParserPlugin.RERANK_DOCS+"=20}"); + params.add("rrq", "id:10"); + assertQ(req(params), + "*[count(//doc)=10]", + "//result[@numFound='" + numDocs + "']", + "//result[@numFoundExact='true']", + "//result/doc[1]/str[@name='id'][.='10']", + "//result/doc[2]/str[@name='id'][.='0']", + "//result/doc[3]/str[@name='id'][.='1']", + "//result/doc[4]/str[@name='id'][.='2']", + "//result/doc[5]/str[@name='id'][.='3']", + "//result/doc[6]/str[@name='id'][.='4']", + "//result/doc[7]/str[@name='id'][.='5']", + "//result/doc[8]/str[@name='id'][.='6']", + "//result/doc[9]/str[@name='id'][.='7']", + "//result/doc[10]/str[@name='id'][.='8']" + ); + + params.add(CommonParams.MIN_EXACT_COUNT, "2"); + assertQ(req(params), + "*[count(//doc)=10]", + "//result[@numFound<='" + numDocs + "']", + "//result[@numFoundExact='false']", + "//result/doc[1]/str[@name='id'][.='10']", + "//result/doc[2]/str[@name='id'][.='0']", + "//result/doc[3]/str[@name='id'][.='1']", + "//result/doc[4]/str[@name='id'][.='2']", + "//result/doc[5]/str[@name='id'][.='3']", + "//result/doc[6]/str[@name='id'][.='4']", + "//result/doc[7]/str[@name='id'][.='5']", + "//result/doc[8]/str[@name='id'][.='6']", + "//result/doc[9]/str[@name='id'][.='7']", + "//result/doc[10]/str[@name='id'][.='8']" + ); + + params.add("sort", "score desc, id_p_i asc"); + assertQ(req(params), + "*[count(//doc)=10]", + "//result[@numFound<='" + numDocs + "']", + "//result[@numFoundExact='false']", + "//result/doc[1]/str[@name='id'][.='10']", + "//result/doc[2]/str[@name='id'][.='0']", + "//result/doc[3]/str[@name='id'][.='1']", + "//result/doc[4]/str[@name='id'][.='2']", + "//result/doc[5]/str[@name='id'][.='3']", + "//result/doc[6]/str[@name='id'][.='4']", + "//result/doc[7]/str[@name='id'][.='5']", + "//result/doc[8]/str[@name='id'][.='6']", + "//result/doc[9]/str[@name='id'][.='7']", + "//result/doc[10]/str[@name='id'][.='8']" + ); + } }