Browse Source

parent/child: several cleanups

* Dropped ScoreType in favour of Lucene's ScoreMode
* Removed `score_type` option from `has_child` and `has_parent` queries in favour for the already existing `score_mode` option.
* Removed the score mode `sum` in favour for the already existing `total` score mode. (`sum` doesn't exist in Lucene's ScoreMode class)
* If `max_children` is set to `0` it now really means that zero children are allowed to match.
Martijn van Groningen 10 years ago
parent
commit
ab0847e0df

+ 5 - 5
core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java

@@ -31,7 +31,7 @@ public class HasChildQueryBuilder extends QueryBuilder implements BoostableQuery
 
     private float boost = 1.0f;
 
-    private String scoreType;
+    private String scoreMode;
 
     private Integer minChildren;
 
@@ -59,8 +59,8 @@ public class HasChildQueryBuilder extends QueryBuilder implements BoostableQuery
     /**
      * Defines how the scores from the matching child documents are mapped into the parent document.
      */
-    public HasChildQueryBuilder scoreType(String scoreType) {
-        this.scoreType = scoreType;
+    public HasChildQueryBuilder scoreMode(String scoreMode) {
+        this.scoreMode = scoreMode;
         return this;
     }
 
@@ -105,8 +105,8 @@ public class HasChildQueryBuilder extends QueryBuilder implements BoostableQuery
         if (boost != 1.0f) {
             builder.field("boost", boost);
         }
-        if (scoreType != null) {
-            builder.field("score_type", scoreType);
+        if (scoreMode != null) {
+            builder.field("score_mode", scoreMode);
         }
         if (minChildren != null) {
             builder.field("min_children", minChildren);

+ 20 - 33
core/src/main/java/org/elasticsearch/index/query/HasChildQueryParser.java

@@ -38,7 +38,6 @@ import org.elasticsearch.index.query.support.InnerHitsQueryParserHelper;
 import org.elasticsearch.index.query.support.XContentStructure;
 import org.elasticsearch.search.fetch.innerhits.InnerHitsContext;
 import org.elasticsearch.search.fetch.innerhits.InnerHitsSubSearchContext;
-import org.elasticsearch.search.internal.SearchContext;
 
 import java.io.IOException;
 
@@ -69,9 +68,9 @@ public class HasChildQueryParser implements QueryParser {
         boolean queryFound = false;
         float boost = 1.0f;
         String childType = null;
-        ScoreType scoreType = ScoreType.NONE;
+        ScoreMode scoreMode = ScoreMode.None;
         int minChildren = 0;
-        int maxChildren = 0;
+        int maxChildren = Integer.MAX_VALUE;
         String queryName = null;
         InnerHitsSubSearchContext innerHits = null;
 
@@ -99,10 +98,8 @@ public class HasChildQueryParser implements QueryParser {
             } else if (token.isValue()) {
                 if ("type".equals(currentFieldName) || "child_type".equals(currentFieldName) || "childType".equals(currentFieldName)) {
                     childType = parser.text();
-                } else if ("score_type".equals(currentFieldName) || "scoreType".equals(currentFieldName)) {
-                    scoreType = ScoreType.fromString(parser.text());
                 } else if ("score_mode".equals(currentFieldName) || "scoreMode".equals(currentFieldName)) {
-                    scoreType = ScoreType.fromString(parser.text());
+                    scoreMode = parseScoreMode(parser.text());
                 } else if ("boost".equals(currentFieldName)) {
                     boost = parser.floatValue();
                 } else if ("min_children".equals(currentFieldName) || "minChildren".equals(currentFieldName)) {
@@ -162,7 +159,7 @@ public class HasChildQueryParser implements QueryParser {
 
         final Query query;
         final ParentChildIndexFieldData parentChildIndexFieldData = parseContext.getForField(parentFieldMapper.fieldType());
-        query = joinUtilHelper(parentType, parentChildIndexFieldData, parentDocMapper.typeFilter(), scoreType, innerQuery, minChildren, maxChildren);
+        query = joinUtilHelper(parentType, parentChildIndexFieldData, parentDocMapper.typeFilter(), scoreMode, innerQuery, minChildren, maxChildren);
         if (queryName != null) {
             parseContext.addNamedQuery(queryName, query);
         }
@@ -170,35 +167,25 @@ public class HasChildQueryParser implements QueryParser {
         return query;
     }
 
-    public static Query joinUtilHelper(String parentType, ParentChildIndexFieldData parentChildIndexFieldData, Query toQuery, ScoreType scoreType, Query innerQuery, int minChildren, int maxChildren) throws IOException {
-        ScoreMode scoreMode;
-        // TODO: move entirely over from ScoreType to org.apache.lucene.join.ScoreMode, when we drop the 1.x parent child code.
-        switch (scoreType) {
-            case NONE:
-                scoreMode = ScoreMode.None;
-                break;
-            case MIN:
-                scoreMode = ScoreMode.Min;
-                break;
-            case MAX:
-                scoreMode = ScoreMode.Max;
-                break;
-            case SUM:
-                scoreMode = ScoreMode.Total;
-                break;
-            case AVG:
-                scoreMode = ScoreMode.Avg;
-                break;
-            default:
-                throw new UnsupportedOperationException("score type [" + scoreType + "] not supported");
-        }
-        // 0 in pre 2.x p/c impl means unbounded
-        if (maxChildren == 0) {
-            maxChildren = Integer.MAX_VALUE;
-        }
+    public static Query joinUtilHelper(String parentType, ParentChildIndexFieldData parentChildIndexFieldData, Query toQuery, ScoreMode scoreMode, Query innerQuery, int minChildren, int maxChildren) throws IOException {
         return new LateParsingQuery(toQuery, innerQuery, minChildren, maxChildren, parentType, scoreMode, parentChildIndexFieldData);
     }
 
+    public static ScoreMode parseScoreMode(String scoreModeString) {
+        if ("none".equals(scoreModeString)) {
+            return ScoreMode.None;
+        } else if ("min".equals(scoreModeString)) {
+            return ScoreMode.Min;
+        } else if ("max".equals(scoreModeString)) {
+            return ScoreMode.Max;
+        } else if ("avg".equals(scoreModeString)) {
+            return ScoreMode.Avg;
+        } else if ("total".equals(scoreModeString)) {
+            return ScoreMode.Total;
+        }
+        throw new IllegalArgumentException("No score mode for child query [" + scoreModeString + "] found");
+    }
+
     final static class LateParsingQuery extends Query {
 
         private final Query toQuery;

+ 5 - 5
core/src/main/java/org/elasticsearch/index/query/HasParentQueryBuilder.java

@@ -30,7 +30,7 @@ public class HasParentQueryBuilder extends QueryBuilder implements BoostableQuer
 
     private final QueryBuilder queryBuilder;
     private final String parentType;
-    private String scoreType;
+    private String scoreMode;
     private float boost = 1.0f;
     private String queryName;
     private QueryInnerHitBuilder innerHit = null;
@@ -53,8 +53,8 @@ public class HasParentQueryBuilder extends QueryBuilder implements BoostableQuer
     /**
      * Defines how the parent score is mapped into the child documents.
      */
-    public HasParentQueryBuilder scoreType(String scoreType) {
-        this.scoreType = scoreType;
+    public HasParentQueryBuilder scoreMode(String scoreMode) {
+        this.scoreMode = scoreMode;
         return this;
     }
 
@@ -80,8 +80,8 @@ public class HasParentQueryBuilder extends QueryBuilder implements BoostableQuer
         builder.field("query");
         queryBuilder.toXContent(builder, params);
         builder.field("parent_type", parentType);
-        if (scoreType != null) {
-            builder.field("score_type", scoreType);
+        if (scoreMode != null) {
+            builder.field("score_mode", scoreMode);
         }
         if (boost != 1.0f) {
             builder.field("boost", boost);

+ 2 - 8
core/src/main/java/org/elasticsearch/index/query/HasParentQueryParser.java

@@ -19,6 +19,7 @@
 package org.elasticsearch.index.query;
 
 import org.apache.lucene.search.*;
+import org.apache.lucene.search.join.ScoreMode;
 import org.elasticsearch.common.ParseField;
 import org.elasticsearch.common.Strings;
 import org.elasticsearch.common.inject.Inject;
@@ -88,13 +89,6 @@ public class HasParentQueryParser implements QueryParser {
             } else if (token.isValue()) {
                 if ("type".equals(currentFieldName) || "parent_type".equals(currentFieldName) || "parentType".equals(currentFieldName)) {
                     parentType = parser.text();
-                } else if ("score_type".equals(currentFieldName) || "scoreType".equals(currentFieldName)) {
-                    String scoreTypeValue = parser.text();
-                    if ("score".equals(scoreTypeValue)) {
-                        score = true;
-                    } else if ("none".equals(scoreTypeValue)) {
-                        score = false;
-                    }
                 } else if ("score_mode".equals(currentFieldName) || "scoreMode".equals(currentFieldName)) {
                     String scoreModeValue = parser.text();
                     if ("score".equals(scoreModeValue)) {
@@ -193,7 +187,7 @@ public class HasParentQueryParser implements QueryParser {
         // wrap the query with type query
         innerQuery = Queries.filtered(innerQuery, parentDocMapper.typeFilter());
         Query childrenFilter = Queries.not(parentTypeQuery);
-        ScoreType scoreMode = score ? ScoreType.MAX : ScoreType.NONE;
+        ScoreMode scoreMode = score ? ScoreMode.Max : ScoreMode.None;
         return joinUtilHelper(parentType, parentChildIndexFieldData, childrenFilter, scoreMode, innerQuery, 0, Integer.MAX_VALUE);
     }
 

+ 0 - 71
core/src/main/java/org/elasticsearch/index/query/ScoreType.java

@@ -1,71 +0,0 @@
-/*
- * Licensed to Elasticsearch under one or more contributor
- * license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright
- * ownership. Elasticsearch 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.elasticsearch.index.query;
-
-
-/**
- * Defines how scores from child documents are mapped into the parent document.
- */
-public enum ScoreType {
-    /**
-     * Only the lowest score of all matching child documents is mapped into the
-     * parent.
-     */
-    MIN,
-    /**
-     * Only the highest score of all matching child documents is mapped into the
-     * parent.
-     */
-    MAX,
-
-    /**
-     * The average score based on all matching child documents are mapped into
-     * the parent.
-     */
-    AVG,
-
-    /**
-     * The matching children scores is summed up and mapped into the parent.
-     */
-    SUM,
-
-    /**
-     * Scores are not taken into account
-     */
-    NONE;
-
-
-    public static ScoreType fromString(String type) {
-        if ("none".equals(type)) {
-            return NONE;
-        } else if ("min".equals(type)) {
-            return MIN;
-        } else if ("max".equals(type)) {
-            return MAX;
-        } else if ("avg".equals(type)) {
-            return AVG;
-        } else if ("sum".equals(type)) {
-            return SUM;
-        } else if ("total".equals(type)) { // This name is consistent with: ScoreMode.Total
-            return SUM;
-        }
-        throw new IllegalArgumentException("No score type for child query [" + type + "] found");
-    }
-
-}

+ 6 - 6
core/src/test/java/org/elasticsearch/benchmark/search/child/ChildSearchBenchmark.java

@@ -281,12 +281,12 @@ public class ChildSearchBenchmark {
         System.out.println("--> Running has_child query with score type");
         // run parent child score query
         for (int j = 0; j < QUERY_WARMUP; j++) {
-            client.prepareSearch(indexName).setQuery(hasChildQuery("child", termQuery("field2", parentChildIndexGenerator.getQueryValue())).scoreType("max")).execute().actionGet();
+            client.prepareSearch(indexName).setQuery(hasChildQuery("child", termQuery("field2", parentChildIndexGenerator.getQueryValue())).scoreMode("max")).execute().actionGet();
         }
 
         totalQueryTime = 0;
         for (int j = 0; j < QUERY_COUNT; j++) {
-            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasChildQuery("child", termQuery("field2", parentChildIndexGenerator.getQueryValue())).scoreType("max")).execute().actionGet();
+            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasChildQuery("child", termQuery("field2", parentChildIndexGenerator.getQueryValue())).scoreMode("max")).execute().actionGet();
             if (j % 10 == 0) {
                 System.out.println("--> hits [" + j + "], got [" + searchResponse.getHits().totalHits() + "]");
             }
@@ -296,7 +296,7 @@ public class ChildSearchBenchmark {
         
         totalQueryTime = 0;
         for (int j = 0; j < QUERY_COUNT; j++) {
-            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasChildQuery("child", matchAllQuery()).scoreType("max")).execute().actionGet();
+            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasChildQuery("child", matchAllQuery()).scoreMode("max")).execute().actionGet();
             if (j % 10 == 0) {
                 System.out.println("--> hits [" + j + "], got [" + searchResponse.getHits().totalHits() + "]");
             }
@@ -307,12 +307,12 @@ public class ChildSearchBenchmark {
         System.out.println("--> Running has_parent query with score type");
         // run parent child score query
         for (int j = 0; j < QUERY_WARMUP; j++) {
-            client.prepareSearch(indexName).setQuery(hasParentQuery("parent", termQuery("field1", parentChildIndexGenerator.getQueryValue())).scoreType("score")).execute().actionGet();
+            client.prepareSearch(indexName).setQuery(hasParentQuery("parent", termQuery("field1", parentChildIndexGenerator.getQueryValue())).scoreMode("score")).execute().actionGet();
         }
 
         totalQueryTime = 0;
         for (int j = 1; j < QUERY_COUNT; j++) {
-            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasParentQuery("parent", termQuery("field1", parentChildIndexGenerator.getQueryValue())).scoreType("score")).execute().actionGet();
+            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasParentQuery("parent", termQuery("field1", parentChildIndexGenerator.getQueryValue())).scoreMode("score")).execute().actionGet();
             if (j % 10 == 0) {
                 System.out.println("--> hits [" + j + "], got [" + searchResponse.getHits().totalHits() + "]");
             }
@@ -322,7 +322,7 @@ public class ChildSearchBenchmark {
 
         totalQueryTime = 0;
         for (int j = 1; j < QUERY_COUNT; j++) {
-            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasParentQuery("parent", matchAllQuery()).scoreType("score")).execute().actionGet();
+            SearchResponse searchResponse = client.prepareSearch(indexName).setQuery(hasParentQuery("parent", matchAllQuery()).scoreMode("score")).execute().actionGet();
             if (j % 10 == 0) {
                 System.out.println("--> hits [" + j + "], got [" + searchResponse.getHits().totalHits() + "]");
             }

+ 1 - 1
core/src/test/java/org/elasticsearch/benchmark/search/child/ChildSearchShortCircuitBenchmark.java

@@ -178,7 +178,7 @@ public class ChildSearchShortCircuitBenchmark {
         for (int i = 1; i < PARENT_COUNT; i *= 2) {
             for (int j = 0; j < QUERY_COUNT; j++) {
                 SearchResponse searchResponse = client.prepareSearch(indexName)
-                        .setQuery(hasChildQuery("child", matchQuery("field2", i)).scoreType("max"))
+                        .setQuery(hasChildQuery("child", matchQuery("field2", i)).scoreMode("max"))
                         .execute().actionGet();
                 if (searchResponse.getHits().totalHits() != i) {
                     System.err.println("--> mismatch on hits");

+ 10 - 14
core/src/test/java/org/elasticsearch/index/query/ScoreTypeTests.java → core/src/test/java/org/elasticsearch/index/query/HasChildQueryParserTests.java

@@ -18,42 +18,38 @@
  */
 package org.elasticsearch.index.query;
 
-import org.elasticsearch.index.query.ScoreType;
+import org.apache.lucene.search.join.ScoreMode;
 import org.elasticsearch.test.ESTestCase;
 import org.junit.Test;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.equalTo;
 
-/**
- * Tests {@link ScoreType} to ensure backward compatibility of any changes.
- */
-public class ScoreTypeTests extends ESTestCase {
+public class HasChildQueryParserTests extends ESTestCase {
+
     @Test
     public void minFromString() {
-        assertThat("fromString(min) != MIN", ScoreType.MIN, equalTo(ScoreType.fromString("min")));
+        assertThat("fromString(min) != MIN", ScoreMode.Min, equalTo(HasChildQueryParser.parseScoreMode("min")));
     }
 
     @Test
     public void maxFromString() {
-        assertThat("fromString(max) != MAX", ScoreType.MAX, equalTo(ScoreType.fromString("max")));
+        assertThat("fromString(max) != MAX", ScoreMode.Max, equalTo(HasChildQueryParser.parseScoreMode("max")));
     }
 
     @Test
     public void avgFromString() {
-        assertThat("fromString(avg) != AVG", ScoreType.AVG, equalTo(ScoreType.fromString("avg")));
+        assertThat("fromString(avg) != AVG", ScoreMode.Avg, equalTo(HasChildQueryParser.parseScoreMode("avg")));
     }
 
     @Test
     public void sumFromString() {
-        assertThat("fromString(sum) != SUM", ScoreType.SUM, equalTo(ScoreType.fromString("sum")));
-        // allowed for consistency with ScoreMode.Total:
-        assertThat("fromString(total) != SUM", ScoreType.SUM, equalTo(ScoreType.fromString("total")));
+        assertThat("fromString(total) != SUM", ScoreMode.Total, equalTo(HasChildQueryParser.parseScoreMode("total")));
     }
 
     @Test
     public void noneFromString() {
-        assertThat("fromString(none) != NONE", ScoreType.NONE, equalTo(ScoreType.fromString("none")));
+        assertThat("fromString(none) != NONE", ScoreMode.None, equalTo(HasChildQueryParser.parseScoreMode("none")));
     }
 
     /**
@@ -61,7 +57,7 @@ public class ScoreTypeTests extends ESTestCase {
      */
     @Test(expected = IllegalArgumentException.class)
     public void nullFromString_throwsException() {
-        ScoreType.fromString(null);
+        HasChildQueryParser.parseScoreMode(null);
     }
 
     /**
@@ -69,6 +65,6 @@ public class ScoreTypeTests extends ESTestCase {
      */
     @Test(expected = IllegalArgumentException.class)
     public void unrecognizedFromString_throwsException() {
-        ScoreType.fromString("unrecognized value");
+        HasChildQueryParser.parseScoreMode("unrecognized value");
     }
 }

+ 69 - 155
core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java

@@ -18,6 +18,7 @@
  */
 package org.elasticsearch.search.child;
 
+import org.apache.lucene.search.join.ScoreMode;
 import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
 import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
 import org.elasticsearch.action.count.CountResponse;
@@ -26,6 +27,7 @@ import org.elasticsearch.action.index.IndexRequestBuilder;
 import org.elasticsearch.action.search.SearchPhaseExecutionException;
 import org.elasticsearch.action.search.SearchResponse;
 import org.elasticsearch.action.search.SearchType;
+import org.elasticsearch.common.collect.HppcMaps;
 import org.elasticsearch.common.lucene.search.function.CombineFunction;
 import org.elasticsearch.common.settings.Settings;
 import org.elasticsearch.common.unit.TimeValue;
@@ -34,7 +36,6 @@ import org.elasticsearch.index.mapper.MergeMappingException;
 import org.elasticsearch.index.query.HasChildQueryBuilder;
 import org.elasticsearch.index.query.QueryBuilder;
 import org.elasticsearch.index.query.QueryBuilders;
-import org.elasticsearch.index.query.ScoreType;
 import org.elasticsearch.rest.RestStatus;
 import org.elasticsearch.script.Script;
 import org.elasticsearch.search.aggregations.AggregationBuilders;
@@ -74,7 +75,6 @@ import static org.elasticsearch.index.query.QueryBuilders.termQuery;
 import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
 import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.scriptFunction;
 import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.weightFactorFunction;
-import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
 import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
@@ -293,11 +293,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         for (int i = 1; i <= 10; i++) {
             logger.info("Round {}", i);
             SearchResponse searchResponse = client().prepareSearch("test")
-                    .setQuery(constantScoreQuery(hasChildQuery("child", matchAllQuery()).scoreType("max")))
+                    .setQuery(constantScoreQuery(hasChildQuery("child", matchAllQuery()).scoreMode("max")))
                     .get();
             assertNoFailures(searchResponse);
             searchResponse = client().prepareSearch("test")
-                    .setQuery(constantScoreQuery(hasParentQuery("parent", matchAllQuery()).scoreType("score")))
+                    .setQuery(constantScoreQuery(hasParentQuery("parent", matchAllQuery()).scoreMode("score")))
                     .get();
             assertNoFailures(searchResponse);
         }
@@ -555,11 +555,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         client().prepareIndex("test", "child", "c1").setSource("c_field", "1").setParent(parentId).get();
         refresh();
 
-        CountResponse countResponse = client().prepareCount("test").setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max"))
+        CountResponse countResponse = client().prepareCount("test").setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreMode("max"))
                 .get();
         assertHitCount(countResponse, 1l);
 
-        countResponse = client().prepareCount("test").setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score"))
+        countResponse = client().prepareCount("test").setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreMode("score"))
                 .get();
         assertHitCount(countResponse, 1l);
 
@@ -586,20 +586,20 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
 
         SearchResponse searchResponse = client().prepareSearch("test")
                 .setExplain(true)
-                .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max"))
+                .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreMode("max"))
                 .get();
         assertHitCount(searchResponse, 1l);
         assertThat(searchResponse.getHits().getAt(0).explanation().getDescription(), equalTo("Score based on join value p1"));
 
         searchResponse = client().prepareSearch("test")
                 .setExplain(true)
-                .setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score"))
+                .setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreMode("score"))
                 .get();
         assertHitCount(searchResponse, 1l);
         assertThat(searchResponse.getHits().getAt(0).explanation().getDescription(), equalTo("Score based on join value p1"));
 
         ExplainResponse explainResponse = client().prepareExplain("test", "parent", parentId)
-                .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max"))
+                .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreMode("max"))
                 .get();
         assertThat(explainResponse.isExists(), equalTo(true));
         assertThat(explainResponse.getExplanation().getDetails()[0].getDescription(), equalTo("Score based on join value p1"));
@@ -677,7 +677,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
                                 "child",
                                 QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
                                         scriptFunction(new Script("doc['c_field1'].value")))
-                                        .boostMode(CombineFunction.REPLACE.getName())).scoreType("sum")).get();
+                                        .boostMode(CombineFunction.REPLACE.getName())).scoreMode("total")).get();
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("1"));
@@ -694,7 +694,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
                                 "child",
                                 QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
                                         scriptFunction(new Script("doc['c_field1'].value")))
-                                        .boostMode(CombineFunction.REPLACE.getName())).scoreType("max")).get();
+                                        .boostMode(CombineFunction.REPLACE.getName())).scoreMode("max")).get();
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("3"));
@@ -711,7 +711,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
                                 "child",
                                 QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
                                         scriptFunction(new Script("doc['c_field1'].value")))
-                                        .boostMode(CombineFunction.REPLACE.getName())).scoreType("avg")).get();
+                                        .boostMode(CombineFunction.REPLACE.getName())).scoreMode("avg")).get();
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("3"));
@@ -728,7 +728,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
                                 "parent",
                                 QueryBuilders.functionScoreQuery(matchQuery("p_field1", "p_value3"),
                                         scriptFunction(new Script("doc['p_field2'].value")))
-                                        .boostMode(CombineFunction.REPLACE.getName())).scoreType("score"))
+                                        .boostMode(CombineFunction.REPLACE.getName())).scoreMode("score"))
                 .addSort(SortBuilders.fieldSort("c_field3")).addSort(SortBuilders.scoreSort()).get();
 
         assertThat(response.getHits().totalHits(), equalTo(7l));
@@ -768,7 +768,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertNoFailures(response);
         assertThat(response.getHits().totalHits(), equalTo(0l));
 
-        response = client().prepareSearch("test").setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value")).scoreType("max"))
+        response = client().prepareSearch("test").setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value")).scoreMode("max"))
                 .get();
         assertNoFailures(response);
         assertThat(response.getHits().totalHits(), equalTo(0l));
@@ -777,7 +777,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertNoFailures(response);
         assertThat(response.getHits().totalHits(), equalTo(0l));
 
-        response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("child", matchQuery("text", "value")).scoreType("score"))
+        response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("child", matchQuery("text", "value")).scoreMode("score"))
                 .get();
         assertNoFailures(response);
         assertThat(response.getHits().totalHits(), equalTo(0l));
@@ -864,7 +864,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         SearchType[] searchTypes = new SearchType[]{SearchType.QUERY_THEN_FETCH, SearchType.DFS_QUERY_THEN_FETCH};
         for (SearchType searchType : searchTypes) {
             SearchResponse searchResponse = client().prepareSearch("test").setSearchType(searchType)
-                    .setQuery(hasChildQuery("child", prefixQuery("c_field", "c")).scoreType("max")).addSort("p_field", SortOrder.ASC)
+                    .setQuery(hasChildQuery("child", prefixQuery("c_field", "c")).scoreMode("max")).addSort("p_field", SortOrder.ASC)
                     .setSize(5).get();
             assertNoFailures(searchResponse);
             assertThat(searchResponse.getHits().totalHits(), equalTo(10L));
@@ -875,7 +875,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
             assertThat(searchResponse.getHits().hits()[4].id(), equalTo("p004"));
 
             searchResponse = client().prepareSearch("test").setSearchType(searchType)
-                    .setQuery(hasParentQuery("parent", prefixQuery("p_field", "p")).scoreType("score")).addSort("c_field", SortOrder.ASC)
+                    .setQuery(hasParentQuery("parent", prefixQuery("p_field", "p")).scoreMode("score")).addSort("c_field", SortOrder.ASC)
                     .setSize(5).get();
             assertNoFailures(searchResponse);
             assertThat(searchResponse.getHits().totalHits(), equalTo(500L));
@@ -907,7 +907,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         refresh();
 
         SearchResponse searchResponse = client().prepareSearch("test")
-                .setQuery(hasChildQuery("child", termQuery("c_field", "yellow")).scoreType("sum")).get();
+                .setQuery(hasChildQuery("child", termQuery("c_field", "yellow")).scoreMode("total")).get();
         assertNoFailures(searchResponse);
         assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
         assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1"));
@@ -917,7 +917,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
                 .prepareSearch("test")
                 .setQuery(
                         boolQuery().must(matchQuery("c_field", "x")).must(
-                                hasParentQuery("parent", termQuery("p_field", "p_value2")).scoreType("score"))).get();
+                                hasParentQuery("parent", termQuery("p_field", "p_value2")).scoreMode("score"))).get();
         assertNoFailures(searchResponse);
         assertThat(searchResponse.getHits().totalHits(), equalTo(2l));
         assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c3"));
@@ -932,7 +932,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
             client().admin().indices().prepareRefresh("test").get();
         }
 
-        searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow")).scoreType("sum"))
+        searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow")).scoreMode("total"))
                 .get();
         assertNoFailures(searchResponse);
         assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
@@ -943,7 +943,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
                 .prepareSearch("test")
                 .setQuery(
                         boolQuery().must(matchQuery("c_field", "x")).must(
-                                hasParentQuery("parent", termQuery("p_field", "p_value2")).scoreType("score"))).get();
+                                hasParentQuery("parent", termQuery("p_field", "p_value2")).scoreMode("score"))).get();
         assertNoFailures(searchResponse);
         assertThat(searchResponse.getHits().totalHits(), equalTo(2l));
         assertThat(searchResponse.getHits().getAt(0).id(), Matchers.anyOf(equalTo("c3"), equalTo("c4")));
@@ -968,7 +968,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         client().prepareIndex("test", "child", "c5").setSource("c_field", "x").setParent("p2").get();
         refresh();
 
-        SearchResponse searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", matchAllQuery()).scoreType("sum"))
+        SearchResponse searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", matchAllQuery()).scoreMode("total"))
                 .setMinScore(3) // Score needs to be 3 or above!
                 .get();
         assertNoFailures(searchResponse);
@@ -1237,15 +1237,15 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         client().prepareIndex("test", "child", "c3").setParent("p2").setSource("c_field", "red").get();
         refresh();
 
-        String scoreMode = ScoreType.values()[getRandom().nextInt(ScoreType.values().length)].name().toLowerCase(Locale.ROOT);
+        String scoreMode = ScoreMode.values()[getRandom().nextInt(ScoreMode.values().length)].name().toLowerCase(Locale.ROOT);
         SearchResponse searchResponse = client().prepareSearch("test")
-                .setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "blue")).scoreType(scoreMode)).filter(notQuery(termQuery("p_field", "3"))))
+                .setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "blue")).scoreMode(scoreMode)).filter(notQuery(termQuery("p_field", "3"))))
                 .get();
         assertNoFailures(searchResponse);
         assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
 
         searchResponse = client().prepareSearch("test")
-                .setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "red")).scoreType(scoreMode)).filter(notQuery(termQuery("p_field", "3"))))
+                .setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "red")).scoreMode(scoreMode)).filter(notQuery(termQuery("p_field", "3"))))
                 .get();
         assertNoFailures(searchResponse);
         assertThat(searchResponse.getHits().totalHits(), equalTo(2l));
@@ -1263,13 +1263,13 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         client().prepareIndex("test", "child", "c1").setSource("c_field", "1").setParent(parentId).get();
         refresh();
 
-        SearchResponse searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max").queryName("test"))
+        SearchResponse searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreMode("max").queryName("test"))
                 .get();
         assertHitCount(searchResponse, 1l);
         assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1));
         assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("test"));
 
-        searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score").queryName("test"))
+        searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreMode("score").queryName("test"))
                 .get();
         assertHitCount(searchResponse, 1l);
         assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1));
@@ -1311,7 +1311,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
 
         try {
             client().prepareSearch("test")
-                    .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max"))
+                    .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreMode("max"))
                     .get();
             fail();
         } catch (SearchPhaseExecutionException e) {
@@ -1329,7 +1329,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
 
         try {
             client().prepareSearch("test")
-                    .setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score"))
+                    .setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreMode("score"))
                     .get();
             fail();
         } catch (SearchPhaseExecutionException e) {
@@ -1579,28 +1579,23 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         return indexBuilders;
     }
 
-    private SearchResponse minMaxQuery(String scoreType, int minChildren, int maxChildren) throws SearchPhaseExecutionException {
-        return client()
-                .prepareSearch("test")
-                .setQuery(
-                        QueryBuilders
-                                .hasChildQuery(
-                                        "child",
-                                        QueryBuilders.functionScoreQuery(constantScoreQuery(QueryBuilders.termQuery("foo", "two"))).boostMode("replace").scoreMode("sum")
-                                                .add(QueryBuilders.matchAllQuery(), weightFactorFunction(1))
-                                                .add(QueryBuilders.termQuery("foo", "three"), weightFactorFunction(1))
-                                                .add(QueryBuilders.termQuery("foo", "four"), weightFactorFunction(1))).scoreType(scoreType)
-                                .minChildren(minChildren).maxChildren(maxChildren))
-                .addSort("_score", SortOrder.DESC).addSort("id", SortOrder.ASC).get();
-    }
+    private SearchResponse minMaxQuery(String scoreMode, int minChildren, Integer maxChildren) throws SearchPhaseExecutionException {
+        HasChildQueryBuilder hasChildQuery = hasChildQuery(
+                "child",
+                QueryBuilders.functionScoreQuery(constantScoreQuery(QueryBuilders.termQuery("foo", "two"))).boostMode("replace").scoreMode("sum")
+                        .add(QueryBuilders.matchAllQuery(), weightFactorFunction(1))
+                        .add(QueryBuilders.termQuery("foo", "three"), weightFactorFunction(1))
+                        .add(QueryBuilders.termQuery("foo", "four"), weightFactorFunction(1))).scoreMode(scoreMode)
+                .minChildren(minChildren);
+
+        if (maxChildren != null) {
+            hasChildQuery.maxChildren(maxChildren);
+        }
 
-    private SearchResponse minMaxFilter(int minChildren, int maxChildren) throws SearchPhaseExecutionException {
         return client()
                 .prepareSearch("test")
-                .setQuery(
-                        QueryBuilders.constantScoreQuery(QueryBuilders.hasChildQuery("child", termQuery("foo", "two"))
-                                .minChildren(minChildren).maxChildren(maxChildren)))
-                .addSort("id", SortOrder.ASC).setTrackScores(true).get();
+                .setQuery(hasChildQuery)
+                .addSort("_score", SortOrder.DESC).addSort("id", SortOrder.ASC).get();
     }
 
     @Test
@@ -1614,7 +1609,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         SearchResponse response;
 
         // Score mode = NONE
-        response = minMaxQuery("none", 0, 0);
+        response = minMaxQuery("none", 0, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("2"));
@@ -1624,7 +1619,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("4"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("none", 1, 0);
+        response = minMaxQuery("none", 1, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("2"));
@@ -1634,7 +1629,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("4"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("none", 2, 0);
+        response = minMaxQuery("none", 2, null);
 
         assertThat(response.getHits().totalHits(), equalTo(2l));
         assertThat(response.getHits().hits()[0].id(), equalTo("3"));
@@ -1642,13 +1637,13 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[1].id(), equalTo("4"));
         assertThat(response.getHits().hits()[1].score(), equalTo(1f));
 
-        response = minMaxQuery("none", 3, 0);
+        response = minMaxQuery("none", 3, null);
 
         assertThat(response.getHits().totalHits(), equalTo(1l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
         assertThat(response.getHits().hits()[0].score(), equalTo(1f));
 
-        response = minMaxQuery("none", 4, 0);
+        response = minMaxQuery("none", 4, null);
 
         assertThat(response.getHits().totalHits(), equalTo(0l));
 
@@ -1693,8 +1688,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
             assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'"));
         }
 
-        // Score mode = SUM
-        response = minMaxQuery("sum", 0, 0);
+        // Score mode = TOTAL
+        response = minMaxQuery("total", 0, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1704,7 +1699,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("sum", 1, 0);
+        response = minMaxQuery("total", 1, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1714,7 +1709,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("sum", 2, 0);
+        response = minMaxQuery("total", 2, null);
 
         assertThat(response.getHits().totalHits(), equalTo(2l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1722,17 +1717,17 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[1].id(), equalTo("3"));
         assertThat(response.getHits().hits()[1].score(), equalTo(3f));
 
-        response = minMaxQuery("sum", 3, 0);
+        response = minMaxQuery("total", 3, null);
 
         assertThat(response.getHits().totalHits(), equalTo(1l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
         assertThat(response.getHits().hits()[0].score(), equalTo(6f));
 
-        response = minMaxQuery("sum", 4, 0);
+        response = minMaxQuery("total", 4, null);
 
         assertThat(response.getHits().totalHits(), equalTo(0l));
 
-        response = minMaxQuery("sum", 0, 4);
+        response = minMaxQuery("total", 0, 4);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1742,7 +1737,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("sum", 0, 3);
+        response = minMaxQuery("total", 0, 3);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1752,7 +1747,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("sum", 0, 2);
+        response = minMaxQuery("total", 0, 2);
 
         assertThat(response.getHits().totalHits(), equalTo(2l));
         assertThat(response.getHits().hits()[0].id(), equalTo("3"));
@@ -1760,21 +1755,21 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[1].id(), equalTo("2"));
         assertThat(response.getHits().hits()[1].score(), equalTo(1f));
 
-        response = minMaxQuery("sum", 2, 2);
+        response = minMaxQuery("total", 2, 2);
 
         assertThat(response.getHits().totalHits(), equalTo(1l));
         assertThat(response.getHits().hits()[0].id(), equalTo("3"));
         assertThat(response.getHits().hits()[0].score(), equalTo(3f));
 
         try {
-            response = minMaxQuery("sum", 3, 2);
+            response = minMaxQuery("total", 3, 2);
             fail();
         } catch (SearchPhaseExecutionException e) {
             assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'"));
         }
 
         // Score mode = MAX
-        response = minMaxQuery("max", 0, 0);
+        response = minMaxQuery("max", 0, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1784,7 +1779,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("max", 1, 0);
+        response = minMaxQuery("max", 1, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1794,7 +1789,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("max", 2, 0);
+        response = minMaxQuery("max", 2, null);
 
         assertThat(response.getHits().totalHits(), equalTo(2l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1802,13 +1797,13 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[1].id(), equalTo("3"));
         assertThat(response.getHits().hits()[1].score(), equalTo(2f));
 
-        response = minMaxQuery("max", 3, 0);
+        response = minMaxQuery("max", 3, null);
 
         assertThat(response.getHits().totalHits(), equalTo(1l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
         assertThat(response.getHits().hits()[0].score(), equalTo(3f));
 
-        response = minMaxQuery("max", 4, 0);
+        response = minMaxQuery("max", 4, null);
 
         assertThat(response.getHits().totalHits(), equalTo(0l));
 
@@ -1854,7 +1849,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         }
 
         // Score mode = AVG
-        response = minMaxQuery("avg", 0, 0);
+        response = minMaxQuery("avg", 0, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1864,7 +1859,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("avg", 1, 0);
+        response = minMaxQuery("avg", 1, null);
 
         assertThat(response.getHits().totalHits(), equalTo(3l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1874,7 +1869,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[2].id(), equalTo("2"));
         assertThat(response.getHits().hits()[2].score(), equalTo(1f));
 
-        response = minMaxQuery("avg", 2, 0);
+        response = minMaxQuery("avg", 2, null);
 
         assertThat(response.getHits().totalHits(), equalTo(2l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
@@ -1882,13 +1877,13 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         assertThat(response.getHits().hits()[1].id(), equalTo("3"));
         assertThat(response.getHits().hits()[1].score(), equalTo(1.5f));
 
-        response = minMaxQuery("avg", 3, 0);
+        response = minMaxQuery("avg", 3, null);
 
         assertThat(response.getHits().totalHits(), equalTo(1l));
         assertThat(response.getHits().hits()[0].id(), equalTo("4"));
         assertThat(response.getHits().hits()[0].score(), equalTo(2f));
 
-        response = minMaxQuery("avg", 4, 0);
+        response = minMaxQuery("avg", 4, null);
 
         assertThat(response.getHits().totalHits(), equalTo(0l));
 
@@ -1932,87 +1927,6 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
         } catch (SearchPhaseExecutionException e) {
             assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'"));
         }
-
-        // HasChildFilter
-        response = minMaxFilter(0, 0);
-
-        assertThat(response.getHits().totalHits(), equalTo(3l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("2"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[1].id(), equalTo("3"));
-        assertThat(response.getHits().hits()[1].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[2].id(), equalTo("4"));
-        assertThat(response.getHits().hits()[2].score(), equalTo(1f));
-
-        response = minMaxFilter(1, 0);
-
-        assertThat(response.getHits().totalHits(), equalTo(3l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("2"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[1].id(), equalTo("3"));
-        assertThat(response.getHits().hits()[1].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[2].id(), equalTo("4"));
-        assertThat(response.getHits().hits()[2].score(), equalTo(1f));
-
-        response = minMaxFilter(2, 0);
-
-        assertThat(response.getHits().totalHits(), equalTo(2l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("3"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[1].id(), equalTo("4"));
-        assertThat(response.getHits().hits()[1].score(), equalTo(1f));
-
-        response = minMaxFilter(3, 0);
-
-        assertThat(response.getHits().totalHits(), equalTo(1l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("4"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-
-        response = minMaxFilter(4, 0);
-
-        assertThat(response.getHits().totalHits(), equalTo(0l));
-
-        response = minMaxFilter(0, 4);
-
-        assertThat(response.getHits().totalHits(), equalTo(3l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("2"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[1].id(), equalTo("3"));
-        assertThat(response.getHits().hits()[1].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[2].id(), equalTo("4"));
-        assertThat(response.getHits().hits()[2].score(), equalTo(1f));
-
-        response = minMaxFilter(0, 3);
-
-        assertThat(response.getHits().totalHits(), equalTo(3l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("2"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[1].id(), equalTo("3"));
-        assertThat(response.getHits().hits()[1].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[2].id(), equalTo("4"));
-        assertThat(response.getHits().hits()[2].score(), equalTo(1f));
-
-        response = minMaxFilter(0, 2);
-
-        assertThat(response.getHits().totalHits(), equalTo(2l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("2"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-        assertThat(response.getHits().hits()[1].id(), equalTo("3"));
-        assertThat(response.getHits().hits()[1].score(), equalTo(1f));
-
-        response = minMaxFilter(2, 2);
-
-        assertThat(response.getHits().totalHits(), equalTo(1l));
-        assertThat(response.getHits().hits()[0].id(), equalTo("3"));
-        assertThat(response.getHits().hits()[0].score(), equalTo(1f));
-
-        try {
-            response = minMaxFilter(3, 2);
-            fail();
-        } catch (SearchPhaseExecutionException e) {
-            assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'"));
-        }
-
     }
 
     @Test

+ 17 - 1
docs/reference/migration/migrate_3_0.asciidoc

@@ -71,4 +71,20 @@ with `_parent` field mapping created before version `2.0.0`. The data of these i
 The format of the join between parent and child documents have changed with the `2.0.0` release. The old
 format can't read from version `3.0.0` and onwards. The new format allows for a much more efficient and
 scalable join between parent and child documents and the join data structures are stored on on disk
-data structures as opposed as before the join data structures were stored in the jvm heap space.
+data structures as opposed as before the join data structures were stored in the jvm heap space.
+
+==== `score_type` has been removed
+
+The `score_type` option has been removed from the `has_child` and `has_parent` queries in favour of the `score_mode` option
+which does the exact same thing.
+
+==== `sum` score mode removed
+
+The `sum` score mode has been removed in favour of the `total` mode which doesn the same and is already available in
+previous versions.
+
+==== `max_children` option
+
+When `max_children` was set to `0` on the `has_child` query then there was no upper limit on how many children documents
+are allowed to match. This has changed and `0` now really means to zero child documents are allowed. If no upper limit
+is needed then the `max_children` option shouldn't be defined at all on the `has_child` query.

+ 2 - 2
docs/reference/query-dsl/has-child-query.asciidoc

@@ -23,9 +23,9 @@ an example:
 ==== Scoring capabilities
 
 The `has_child` also has scoring support. The
-supported score types are `min`, `max`, `sum`, `avg` or `none`. The default is
+supported score modes are `min`, `max`, `total`, `avg` or `none`. The default is
 `none` and yields the same behaviour as in previous versions. If the
-score type is set to another value than `none`, the scores of all the
+score mode is set to another value than `none`, the scores of all the
 matching child documents are aggregated into the associated parent
 documents. The score type can be specified with the `score_mode` field
 inside the `has_child` query:

+ 1 - 1
docs/reference/query-dsl/has-parent-query.asciidoc

@@ -30,7 +30,7 @@ this ignores the score from the parent document. The score is in this
 case equal to the boost on the `has_parent` query (Defaults to 1). If
 the score type is set to `score`, then the score of the matching parent
 document is aggregated into the child documents belonging to the
-matching parent document. The score type can be specified with the
+matching parent document. The score mode can be specified with the
 `score_mode` field inside the `has_parent` query:
 
 [source,js]