Skip to content

Commit 2928fd6

Browse files
committed
Cleanup query builder for inner hits construction.
* Inner hits can now only be provided and prepared via setter in the nested, has_child and has_parent query. * Also made `score_mode` a required constructor parameter. * Moved has_child's min_child/max_children validation from doToQuery(...) to a setter.
1 parent c9ada75 commit 2928fd6

File tree

21 files changed

+389
-516
lines changed

21 files changed

+389
-516
lines changed

core/src/main/java/org/elasticsearch/index/query/AbstractQueryBuilder.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,4 +272,12 @@ public final QueryBuilder<?> rewrite(QueryRewriteContext queryShardContext) thro
272272
protected QueryBuilder<?> doRewrite(QueryRewriteContext queryShardContext) throws IOException {
273273
return this;
274274
}
275+
276+
// Like Objects.requireNotNull(...) but instead throws a IllegalArgumentException
277+
protected static <T> T requireValue(T value, String message) {
278+
if (value == null) {
279+
throw new IllegalArgumentException(message);
280+
}
281+
return value;
282+
}
275283
}

core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java

Lines changed: 34 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@
4545
import java.util.Objects;
4646

4747
/**
48-
* A query builder for <tt>has_child</tt> queries.
48+
* A query builder for <tt>has_child</tt> query.
4949
*/
5050
public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuilder> {
5151

@@ -68,10 +68,6 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil
6868
* The default value for ignore_unmapped.
6969
*/
7070
public static final boolean DEFAULT_IGNORE_UNMAPPED = false;
71-
/*
72-
* The default score mode that is used to combine score coming from multiple parent documents.
73-
*/
74-
public static final ScoreMode DEFAULT_SCORE_MODE = ScoreMode.None;
7571

7672
private static final ParseField QUERY_FIELD = new ParseField("query", "filter");
7773
private static final ParseField TYPE_FIELD = new ParseField("type", "child_type");
@@ -82,42 +78,25 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil
8278
private static final ParseField IGNORE_UNMAPPED_FIELD = new ParseField("ignore_unmapped");
8379

8480
private final QueryBuilder<?> query;
85-
8681
private final String type;
87-
88-
private ScoreMode scoreMode = DEFAULT_SCORE_MODE;
89-
82+
private final ScoreMode scoreMode;
83+
private InnerHitBuilder innerHitBuilder;
9084
private int minChildren = DEFAULT_MIN_CHILDREN;
91-
9285
private int maxChildren = DEFAULT_MAX_CHILDREN;
93-
94-
private InnerHitBuilder innerHitBuilder;
95-
9686
private boolean ignoreUnmapped = false;
9787

88+
public HasChildQueryBuilder(String type, QueryBuilder<?> query, ScoreMode scoreMode) {
89+
this(type, query, DEFAULT_MIN_CHILDREN, DEFAULT_MAX_CHILDREN, scoreMode, null);
90+
}
9891

99-
public HasChildQueryBuilder(String type, QueryBuilder<?> query, int maxChildren, int minChildren, ScoreMode scoreMode,
92+
private HasChildQueryBuilder(String type, QueryBuilder<?> query, int minChildren, int maxChildren, ScoreMode scoreMode,
10093
InnerHitBuilder innerHitBuilder) {
101-
this(type, query);
102-
scoreMode(scoreMode);
103-
this.maxChildren = maxChildren;
104-
this.minChildren = minChildren;
94+
this.type = requireValue(type, "[" + NAME + "] requires 'type' field");
95+
this.query = requireValue(query, "[" + NAME + "] requires 'query' field");
96+
this.scoreMode = requireValue(scoreMode, "[" + NAME + "] requires 'score_mode' field");
10597
this.innerHitBuilder = innerHitBuilder;
106-
if (this.innerHitBuilder != null) {
107-
this.innerHitBuilder.setParentChildType(type);
108-
this.innerHitBuilder.setQuery(query);
109-
}
110-
}
111-
112-
public HasChildQueryBuilder(String type, QueryBuilder<?> query) {
113-
if (type == null) {
114-
throw new IllegalArgumentException("[" + NAME + "] requires 'type' field");
115-
}
116-
if (query == null) {
117-
throw new IllegalArgumentException("[" + NAME + "] requires 'query' field");
118-
}
119-
this.type = type;
120-
this.query = query;
98+
this.minChildren = minChildren;
99+
this.maxChildren = maxChildren;
121100
}
122101

123102
/**
@@ -137,64 +116,47 @@ public HasChildQueryBuilder(StreamInput in) throws IOException {
137116
@Override
138117
protected void doWriteTo(StreamOutput out) throws IOException {
139118
out.writeString(type);
140-
out.writeInt(minChildren());
141-
out.writeInt(maxChildren());
119+
out.writeInt(minChildren);
120+
out.writeInt(maxChildren);
142121
out.writeVInt(scoreMode.ordinal());
143122
out.writeQuery(query);
144123
out.writeOptionalWriteable(innerHitBuilder);
145124
out.writeBoolean(ignoreUnmapped);
146125
}
147126

148127
/**
149-
* Defines how the scores from the matching child documents are mapped into the parent document.
128+
* Defines the minimum number of children that are required to match for the parent to be considered a match and
129+
* the maximum number of children that are required to match for the parent to be considered a match.
150130
*/
151-
public HasChildQueryBuilder scoreMode(ScoreMode scoreMode) {
152-
if (scoreMode == null) {
153-
throw new IllegalArgumentException("[" + NAME + "] requires 'score_mode' field");
154-
}
155-
this.scoreMode = scoreMode;
156-
return this;
157-
}
158-
159-
/**
160-
* Defines the minimum number of children that are required to match for the parent to be considered a match.
161-
*/
162-
public HasChildQueryBuilder minChildren(int minChildren) {
131+
public HasChildQueryBuilder minMaxChildren(int minChildren, int maxChildren) {
163132
if (minChildren < 0) {
164-
throw new IllegalArgumentException("[" + NAME + "] requires non-negative 'min_children' field");
133+
throw new IllegalArgumentException("[" + NAME + "] requires non-negative 'min_children' field");
165134
}
166-
this.minChildren = minChildren;
167-
return this;
168-
}
169-
170-
/**
171-
* Defines the maximum number of children that are required to match for the parent to be considered a match.
172-
*/
173-
public HasChildQueryBuilder maxChildren(int maxChildren) {
174135
if (maxChildren < 0) {
175-
throw new IllegalArgumentException("[" + NAME + "] requires non-negative 'max_children' field");
136+
throw new IllegalArgumentException("[" + NAME + "] requires non-negative 'max_children' field");
176137
}
138+
if (maxChildren < minChildren) {
139+
throw new IllegalArgumentException("[" + NAME + "] 'max_children' is less than 'min_children'");
140+
}
141+
this.minChildren = minChildren;
177142
this.maxChildren = maxChildren;
178143
return this;
179144
}
180145

181-
/**
182-
* Sets the query name for the filter that can be used when searching for matched_filters per hit.
183-
*/
184-
public HasChildQueryBuilder innerHit(InnerHitBuilder innerHitBuilder) {
185-
this.innerHitBuilder = Objects.requireNonNull(innerHitBuilder);
186-
this.innerHitBuilder.setParentChildType(type);
187-
this.innerHitBuilder.setQuery(query);
188-
return this;
189-
}
190-
191146
/**
192147
* Returns inner hit definition in the scope of this query and reusing the defined type and query.
193148
*/
194149
public InnerHitBuilder innerHit() {
195150
return innerHitBuilder;
196151
}
197152

153+
public HasChildQueryBuilder innerHit(InnerHitBuilder innerHit) {
154+
innerHit.setParentChildType(type);
155+
innerHit.setQuery(query);
156+
this.innerHitBuilder = innerHit;
157+
return this;
158+
}
159+
198160
/**
199161
* Returns the children query to execute.
200162
*/
@@ -270,7 +232,7 @@ public static HasChildQueryBuilder fromXContent(QueryParseContext parseContext)
270232
XContentParser parser = parseContext.parser();
271233
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
272234
String childType = null;
273-
ScoreMode scoreMode = HasChildQueryBuilder.DEFAULT_SCORE_MODE;
235+
ScoreMode scoreMode = ScoreMode.None;
274236
int minChildren = HasChildQueryBuilder.DEFAULT_MIN_CHILDREN;
275237
int maxChildren = HasChildQueryBuilder.DEFAULT_MAX_CHILDREN;
276238
boolean ignoreUnmapped = DEFAULT_IGNORE_UNMAPPED;
@@ -312,7 +274,7 @@ public static HasChildQueryBuilder fromXContent(QueryParseContext parseContext)
312274
}
313275
}
314276
}
315-
HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder(childType, iqb, maxChildren, minChildren,
277+
HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder(childType, iqb, minChildren, maxChildren,
316278
scoreMode, innerHitBuilder);
317279
hasChildQueryBuilder.queryName(queryName);
318280
hasChildQueryBuilder.boost(boost);
@@ -386,10 +348,6 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
386348
"[" + NAME + "] Type [" + type + "] points to a non existent parent type [" + parentType + "]");
387349
}
388350

389-
if (maxChildren > 0 && maxChildren < minChildren) {
390-
throw new QueryShardException(context, "[" + NAME + "] 'max_children' is less than 'min_children'");
391-
}
392-
393351
// wrap the query with type query
394352
innerQuery = Queries.filtered(innerQuery, childDocMapper.typeFilter());
395353

@@ -502,7 +460,7 @@ protected boolean doEquals(HasChildQueryBuilder that) {
502460
&& Objects.equals(scoreMode, that.scoreMode)
503461
&& Objects.equals(minChildren, that.minChildren)
504462
&& Objects.equals(maxChildren, that.maxChildren)
505-
&& Objects.equals(innerHitBuilder, that.innerHitBuilder)
463+
&& Objects.equals(innerHitBuilder, that.innerHitBuilder)
506464
&& Objects.equals(ignoreUnmapped, that.ignoreUnmapped);
507465
}
508466

@@ -515,12 +473,7 @@ protected int doHashCode() {
515473
protected QueryBuilder<?> doRewrite(QueryRewriteContext queryRewriteContext) throws IOException {
516474
QueryBuilder<?> rewrite = query.rewrite(queryRewriteContext);
517475
if (rewrite != query) {
518-
HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder(type, rewrite);
519-
hasChildQueryBuilder.minChildren(minChildren);
520-
hasChildQueryBuilder.maxChildren(maxChildren);
521-
hasChildQueryBuilder.scoreMode(scoreMode);
522-
hasChildQueryBuilder.innerHit(innerHitBuilder);
523-
return hasChildQueryBuilder;
476+
return new HasChildQueryBuilder(type, rewrite, minChildren, minChildren, scoreMode, innerHitBuilder);
524477
}
525478
return this;
526479
}

core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java

Lines changed: 16 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,6 @@ public class HasParentQueryBuilder extends AbstractQueryBuilder<HasParentQueryBu
4848
public static final String NAME = "has_parent";
4949
public static final ParseField QUERY_NAME_FIELD = new ParseField(NAME);
5050

51-
public static final boolean DEFAULT_SCORE = false;
52-
5351
/**
5452
* The default value for ignore_unmapped.
5553
*/
@@ -64,33 +62,19 @@ public class HasParentQueryBuilder extends AbstractQueryBuilder<HasParentQueryBu
6462

6563
private final QueryBuilder<?> query;
6664
private final String type;
67-
private boolean score = DEFAULT_SCORE;
65+
private final boolean score;
6866
private InnerHitBuilder innerHit;
6967
private boolean ignoreUnmapped = false;
7068

71-
/**
72-
* @param type The parent type
73-
* @param query The query that will be matched with parent documents
74-
*/
75-
public HasParentQueryBuilder(String type, QueryBuilder<?> query) {
76-
if (type == null) {
77-
throw new IllegalArgumentException("[" + NAME + "] requires 'parent_type' field");
78-
}
79-
if (query == null) {
80-
throw new IllegalArgumentException("[" + NAME + "] requires 'query' field");
81-
}
82-
this.type = type;
83-
this.query = query;
69+
public HasParentQueryBuilder(String type, QueryBuilder<?> query, boolean score) {
70+
this(type, query, score, null);
8471
}
8572

86-
public HasParentQueryBuilder(String type, QueryBuilder<?> query, boolean score, InnerHitBuilder innerHit) {
87-
this(type, query);
73+
private HasParentQueryBuilder(String type, QueryBuilder<?> query, boolean score, InnerHitBuilder innerHit) {
74+
this.type = requireValue(type, "[" + NAME + "] requires 'type' field");
75+
this.query = requireValue(query, "[" + NAME + "] requires 'query' field");
8876
this.score = score;
8977
this.innerHit = innerHit;
90-
if (this.innerHit != null) {
91-
this.innerHit.setParentChildType(type);
92-
this.innerHit.setQuery(query);
93-
}
9478
}
9579

9680
/**
@@ -114,24 +98,6 @@ protected void doWriteTo(StreamOutput out) throws IOException {
11498
out.writeBoolean(ignoreUnmapped);
11599
}
116100

117-
/**
118-
* Defines if the parent score is mapped into the child documents.
119-
*/
120-
public HasParentQueryBuilder score(boolean score) {
121-
this.score = score;
122-
return this;
123-
}
124-
125-
/**
126-
* Sets inner hit definition in the scope of this query and reusing the defined type and query.
127-
*/
128-
public HasParentQueryBuilder innerHit(InnerHitBuilder innerHit) {
129-
this.innerHit = Objects.requireNonNull(innerHit);
130-
this.innerHit.setParentChildType(type);
131-
this.innerHit.setQuery(query);
132-
return this;
133-
}
134-
135101
/**
136102
* Returns the query to execute.
137103
*/
@@ -160,6 +126,13 @@ public InnerHitBuilder innerHit() {
160126
return innerHit;
161127
}
162128

129+
public HasParentQueryBuilder innerHit(InnerHitBuilder innerHit) {
130+
innerHit.setParentChildType(type);
131+
innerHit.setQuery(query);
132+
this.innerHit = innerHit;
133+
return this;
134+
}
135+
163136
/**
164137
* Sets whether the query builder should ignore unmapped types (and run a
165138
* {@link MatchNoDocsQuery} in place of this query) or throw an exception if
@@ -264,7 +237,7 @@ public static HasParentQueryBuilder fromXContent(QueryParseContext parseContext)
264237
XContentParser parser = parseContext.parser();
265238
float boost = AbstractQueryBuilder.DEFAULT_BOOST;
266239
String parentType = null;
267-
boolean score = HasParentQueryBuilder.DEFAULT_SCORE;
240+
boolean score = false;
268241
String queryName = null;
269242
InnerHitBuilder innerHits = null;
270243
boolean ignoreUnmapped = DEFAULT_IGNORE_UNMAPPED;
@@ -323,7 +296,7 @@ protected boolean doEquals(HasParentQueryBuilder that) {
323296
return Objects.equals(query, that.query)
324297
&& Objects.equals(type, that.type)
325298
&& Objects.equals(score, that.score)
326-
&& Objects.equals(innerHit, that.innerHit)
299+
&& Objects.equals(innerHit, that.innerHit)
327300
&& Objects.equals(ignoreUnmapped, that.ignoreUnmapped);
328301
}
329302

@@ -336,10 +309,7 @@ protected int doHashCode() {
336309
protected QueryBuilder<?> doRewrite(QueryRewriteContext queryShardContext) throws IOException {
337310
QueryBuilder<?> rewrite = query.rewrite(queryShardContext);
338311
if (rewrite != query) {
339-
HasParentQueryBuilder hasParentQueryBuilder = new HasParentQueryBuilder(type, rewrite);
340-
hasParentQueryBuilder.score(score);
341-
hasParentQueryBuilder.innerHit(innerHit);
342-
return hasParentQueryBuilder;
312+
return new HasParentQueryBuilder(type, rewrite, score, innerHit);
343313
}
344314
return this;
345315
}

0 commit comments

Comments
 (0)