9
9
10
10
package org .elasticsearch .xpack .application .rules .retriever ;
11
11
12
+ import org .apache .lucene .search .ScoreDoc ;
12
13
import org .elasticsearch .common .ParsingException ;
13
14
import org .elasticsearch .features .NodeFeature ;
15
+ import org .elasticsearch .index .query .BoolQueryBuilder ;
14
16
import org .elasticsearch .index .query .QueryBuilder ;
15
17
import org .elasticsearch .license .LicenseUtils ;
18
+ import org .elasticsearch .search .builder .PointInTimeBuilder ;
16
19
import org .elasticsearch .search .builder .SearchSourceBuilder ;
20
+ import org .elasticsearch .search .fetch .StoredFieldsContext ;
21
+ import org .elasticsearch .search .rank .RankDoc ;
22
+ import org .elasticsearch .search .retriever .CompoundRetrieverBuilder ;
17
23
import org .elasticsearch .search .retriever .RetrieverBuilder ;
18
24
import org .elasticsearch .search .retriever .RetrieverParserContext ;
25
+ import org .elasticsearch .search .retriever .rankdoc .RankDocsQueryBuilder ;
19
26
import org .elasticsearch .xcontent .ConstructingObjectParser ;
20
27
import org .elasticsearch .xcontent .ParseField ;
21
28
import org .elasticsearch .xcontent .XContentBuilder ;
25
32
import org .elasticsearch .xpack .core .XPackPlugin ;
26
33
27
34
import java .io .IOException ;
35
+ import java .util .ArrayList ;
28
36
import java .util .List ;
29
37
import java .util .Map ;
30
38
import java .util .Objects ;
31
39
40
+ import static org .elasticsearch .search .rank .RankBuilder .DEFAULT_RANK_WINDOW_SIZE ;
32
41
import static org .elasticsearch .xcontent .ConstructingObjectParser .constructorArg ;
42
+ import static org .elasticsearch .xcontent .ConstructingObjectParser .optionalConstructorArg ;
33
43
34
44
/**
35
45
* A query rule retriever applies query rules defined in one or more rulesets to the underlying retriever.
36
46
*/
37
- public final class QueryRuleRetrieverBuilder extends RetrieverBuilder {
47
+ public final class QueryRuleRetrieverBuilder extends CompoundRetrieverBuilder < QueryRuleRetrieverBuilder > {
38
48
39
49
public static final String NAME = "rule" ;
40
50
public static final NodeFeature QUERY_RULE_RETRIEVERS_SUPPORTED = new NodeFeature ("query_rule_retriever_supported" );
41
51
42
52
public static final ParseField RULESET_IDS_FIELD = new ParseField ("ruleset_ids" );
43
53
public static final ParseField MATCH_CRITERIA_FIELD = new ParseField ("match_criteria" );
44
54
public static final ParseField RETRIEVER_FIELD = new ParseField ("retriever" );
55
+ public static final ParseField RANK_WINDOW_SIZE_FIELD = new ParseField ("rank_window_size" );
45
56
46
57
@ SuppressWarnings ("unchecked" )
47
58
public static final ConstructingObjectParser <QueryRuleRetrieverBuilder , RetrieverParserContext > PARSER = new ConstructingObjectParser <>(
@@ -50,14 +61,16 @@ public final class QueryRuleRetrieverBuilder extends RetrieverBuilder {
50
61
List <String > rulesetIds = (List <String >) args [0 ];
51
62
Map <String , Object > matchCriteria = (Map <String , Object >) args [1 ];
52
63
RetrieverBuilder retrieverBuilder = (RetrieverBuilder ) args [2 ];
53
- return new QueryRuleRetrieverBuilder (rulesetIds , matchCriteria , retrieverBuilder );
64
+ int rankWindowSize = args [3 ] == null ? DEFAULT_RANK_WINDOW_SIZE : (int ) args [3 ];
65
+ return new QueryRuleRetrieverBuilder (rulesetIds , matchCriteria , retrieverBuilder , rankWindowSize );
54
66
}
55
67
);
56
68
57
69
static {
58
70
PARSER .declareStringArray (constructorArg (), RULESET_IDS_FIELD );
59
71
PARSER .declareObject (constructorArg (), (p , c ) -> p .map (), MATCH_CRITERIA_FIELD );
60
72
PARSER .declareNamedObject (constructorArg (), (p , c , n ) -> p .namedObject (RetrieverBuilder .class , n , c ), RETRIEVER_FIELD );
73
+ PARSER .declareInt (optionalConstructorArg (), RANK_WINDOW_SIZE_FIELD );
61
74
RetrieverBuilder .declareBaseParserFields (NAME , PARSER );
62
75
}
63
76
@@ -77,36 +90,66 @@ public static QueryRuleRetrieverBuilder fromXContent(XContentParser parser, Retr
77
90
78
91
private final List <String > rulesetIds ;
79
92
private final Map <String , Object > matchCriteria ;
80
- private final RetrieverBuilder retrieverBuilder ;
81
93
82
- public QueryRuleRetrieverBuilder (List <String > rulesetIds , Map <String , Object > matchCriteria , RetrieverBuilder retrieverBuilder ) {
94
+ public QueryRuleRetrieverBuilder (
95
+ List <String > rulesetIds ,
96
+ Map <String , Object > matchCriteria ,
97
+ RetrieverBuilder retrieverBuilder ,
98
+ int rankWindowSize
99
+ ) {
100
+ super (List .of (new RetrieverSource (retrieverBuilder , null )), rankWindowSize );
83
101
this .rulesetIds = rulesetIds ;
84
102
this .matchCriteria = matchCriteria ;
85
- this .retrieverBuilder = retrieverBuilder ;
86
103
}
87
104
88
- @ Override
89
- public String getName () {
90
- return NAME ;
105
+ public QueryRuleRetrieverBuilder (
106
+ List <String > rulesetIds ,
107
+ Map <String , Object > matchCriteria ,
108
+ List <RetrieverSource > retrieverSource ,
109
+ int rankWindowSize ,
110
+ String retrieverName ,
111
+ List <QueryBuilder > preFilterQueryBuilders
112
+ ) {
113
+ super (retrieverSource , rankWindowSize );
114
+ this .rulesetIds = rulesetIds ;
115
+ this .matchCriteria = matchCriteria ;
116
+ this .retrieverName = retrieverName ;
117
+ this .preFilterQueryBuilders = new ArrayList <>(preFilterQueryBuilders );
91
118
}
92
119
93
120
@ Override
94
- public QueryBuilder topDocsQuery () {
95
- assert rankDocs != null : "{rankDocs} should have been materialized at this point" ;
96
-
97
- // TODO is this correct?
98
- return retrieverBuilder .topDocsQuery ();
121
+ public String getName () {
122
+ return NAME ;
99
123
}
100
124
101
125
@ Override
102
- public void extractToSearchSourceBuilder (SearchSourceBuilder searchSourceBuilder , boolean compoundUsed ) {
126
+ protected SearchSourceBuilder createSearchSourceBuilder (PointInTimeBuilder pit , RetrieverBuilder retrieverBuilder ) {
127
+ var sourceBuilder = new SearchSourceBuilder ().pointInTimeBuilder (pit )
128
+ .trackTotalHits (false )
129
+ .storedFields (new StoredFieldsContext (false ))
130
+ .size (rankWindowSize );
131
+ if (preFilterQueryBuilders .isEmpty () == false ) {
132
+ retrieverBuilder .getPreFilterQueryBuilders ().addAll (preFilterQueryBuilders );
133
+ }
134
+ retrieverBuilder .extractToSearchSourceBuilder (sourceBuilder , true );
103
135
104
- // TODO throw if compoundUsed is true?
136
+ QueryBuilder query = sourceBuilder .query ();
137
+ if (query != null && query instanceof RuleQueryBuilder == false ) {
138
+ QueryBuilder organicQuery = query ;
139
+ query = new RuleQueryBuilder (organicQuery , matchCriteria , rulesetIds );
140
+ }
105
141
106
- QueryBuilder organicQuery = retrieverBuilder .topDocsQuery ();
107
- QueryBuilder queryBuilder = new RuleQueryBuilder (organicQuery , matchCriteria , rulesetIds );
142
+ // apply the pre-filters
143
+ if (preFilterQueryBuilders .size () > 0 ) {
144
+ BoolQueryBuilder newQuery = new BoolQueryBuilder ();
145
+ if (query != null ) {
146
+ newQuery .must (query );
147
+ }
148
+ preFilterQueryBuilders .forEach (newQuery ::filter );
149
+ sourceBuilder .query (newQuery );
150
+ }
108
151
109
- searchSourceBuilder . query ( queryBuilder ) ;
152
+ return sourceBuilder ;
110
153
}
111
154
112
155
@ Override
@@ -115,24 +158,46 @@ public void doToXContent(XContentBuilder builder, Params params) throws IOExcept
115
158
builder .startObject (MATCH_CRITERIA_FIELD .getPreferredName ());
116
159
builder .mapContents (matchCriteria );
117
160
builder .endObject ();
118
- builder .startObject ("retriever" );
119
- builder .startObject ();
120
- builder .field (retrieverBuilder .getName ());
121
- retrieverBuilder .toXContent (builder , params );
122
- builder .endObject ();
123
- builder .endObject ();
161
+ }
162
+
163
+ @ Override
164
+ protected QueryRuleRetrieverBuilder clone (List <RetrieverSource > newChildRetrievers ) {
165
+ return new QueryRuleRetrieverBuilder (
166
+ rulesetIds ,
167
+ matchCriteria ,
168
+ newChildRetrievers ,
169
+ rankWindowSize ,
170
+ retrieverName ,
171
+ preFilterQueryBuilders
172
+ );
173
+ }
174
+
175
+ @ Override
176
+ protected RankDoc [] combineInnerRetrieverResults (List <ScoreDoc []> rankResults ) {
177
+ assert rankResults .size () == 1 ;
178
+ ScoreDoc [] scoreDocs = rankResults .getFirst ();
179
+ RankDoc [] rankDocs = new RankDoc [scoreDocs .length ];
180
+ for (int i = 0 ; i < scoreDocs .length ; i ++) {
181
+ ScoreDoc scoreDoc = scoreDocs [i ];
182
+ rankDocs [i ] = new RankDoc (scoreDoc .doc , scoreDoc .score , scoreDoc .shardIndex );
183
+ }
184
+ return rankDocs ;
185
+ }
186
+
187
+ @ Override
188
+ public QueryBuilder explainQuery () {
189
+ // the original matching set of the QueryRuleRetriever retriever is specified by its nested retriever
190
+ return new RankDocsQueryBuilder (rankDocs , new QueryBuilder [] { innerRetrievers .getFirst ().retriever ().explainQuery () }, true );
124
191
}
125
192
126
193
@ Override
127
194
public boolean doEquals (Object o ) {
128
195
QueryRuleRetrieverBuilder that = (QueryRuleRetrieverBuilder ) o ;
129
- return Objects .equals (rulesetIds , that .rulesetIds )
130
- && Objects .equals (matchCriteria , that .matchCriteria )
131
- && Objects .equals (retrieverBuilder , that .retrieverBuilder );
196
+ return super .doEquals (o ) && Objects .equals (rulesetIds , that .rulesetIds ) && Objects .equals (matchCriteria , that .matchCriteria );
132
197
}
133
198
134
199
@ Override
135
200
public int doHashCode () {
136
- return Objects .hash (rulesetIds , matchCriteria , retrieverBuilder );
201
+ return Objects .hash (super . doHashCode (), rulesetIds , matchCriteria );
137
202
}
138
203
}
0 commit comments