Skip to content

Commit 930e6c1

Browse files
committed
SOLR-17951: Optimize re-ranking based on "functions"
1 parent a484172 commit 930e6c1

6 files changed

Lines changed: 190 additions & 44 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
title: Optimize re-ranking based on "functions"
2+
type: added
3+
authors:
4+
- name: hossman
5+
links:
6+
- name: SOLR-17951
7+
url: https://issues.apache.org/jira/browse/SOLR-17951

solr/core/src/java/org/apache/solr/search/AbstractReRankQuery.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
*/
1717
package org.apache.solr.search;
1818

19+
import com.google.common.annotations.VisibleForTesting;
1920
import java.io.IOException;
2021
import java.util.Map;
2122
import java.util.Set;
@@ -59,6 +60,26 @@ public AbstractReRankQuery(Query mainQuery, int reRankDocs, Rescorer reRankQuery
5960
this.reRankQueryRescorer = reRankQueryRescorer;
6061
}
6162

63+
@VisibleForTesting
64+
int getReRankDocs() {
65+
return reRankDocs;
66+
}
67+
68+
@VisibleForTesting
69+
Rescorer getRescorer() {
70+
return reRankQueryRescorer;
71+
}
72+
73+
@VisibleForTesting
74+
ReRankOperator getReRankOperator() {
75+
return reRankOperator;
76+
}
77+
78+
@VisibleForTesting
79+
ReRankScaler getReRankScaler() {
80+
return reRankScaler;
81+
}
82+
6283
@Override
6384
public RankQuery wrap(Query _mainQuery) {
6485
if (_mainQuery != null) {

solr/core/src/java/org/apache/solr/search/ReRankOperator.java

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,12 +17,24 @@
1717
package org.apache.solr.search;
1818

1919
import java.util.Locale;
20+
import java.util.function.DoubleBinaryOperator;
2021
import org.apache.solr.common.SolrException;
2122

22-
public enum ReRankOperator {
23-
ADD,
24-
MULTIPLY,
25-
REPLACE;
23+
public enum ReRankOperator implements DoubleBinaryOperator {
24+
ADD((firstPass, secondPass) -> firstPass + secondPass),
25+
MULTIPLY((firstPass, secondPass) -> firstPass * secondPass),
26+
REPLACE((firstPass, secondPass) -> secondPass);
27+
28+
private final DoubleBinaryOperator op;
29+
30+
private ReRankOperator(final DoubleBinaryOperator op) {
31+
this.op = op;
32+
}
33+
34+
@Override
35+
public double applyAsDouble(final double firstPass, final double secondPass) {
36+
return op.applyAsDouble(firstPass, secondPass);
37+
}
2638

2739
public static ReRankOperator get(String p) {
2840
if (p != null) {

solr/core/src/java/org/apache/solr/search/ReRankQParserPlugin.java

Lines changed: 52 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,15 @@
1818

1919
import java.io.IOException;
2020
import java.lang.invoke.MethodHandles;
21+
import java.util.function.DoubleBinaryOperator;
22+
import org.apache.lucene.queries.function.FunctionQuery;
23+
import org.apache.lucene.queries.function.FunctionScoreQuery;
24+
import org.apache.lucene.search.DoubleValuesSource;
25+
import org.apache.lucene.search.DoubleValuesSourceRescorer;
2126
import org.apache.lucene.search.MatchAllDocsQuery;
2227
import org.apache.lucene.search.Query;
2328
import org.apache.lucene.search.QueryRescorer;
29+
import org.apache.lucene.search.Rescorer;
2430
import org.apache.solr.common.SolrException;
2531
import org.apache.solr.common.params.CommonParams;
2632
import org.apache.solr.common.params.SolrParams;
@@ -63,6 +69,26 @@ public QParser createParser(
6369
return new ReRankQParser(query, localParams, params, req);
6470
}
6571

72+
/**
73+
* Helper method for constructing a {@link Rescorer} from a {@link #RERANK_QUERY}, {@link
74+
* #RERANK_WEIGHT}, and {@link #RERANK_OPERATOR}.
75+
*
76+
* <p>By default, this returns a customized {@link QueryRescorer}, unless the {@link
77+
* #RERANK_QUERY} is a known type that can more efficiently be re-ranked using a customized {@link
78+
* DoubleValuesSourceRescorer}.
79+
*/
80+
private static Rescorer createRescorer(
81+
final Query reRankQuery, final double reRankWeight, final ReRankOperator reRankOperator) {
82+
assert null != reRankQuery;
83+
return switch (reRankQuery) {
84+
case FunctionQuery functionQuery -> new ReRankDoubleValuesSourceRescorer(
85+
functionQuery.getValueSource().asDoubleValuesSource(), reRankWeight, reRankOperator);
86+
case FunctionScoreQuery functionQuery -> new ReRankDoubleValuesSourceRescorer(
87+
functionQuery.getSource(), reRankWeight, reRankOperator);
88+
default -> new ReRankQueryRescorer(reRankQuery, reRankWeight, reRankOperator);
89+
};
90+
}
91+
6692
private static class ReRankQParser extends QParser {
6793

6894
private boolean isExplainResults() {
@@ -135,7 +161,7 @@ public Query parse() throws SyntaxError {
135161
reRankScale,
136162
reRankScaleWeight,
137163
reRankOperator,
138-
new ReRankQueryRescorer(reRankQuery, 1, ReRankOperator.REPLACE),
164+
createRescorer(reRankQuery, 1, ReRankOperator.REPLACE),
139165
explainResults);
140166

141167
if (reRankScaler.scaleScores()) {
@@ -148,6 +174,28 @@ public Query parse() throws SyntaxError {
148174
}
149175
}
150176

177+
private static final class ReRankDoubleValuesSourceRescorer extends DoubleValuesSourceRescorer {
178+
final DoubleBinaryOperator scoreCombiner;
179+
180+
public ReRankDoubleValuesSourceRescorer(
181+
final DoubleValuesSource valuesSource,
182+
final double reRankWeight,
183+
final ReRankOperator reRankOperator) {
184+
super(valuesSource);
185+
this.scoreCombiner =
186+
(score, value) -> reRankOperator.applyAsDouble(score, reRankWeight * value);
187+
}
188+
189+
@Override
190+
protected float combine(
191+
final float firstPassScore, final boolean valuePresent, final double sourceValue) {
192+
if (valuePresent) {
193+
return (float) scoreCombiner.applyAsDouble(firstPassScore, sourceValue);
194+
}
195+
return firstPassScore;
196+
}
197+
}
198+
151199
private static final class ReRankQueryRescorer extends QueryRescorer {
152200

153201
final BiFloatFunction scoreCombiner;
@@ -160,20 +208,8 @@ interface BiFloatFunction {
160208
public ReRankQueryRescorer(
161209
Query reRankQuery, double reRankWeight, ReRankOperator reRankOperator) {
162210
super(reRankQuery);
163-
switch (reRankOperator) {
164-
case ADD:
165-
scoreCombiner = (score, second) -> (float) (score + reRankWeight * second);
166-
break;
167-
case MULTIPLY:
168-
scoreCombiner = (score, second) -> (float) (score * reRankWeight * second);
169-
break;
170-
case REPLACE:
171-
scoreCombiner = (score, second) -> (float) (reRankWeight * second);
172-
break;
173-
default:
174-
scoreCombiner = null;
175-
throw new IllegalArgumentException("Unexpected: reRankOperator=" + reRankOperator);
176-
}
211+
scoreCombiner =
212+
(score, second) -> (float) reRankOperator.applyAsDouble(score, reRankWeight * second);
177213
}
178214

179215
@Override
@@ -226,7 +262,7 @@ public ReRankQuery(
226262
super(
227263
defaultQuery,
228264
reRankDocs,
229-
new ReRankQueryRescorer(reRankQuery, reRankWeight, reRankOperator),
265+
createRescorer(reRankQuery, reRankWeight, reRankOperator),
230266
reRankScaler,
231267
reRankOperator);
232268
this.reRankQuery = reRankQuery;

solr/core/src/java/org/apache/solr/search/ReRankScaler.java

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
import java.util.Map;
2424
import java.util.Set;
2525
import org.apache.lucene.search.Explanation;
26-
import org.apache.lucene.search.QueryRescorer;
26+
import org.apache.lucene.search.Rescorer;
2727
import org.apache.lucene.search.ScoreDoc;
2828

2929
public class ReRankScaler {
@@ -35,7 +35,7 @@ public class ReRankScaler {
3535
protected boolean explainResults;
3636
protected ReRankOperator reRankOperator;
3737
protected ReRankScalerExplain reRankScalerExplain;
38-
private QueryRescorer replaceRescorer;
38+
private Rescorer replaceRescorer;
3939
private Set<Integer> reRankSet;
4040
private double reRankScaleWeight;
4141

@@ -44,7 +44,7 @@ public ReRankScaler(
4444
String reRankScale,
4545
double reRankScaleWeight,
4646
ReRankOperator reRankOperator,
47-
QueryRescorer replaceRescorer,
47+
Rescorer replaceRescorer,
4848
boolean explainResults)
4949
throws SyntaxError {
5050

@@ -99,7 +99,7 @@ public boolean equals(Object o) {
9999
}
100100
}
101101

102-
public QueryRescorer getReplaceRescorer() {
102+
public Rescorer getReplaceRescorer() {
103103
return replaceRescorer;
104104
}
105105

@@ -237,16 +237,7 @@ public static float combineScores(
237237
float reRankScore,
238238
double reRankScaleWeight,
239239
ReRankOperator reRankOperator) {
240-
switch (reRankOperator) {
241-
case ADD:
242-
return (float) (orginalScore + reRankScaleWeight * reRankScore);
243-
case REPLACE:
244-
return (float) (reRankScaleWeight * reRankScore);
245-
case MULTIPLY:
246-
return (float) (orginalScore * reRankScaleWeight * reRankScore);
247-
default:
248-
return -1;
249-
}
240+
return (float) reRankOperator.applyAsDouble(orginalScore, reRankScaleWeight * reRankScore);
250241
}
251242

252243
public static final class ReRankScalerExplain {

0 commit comments

Comments
 (0)