diff --git a/build.gradle b/build.gradle index 09748ea1e8a..31784a1798a 100644 --- a/build.gradle +++ b/build.gradle @@ -138,6 +138,7 @@ subprojects { "org.elasticsearch.plugin:transport-netty4-client:${version}": ':modules:transport-netty4', "org.elasticsearch.plugin:reindex-client:${version}": ':modules:reindex', "org.elasticsearch.plugin:lang-mustache-client:${version}": ':modules:lang-mustache', + "org.elasticsearch.plugin:parent-join-client:${version}": ':modules:parent-join', "org.elasticsearch.plugin:percolator-client:${version}": ':modules:percolator', ] project.afterEvaluate { diff --git a/buildSrc/src/main/resources/checkstyle_suppressions.xml b/buildSrc/src/main/resources/checkstyle_suppressions.xml index 9a550740fde..4acd927fff1 100644 --- a/buildSrc/src/main/resources/checkstyle_suppressions.xml +++ b/buildSrc/src/main/resources/checkstyle_suppressions.xml @@ -620,7 +620,6 @@ - @@ -689,7 +688,6 @@ - @@ -716,7 +714,6 @@ - diff --git a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/QueryDSLDocumentationTests.java b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/QueryDSLDocumentationTests.java index f01e4824b3f..f48572b0473 100644 --- a/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/QueryDSLDocumentationTests.java +++ b/client/rest-high-level/src/test/java/org/elasticsearch/client/documentation/QueryDSLDocumentationTests.java @@ -51,8 +51,6 @@ import static org.elasticsearch.index.query.QueryBuilders.geoBoundingBoxQuery; import static org.elasticsearch.index.query.QueryBuilders.geoDistanceQuery; import static org.elasticsearch.index.query.QueryBuilders.geoPolygonQuery; import static org.elasticsearch.index.query.QueryBuilders.geoShapeQuery; -import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; -import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.idsQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; @@ -216,24 +214,6 @@ public class QueryDSLDocumentationTests extends ESTestCase { } } - public void testHasChild() { - // tag::has_child - hasChildQuery( - "blog_tag", // <1> - termQuery("tag","something"), // <2> - ScoreMode.None); // <3> - // end::has_child - } - - public void testHasParent() { - // tag::has_parent - hasParentQuery( - "blog", // <1> - termQuery("tag","something"), // <2> - false); // <3> - // end::has_parent - } - public void testIds() { // tag::ids idsQuery("my_type", "type2") diff --git a/client/transport/build.gradle b/client/transport/build.gradle index 77833c1f267..b2edc9c8fcd 100644 --- a/client/transport/build.gradle +++ b/client/transport/build.gradle @@ -31,6 +31,7 @@ dependencies { compile "org.elasticsearch.plugin:reindex-client:${version}" compile "org.elasticsearch.plugin:lang-mustache-client:${version}" compile "org.elasticsearch.plugin:percolator-client:${version}" + compile "org.elasticsearch.plugin:parent-join-client:${version}" testCompile "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}" testCompile "junit:junit:${versions.junit}" testCompile "org.hamcrest:hamcrest-all:${versions.hamcrest}" diff --git a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java index dd23429dbdb..b6eb84b03b7 100644 --- a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java @@ -195,7 +195,8 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl } } - InnerHitBuilder(InnerHitBuilder other, QueryBuilder query, String parentChildType, boolean ignoreUnmapped) { + // NORELEASE Do not use this ctr, it is public for hasChild and hasParent query but this is temporary + public InnerHitBuilder(InnerHitBuilder other, QueryBuilder query, String parentChildType, boolean ignoreUnmapped) { this(other); this.query = query; this.parentChildType = parentChildType; @@ -751,7 +752,8 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl } } - static InnerHitBuilder rewrite(InnerHitBuilder original, QueryBuilder rewrittenQuery) { + // TODO public for hasParent and hasChild query + public static InnerHitBuilder rewrite(InnerHitBuilder original, QueryBuilder rewrittenQuery) { if (original == null) { return null; } diff --git a/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java b/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java index b0c49a3f4a8..2d23f256f06 100644 --- a/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java +++ b/core/src/main/java/org/elasticsearch/index/query/NestedQueryBuilder.java @@ -23,7 +23,6 @@ import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.search.join.BitSetProducer; import org.apache.lucene.search.join.ScoreMode; -import org.apache.lucene.search.join.ToParentBlockJoinQuery; import org.elasticsearch.common.ParseField; import org.elasticsearch.common.ParsingException; import org.elasticsearch.common.io.stream.StreamInput; @@ -36,6 +35,7 @@ import org.elasticsearch.index.search.ESToParentBlockJoinQuery; import org.elasticsearch.index.search.NestedHelper; import java.io.IOException; +import java.util.Locale; import java.util.Map; import java.util.Objects; @@ -144,7 +144,7 @@ public class NestedQueryBuilder extends AbstractQueryBuilder builder.field(PATH_FIELD.getPreferredName(), path); builder.field(IGNORE_UNMAPPED_FIELD.getPreferredName(), ignoreUnmapped); if (scoreMode != null) { - builder.field(SCORE_MODE_FIELD.getPreferredName(), HasChildQueryBuilder.scoreModeAsString(scoreMode)); + builder.field(SCORE_MODE_FIELD.getPreferredName(), scoreModeAsString(scoreMode)); } printBoostAndQueryName(builder); if (innerHitBuilder != null) { @@ -183,7 +183,7 @@ public class NestedQueryBuilder extends AbstractQueryBuilder } else if (IGNORE_UNMAPPED_FIELD.match(currentFieldName)) { ignoreUnmapped = parser.booleanValue(); } else if (SCORE_MODE_FIELD.match(currentFieldName)) { - scoreMode = HasChildQueryBuilder.parseScoreMode(parser.text()); + scoreMode = parseScoreMode(parser.text()); } else if (AbstractQueryBuilder.NAME_FIELD.match(currentFieldName)) { queryName = parser.text(); } else { @@ -201,6 +201,30 @@ public class NestedQueryBuilder extends AbstractQueryBuilder return queryBuilder; } + 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 ("sum".equals(scoreModeString)) { + return ScoreMode.Total; + } + throw new IllegalArgumentException("No score mode for child query [" + scoreModeString + "] found"); + } + + public static String scoreModeAsString(ScoreMode scoreMode) { + if (scoreMode == ScoreMode.Total) { + // Lucene uses 'total' but 'sum' is more consistent with other elasticsearch APIs + return "sum"; + } else { + return scoreMode.name().toLowerCase(Locale.ROOT); + } + } + @Override public final String getWriteableName() { return NAME; diff --git a/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java b/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java index 805ec5fa782..df0493d61c8 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java @@ -471,30 +471,6 @@ public abstract class QueryBuilders { return moreLikeThisQuery(null, null, likeItems); } - /** - * Constructs a new has_child query, with the child type and the query to run on the child documents. The - * results of this query are the parent docs that those child docs matched. - * - * @param type The child type. - * @param query The query. - * @param scoreMode How the scores from the children hits should be aggregated into the parent hit. - */ - public static HasChildQueryBuilder hasChildQuery(String type, QueryBuilder query, ScoreMode scoreMode) { - return new HasChildQueryBuilder(type, query, scoreMode); - } - - /** - * Constructs a new parent query, with the parent type and the query to run on the parent documents. The - * results of this query are the children docs that those parent docs matched. - * - * @param type The parent type. - * @param query The query. - * @param score Whether the score from the parent hit should propagate to the child hit - */ - public static HasParentQueryBuilder hasParentQuery(String type, QueryBuilder query, boolean score) { - return new HasParentQueryBuilder(type, query, score); - } - /** * Constructs a new parent id query that returns all child documents of the specified type that * point to the specified id. diff --git a/core/src/main/java/org/elasticsearch/search/SearchModule.java b/core/src/main/java/org/elasticsearch/search/SearchModule.java index 8707d851d3a..85308f0c249 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchModule.java +++ b/core/src/main/java/org/elasticsearch/search/SearchModule.java @@ -20,8 +20,6 @@ package org.elasticsearch.search; import org.apache.lucene.search.BooleanQuery; -import org.elasticsearch.action.search.SearchRequest; -import org.elasticsearch.action.search.SearchResponse; import org.elasticsearch.common.NamedRegistry; import org.elasticsearch.common.geo.ShapesAvailability; import org.elasticsearch.common.geo.builders.ShapeBuilders; @@ -45,8 +43,6 @@ import org.elasticsearch.index.query.GeoBoundingBoxQueryBuilder; import org.elasticsearch.index.query.GeoDistanceQueryBuilder; import org.elasticsearch.index.query.GeoPolygonQueryBuilder; import org.elasticsearch.index.query.GeoShapeQueryBuilder; -import org.elasticsearch.index.query.HasChildQueryBuilder; -import org.elasticsearch.index.query.HasParentQueryBuilder; import org.elasticsearch.index.query.IdsQueryBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.MatchNoneQueryBuilder; @@ -103,8 +99,6 @@ import org.elasticsearch.search.aggregations.InternalAggregation; import org.elasticsearch.search.aggregations.PipelineAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrixAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.adjacency.InternalAdjacencyMatrix; -import org.elasticsearch.search.aggregations.bucket.children.ChildrenAggregationBuilder; -import org.elasticsearch.search.aggregations.bucket.children.InternalChildren; import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.filter.InternalFilter; import org.elasticsearch.search.aggregations.bucket.filters.FiltersAggregationBuilder; @@ -256,7 +250,6 @@ import org.elasticsearch.search.suggest.term.TermSuggestionBuilder; import java.util.ArrayList; import java.util.List; import java.util.Map; -import java.util.function.BiConsumer; import java.util.function.Consumer; import java.util.function.Function; @@ -410,9 +403,6 @@ public class SearchModule { GeoCentroidAggregationBuilder::parse).addResultReader(InternalGeoCentroid::new)); registerAggregation(new AggregationSpec(ScriptedMetricAggregationBuilder.NAME, ScriptedMetricAggregationBuilder::new, ScriptedMetricAggregationBuilder::parse).addResultReader(InternalScriptedMetric::new)); - registerAggregation(new AggregationSpec(ChildrenAggregationBuilder.NAME, ChildrenAggregationBuilder::new, - ChildrenAggregationBuilder::parse).addResultReader(InternalChildren::new)); - registerFromPlugin(plugins, SearchPlugin::getAggregations, this::registerAggregation); } @@ -706,8 +696,6 @@ public class SearchModule { MatchPhrasePrefixQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MultiMatchQueryBuilder.NAME, MultiMatchQueryBuilder::new, MultiMatchQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(NestedQueryBuilder.NAME, NestedQueryBuilder::new, NestedQueryBuilder::fromXContent)); - registerQuery(new QuerySpec<>(HasChildQueryBuilder.NAME, HasChildQueryBuilder::new, HasChildQueryBuilder::fromXContent)); - registerQuery(new QuerySpec<>(HasParentQueryBuilder.NAME, HasParentQueryBuilder::new, HasParentQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(DisMaxQueryBuilder.NAME, DisMaxQueryBuilder::new, DisMaxQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(IdsQueryBuilder.NAME, IdsQueryBuilder::new, IdsQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MatchAllQueryBuilder.NAME, MatchAllQueryBuilder::new, MatchAllQueryBuilder::fromXContent)); diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java b/core/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java index f43c2670abd..8b704ee8a69 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java +++ b/core/src/main/java/org/elasticsearch/search/aggregations/AggregationBuilders.java @@ -23,8 +23,6 @@ import org.elasticsearch.common.geo.GeoPoint; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrix; import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrixAggregationBuilder; -import org.elasticsearch.search.aggregations.bucket.children.Children; -import org.elasticsearch.search.aggregations.bucket.children.ChildrenAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.filter.Filter; import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder; import org.elasticsearch.search.aggregations.bucket.filters.Filters; @@ -163,20 +161,20 @@ public class AggregationBuilders { public static FiltersAggregationBuilder filters(String name, QueryBuilder... filters) { return new FiltersAggregationBuilder(name, filters); } - + /** * Create a new {@link AdjacencyMatrix} aggregation with the given name. */ public static AdjacencyMatrixAggregationBuilder adjacencyMatrix(String name, Map filters) { return new AdjacencyMatrixAggregationBuilder(name, filters); - } - + } + /** * Create a new {@link AdjacencyMatrix} aggregation with the given name and separator */ public static AdjacencyMatrixAggregationBuilder adjacencyMatrix(String name, String separator, Map filters) { return new AdjacencyMatrixAggregationBuilder(name, separator, filters); - } + } /** * Create a new {@link Sampler} aggregation with the given name. @@ -220,13 +218,6 @@ public class AggregationBuilders { return new ReverseNestedAggregationBuilder(name); } - /** - * Create a new {@link Children} aggregation with the given name. - */ - public static ChildrenAggregationBuilder children(String name, String childType) { - return new ChildrenAggregationBuilder(name, childType); - } - /** * Create a new {@link GeoDistance} aggregation with the given name. */ diff --git a/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/CustomQueryScorer.java b/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/CustomQueryScorer.java index e25e7b74941..2f728e21b6f 100644 --- a/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/CustomQueryScorer.java +++ b/core/src/main/java/org/elasticsearch/search/fetch/subphase/highlight/CustomQueryScorer.java @@ -26,7 +26,6 @@ import org.apache.lucene.search.highlight.WeightedSpanTerm; import org.apache.lucene.search.highlight.WeightedSpanTermExtractor; import org.elasticsearch.common.lucene.search.function.FiltersFunctionScoreQuery; import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery; -import org.elasticsearch.index.query.HasChildQueryBuilder; import java.io.IOException; import java.util.Map; @@ -83,7 +82,7 @@ public final class CustomQueryScorer extends QueryScorer { } protected void extract(Query query, float boost, Map terms) throws IOException { - if (query instanceof HasChildQueryBuilder.LateParsingQuery) { + if (isChildOrParentQuery(query.getClass())) { // skip has_child or has_parent queries, see: https://github.com/elastic/elasticsearch/issues/14999 return; } else if (query instanceof FunctionScoreQuery) { @@ -94,5 +93,13 @@ public final class CustomQueryScorer extends QueryScorer { super.extract(query, boost, terms); } } + + /** + * Workaround to detect parent/child query + */ + private static final String PARENT_CHILD_QUERY_NAME = "HasChildQueryBuilder$LateParsingQuery"; + private static boolean isChildOrParentQuery(Class clazz) { + return clazz.getName().endsWith(PARENT_CHILD_QUERY_NAME); + } } } diff --git a/core/src/test/java/org/elasticsearch/action/bulk/BulkWithUpdatesIT.java b/core/src/test/java/org/elasticsearch/action/bulk/BulkWithUpdatesIT.java index 21930b3763b..cf41042ab8c 100644 --- a/core/src/test/java/org/elasticsearch/action/bulk/BulkWithUpdatesIT.java +++ b/core/src/test/java/org/elasticsearch/action/bulk/BulkWithUpdatesIT.java @@ -450,156 +450,7 @@ public class BulkWithUpdatesIT extends ESIntegTestCase { assertHitCount(countResponse, numDocs); } - /* - Test for https://github.com/elastic/elasticsearch/issues/3444 - */ - public void testBulkUpdateDocAsUpsertWithParent() throws Exception { - client().admin().indices().prepareCreate("test") - .setSettings("index.mapping.single_type", false) - .addMapping("parent", "{\"parent\":{}}", XContentType.JSON) - .addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON) - .execute().actionGet(); - ensureGreen(); - BulkRequestBuilder builder = client().prepareBulk(); - - // It's important to use JSON parsing here and request objects: issue 3444 is related to incomplete option parsing - byte[] addParent = new BytesArray( - "{" + - " \"index\" : {" + - " \"_index\" : \"test\"," + - " \"_type\" : \"parent\"," + - " \"_id\" : \"parent1\"" + - " }" + - "}" + - "\n" + - "{" + - " \"field1\" : \"value1\"" + - "}" + - "\n").array(); - - byte[] addChild = new BytesArray( - "{" + - " \"update\" : {" + - " \"_index\" : \"test\"," + - " \"_type\" : \"child\"," + - " \"_id\" : \"child1\"," + - " \"parent\" : \"parent1\"" + - " }" + - "}" + - "\n" + - "{" + - " \"doc\" : {" + - " \"field1\" : \"value1\"" + - " }," + - " \"doc_as_upsert\" : \"true\"" + - "}" + - "\n").array(); - - builder.add(addParent, 0, addParent.length, XContentType.JSON); - builder.add(addChild, 0, addChild.length, XContentType.JSON); - - BulkResponse bulkResponse = builder.get(); - assertThat(bulkResponse.getItems().length, equalTo(2)); - assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false)); - assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false)); - - client().admin().indices().prepareRefresh("test").get(); - - //we check that the _parent field was set on the child document by using the has parent query - SearchResponse searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.hasParentQuery("parent", QueryBuilders.matchAllQuery(), false)) - .get(); - - assertNoFailures(searchResponse); - assertSearchHits(searchResponse, "child1"); - } - - /* - Test for https://github.com/elastic/elasticsearch/issues/3444 - */ - public void testBulkUpdateUpsertWithParent() throws Exception { - assertAcked(prepareCreate("test") - .setSettings("index.mapping.single_type", false) - .addMapping("parent", "{\"parent\":{}}", XContentType.JSON) - .addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON)); - ensureGreen(); - - BulkRequestBuilder builder = client().prepareBulk(); - - byte[] addParent = new BytesArray( - "{" + - " \"index\" : {" + - " \"_index\" : \"test\"," + - " \"_type\" : \"parent\"," + - " \"_id\" : \"parent1\"" + - " }" + - "}" + - "\n" + - "{" + - " \"field1\" : \"value1\"" + - "}" + - "\n").array(); - - byte[] addChild1 = new BytesArray( - "{" + - " \"update\" : {" + - " \"_index\" : \"test\"," + - " \"_type\" : \"child\"," + - " \"_id\" : \"child1\"," + - " \"parent\" : \"parent1\"" + - " }" + - "}" + - "\n" + - "{" + - " \"script\" : {" + - " \"inline\" : \"ctx._source.field2 = 'value2'\"" + - " }," + - " \"lang\" : \"" + CustomScriptPlugin.NAME + "\"," + - " \"upsert\" : {" + - " \"field1\" : \"value1'\"" + - " }" + - "}" + - "\n").array(); - - byte[] addChild2 = new BytesArray( - "{" + - " \"update\" : {" + - " \"_index\" : \"test\"," + - " \"_type\" : \"child\"," + - " \"_id\" : \"child1\"," + - " \"parent\" : \"parent1\"" + - " }" + - "}" + - "\n" + - "{" + - " \"script\" : \"ctx._source.field2 = 'value2'\"," + - " \"upsert\" : {" + - " \"field1\" : \"value1'\"" + - " }" + - "}" + - "\n").array(); - - builder.add(addParent, 0, addParent.length, XContentType.JSON); - builder.add(addChild1, 0, addChild1.length, XContentType.JSON); - builder.add(addChild2, 0, addChild2.length, XContentType.JSON); - - BulkResponse bulkResponse = builder.get(); - assertThat(bulkResponse.getItems().length, equalTo(3)); - assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false)); - assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false)); - assertThat(bulkResponse.getItems()[2].isFailed(), equalTo(true)); - assertThat(bulkResponse.getItems()[2].getFailure().getCause().getCause().getMessage(), - equalTo("script_lang not supported [painless]")); - - client().admin().indices().prepareRefresh("test").get(); - - SearchResponse searchResponse = client().prepareSearch("test") - .setQuery(QueryBuilders.hasParentQuery("parent", QueryBuilders.matchAllQuery(), false)) - .get(); - - assertSearchHits(searchResponse, "child1"); - } /* * Test for https://github.com/elastic/elasticsearch/issues/8365 diff --git a/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java b/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java index 711804153cf..e711117fb6e 100644 --- a/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java +++ b/core/src/test/java/org/elasticsearch/aliases/IndexAliasesIT.java @@ -63,8 +63,6 @@ import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_ME import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_READ; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_WRITE; import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_READ_ONLY; -import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; -import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.rangeQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; @@ -824,27 +822,6 @@ public class IndexAliasesIT extends ESIntegTestCase { } } - public void testAliasesFilterWithHasChildQuery() throws Exception { - assertAcked(prepareCreate("my-index") - .setSettings("index.mapping.single_type", false) - .addMapping("parent") - .addMapping("child", "_parent", "type=parent") - ); - client().prepareIndex("my-index", "parent", "1").setSource("{}", XContentType.JSON).get(); - client().prepareIndex("my-index", "child", "2").setSource("{}", XContentType.JSON).setParent("1").get(); - refresh(); - - assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter1", hasChildQuery("child", matchAllQuery(), ScoreMode.None))); - assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter2", hasParentQuery("parent", matchAllQuery(), false))); - - SearchResponse response = client().prepareSearch("filter1").get(); - assertHitCount(response, 1); - assertThat(response.getHits().getAt(0).getId(), equalTo("1")); - response = client().prepareSearch("filter2").get(); - assertHitCount(response, 1); - assertThat(response.getHits().getAt(0).getId(), equalTo("2")); - } - public void testAliasesWithBlocks() { createIndex("test"); ensureGreen(); diff --git a/core/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java index cd6622368c9..9e199f71cea 100644 --- a/core/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/InnerHitBuilderTests.java @@ -153,24 +153,6 @@ public class InnerHitBuilderTests extends ESTestCase { assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue()); } - public void testInlineLeafInnerHitsHasChildQuery() throws Exception { - InnerHitBuilder leafInnerHits = randomInnerHits(); - HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None) - .innerHit(leafInnerHits, false); - Map innerHitBuilders = new HashMap<>(); - hasChildQueryBuilder.extractInnerHitBuilders(innerHitBuilders); - assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue()); - } - - public void testInlineLeafInnerHitsHasParentQuery() throws Exception { - InnerHitBuilder leafInnerHits = randomInnerHits(); - HasParentQueryBuilder hasParentQueryBuilder = new HasParentQueryBuilder("type", new MatchAllQueryBuilder(), false) - .innerHit(leafInnerHits, false); - Map innerHitBuilders = new HashMap<>(); - hasParentQueryBuilder.extractInnerHitBuilders(innerHitBuilders); - assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue()); - } - public void testInlineLeafInnerHitsNestedQueryViaBoolQuery() { InnerHitBuilder leafInnerHits = randomInnerHits(); NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("path", new MatchAllQueryBuilder(), ScoreMode.None) @@ -181,25 +163,6 @@ public class InnerHitBuilderTests extends ESTestCase { assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue()); } - public void testInlineLeafInnerHitsNestedQueryViaDisMaxQuery() { - InnerHitBuilder leafInnerHits1 = randomInnerHits(); - NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("path", new MatchAllQueryBuilder(), ScoreMode.None) - .innerHit(leafInnerHits1, false); - - InnerHitBuilder leafInnerHits2 = randomInnerHits(); - HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None) - .innerHit(leafInnerHits2, false); - - DisMaxQueryBuilder disMaxQueryBuilder = new DisMaxQueryBuilder(); - disMaxQueryBuilder.add(nestedQueryBuilder); - disMaxQueryBuilder.add(hasChildQueryBuilder); - Map innerHitBuilders = new HashMap<>(); - disMaxQueryBuilder.extractInnerHitBuilders(innerHitBuilders); - assertThat(innerHitBuilders.size(), equalTo(2)); - assertThat(innerHitBuilders.get(leafInnerHits1.getName()), notNullValue()); - assertThat(innerHitBuilders.get(leafInnerHits2.getName()), notNullValue()); - } - public void testInlineLeafInnerHitsNestedQueryViaConstantScoreQuery() { InnerHitBuilder leafInnerHits = randomInnerHits(); NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("path", new MatchAllQueryBuilder(), ScoreMode.None) @@ -252,43 +215,6 @@ public class InnerHitBuilderTests extends ESTestCase { assertThat(innerHitsContext.getInnerHits().size(), equalTo(0)); } - public void testBuild_ignoreUnmappedHasChildQuery() throws Exception { - QueryShardContext queryShardContext = mock(QueryShardContext.class); - when(queryShardContext.documentMapper("type")).thenReturn(null); - SearchContext searchContext = mock(SearchContext.class); - when(searchContext.getQueryShardContext()).thenReturn(queryShardContext); - - InnerHitBuilder leafInnerHits = randomInnerHits(); - HasChildQueryBuilder query1 = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None) - .innerHit(leafInnerHits, false); - expectThrows(IllegalStateException.class, () -> query1.innerHit().build(searchContext, new InnerHitsContext())); - - HasChildQueryBuilder query2 = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None) - .innerHit(leafInnerHits, true); - InnerHitsContext innerHitsContext = new InnerHitsContext(); - query2.innerHit().build(searchContext, innerHitsContext); - assertThat(innerHitsContext.getInnerHits().size(), equalTo(0)); - } - - public void testBuild_ingoreUnmappedHasParentQuery() throws Exception { - QueryShardContext queryShardContext = mock(QueryShardContext.class); - when(queryShardContext.documentMapper("type")).thenReturn(null); - SearchContext searchContext = mock(SearchContext.class); - when(searchContext.getQueryShardContext()).thenReturn(queryShardContext); - - InnerHitBuilder leafInnerHits = randomInnerHits(); - HasParentQueryBuilder query1 = new HasParentQueryBuilder("type", new MatchAllQueryBuilder(), false) - .innerHit(leafInnerHits, false); - expectThrows(IllegalStateException.class, () -> query1.innerHit().build(searchContext, new InnerHitsContext())); - - HasParentQueryBuilder query2 = new HasParentQueryBuilder("type", new MatchAllQueryBuilder(), false) - .innerHit(leafInnerHits, true); - InnerHitsContext innerHitsContext = new InnerHitsContext(); - query2.innerHit().build(searchContext, innerHitsContext); - assertThat(innerHitsContext.getInnerHits().size(), equalTo(0)); - } - - public static InnerHitBuilder randomInnerHits() { return randomInnerHits(true, true); } diff --git a/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java index 267963878ea..ed4fbcd53cd 100644 --- a/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java @@ -61,7 +61,7 @@ public class NestedQueryBuilderTests extends AbstractQueryTestCase NestedQueryBuilder.parseScoreMode(null)); + assertEquals("No score mode for child query [null] found", e.getMessage()); + } + + /** + * Failure should not change (and the value should never match anything...). + */ + public void testThatUnrecognizedFromStringThrowsException() { + IllegalArgumentException e = expectThrows(IllegalArgumentException.class, + () -> NestedQueryBuilder.parseScoreMode("unrecognized value")); + assertEquals("No score mode for child query [unrecognized value] found", e.getMessage()); + } } diff --git a/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java b/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java index 8514096b837..96767c99b9d 100644 --- a/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java +++ b/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java @@ -270,8 +270,6 @@ public class SearchModuleTests extends ModuleTestCase { "geo_distance", "geo_polygon", "geo_shape", - "has_child", - "has_parent", "ids", "match", "match_all", diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/filter/InternalFilterTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/filter/InternalFilterTests.java index 3e74b9c2187..464f081f6c9 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/filter/InternalFilterTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/filter/InternalFilterTests.java @@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.filter; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase; +import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.List; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/global/InternalGlobalTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/global/InternalGlobalTests.java index 9092c3e0280..2a284746bf6 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/global/InternalGlobalTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/global/InternalGlobalTests.java @@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.global; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase; +import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.List; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/missing/InternalMissingTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/missing/InternalMissingTests.java index f3e151721bf..1a702e94024 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/missing/InternalMissingTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/missing/InternalMissingTests.java @@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.missing; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase; +import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.List; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalNestedTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalNestedTests.java index 7b410723666..a330c8a146e 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalNestedTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalNestedTests.java @@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.nested; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase; +import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.List; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalReverseNestedTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalReverseNestedTests.java index f918024733e..069ac038295 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalReverseNestedTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/nested/InternalReverseNestedTests.java @@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.nested; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase; +import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.List; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/sampler/InternalSamplerTests.java b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/sampler/InternalSamplerTests.java index 1c4fb6d2a65..23facaf8fd2 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/sampler/InternalSamplerTests.java +++ b/core/src/test/java/org/elasticsearch/search/aggregations/bucket/sampler/InternalSamplerTests.java @@ -20,7 +20,7 @@ package org.elasticsearch.search.aggregations.bucket.sampler; import org.elasticsearch.common.io.stream.Writeable; import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase; +import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.List; @@ -42,4 +42,4 @@ public class InternalSamplerTests extends InternalSingleBucketAggregationTestCas protected Writeable.Reader instanceReader() { return InternalSampler::new; } -} \ No newline at end of file +} diff --git a/core/src/test/java/org/elasticsearch/search/fetch/subphase/InnerHitsIT.java b/core/src/test/java/org/elasticsearch/search/fetch/subphase/InnerHitsIT.java index 6fbda92ba26..8eca5055646 100644 --- a/core/src/test/java/org/elasticsearch/search/fetch/subphase/InnerHitsIT.java +++ b/core/src/test/java/org/elasticsearch/search/fetch/subphase/InnerHitsIT.java @@ -55,8 +55,6 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; -import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; -import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.nestedQuery; @@ -246,268 +244,6 @@ public class InnerHitsIT extends ESIntegTestCase { } } - public void testSimpleParentChild() throws Exception { - assertAcked(prepareCreate("articles") - .setSettings("index.mapping.single_type", false) - .addMapping("article", "title", "type=text") - .addMapping("comment", "_parent", "type=article", "message", "type=text,fielddata=true") - ); - - List requests = new ArrayList<>(); - requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox")); - requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick")); - requests.add(client().prepareIndex("articles", "comment", "2").setParent("1").setSource("message", "fox ate rabbit x y z")); - requests.add(client().prepareIndex("articles", "comment", "3").setParent("1").setSource("message", "rabbit got away")); - requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant")); - requests.add(client().prepareIndex("articles", "comment", "4").setParent("2").setSource("message", "elephant captured")); - requests.add(client().prepareIndex("articles", "comment", "5").setParent("2").setSource("message", "mice squashed by elephant x")); - requests.add(client().prepareIndex("articles", "comment", "6").setParent("2").setSource("message", "elephant scared by mice x y")); - indexRandom(true, requests); - - SearchResponse response = client().prepareSearch("articles") - .setQuery(hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None) - .innerHit(new InnerHitBuilder(), false)) - .get(); - assertNoFailures(response); - assertHitCount(response, 1); - assertSearchHit(response, 1, hasId("1")); - assertThat(response.getHits().getAt(0).getShard(), notNullValue()); - - assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); - SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); - assertThat(innerHits.getTotalHits(), equalTo(2L)); - - assertThat(innerHits.getAt(0).getId(), equalTo("1")); - assertThat(innerHits.getAt(0).getType(), equalTo("comment")); - assertThat(innerHits.getAt(1).getId(), equalTo("2")); - assertThat(innerHits.getAt(1).getType(), equalTo("comment")); - - response = client().prepareSearch("articles") - .setQuery(hasChildQuery("comment", matchQuery("message", "elephant"), ScoreMode.None) - .innerHit(new InnerHitBuilder(), false)) - .get(); - assertNoFailures(response); - assertHitCount(response, 1); - assertSearchHit(response, 1, hasId("2")); - - assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); - innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); - assertThat(innerHits.getTotalHits(), equalTo(3L)); - - assertThat(innerHits.getAt(0).getId(), equalTo("4")); - assertThat(innerHits.getAt(0).getType(), equalTo("comment")); - assertThat(innerHits.getAt(1).getId(), equalTo("5")); - assertThat(innerHits.getAt(1).getType(), equalTo("comment")); - assertThat(innerHits.getAt(2).getId(), equalTo("6")); - assertThat(innerHits.getAt(2).getType(), equalTo("comment")); - - response = client().prepareSearch("articles") - .setQuery( - hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None).innerHit( - new InnerHitBuilder() - .addDocValueField("message") - .setHighlightBuilder(new HighlightBuilder().field("message")) - .setExplain(true).setSize(1) - .addScriptField("script", new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5", - Collections.emptyMap())), - false) - ).get(); - assertNoFailures(response); - innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); - assertThat(innerHits.getHits().length, equalTo(1)); - assertThat(innerHits.getAt(0).getHighlightFields().get("message").getFragments()[0].string(), equalTo("fox eat quick")); - assertThat(innerHits.getAt(0).getExplanation().toString(), containsString("weight(message:fox")); - assertThat(innerHits.getAt(0).getFields().get("message").getValue().toString(), equalTo("eat")); - assertThat(innerHits.getAt(0).getFields().get("script").getValue().toString(), equalTo("5")); - } - - public void testRandomParentChild() throws Exception { - assertAcked(prepareCreate("idx") - .setSettings("index.mapping.single_type", false) - .addMapping("parent") - .addMapping("child1", "_parent", "type=parent") - .addMapping("child2", "_parent", "type=parent") - ); - int numDocs = scaledRandomIntBetween(5, 50); - List requestBuilders = new ArrayList<>(); - - int child1 = 0; - int child2 = 0; - int[] child1InnerObjects = new int[numDocs]; - int[] child2InnerObjects = new int[numDocs]; - for (int parent = 0; parent < numDocs; parent++) { - String parentId = String.format(Locale.ENGLISH, "%03d", parent); - requestBuilders.add(client().prepareIndex("idx", "parent", parentId).setSource("{}", XContentType.JSON)); - - int numChildDocs = child1InnerObjects[parent] = scaledRandomIntBetween(1, numDocs); - int limit = child1 + numChildDocs; - for (; child1 < limit; child1++) { - requestBuilders.add(client().prepareIndex("idx", "child1", - String.format(Locale.ENGLISH, "%04d", child1)).setParent(parentId).setSource("{}", XContentType.JSON)); - } - numChildDocs = child2InnerObjects[parent] = scaledRandomIntBetween(1, numDocs); - limit = child2 + numChildDocs; - for (; child2 < limit; child2++) { - requestBuilders.add(client().prepareIndex("idx", "child2", - String.format(Locale.ENGLISH, "%04d", child2)).setParent(parentId).setSource("{}", XContentType.JSON)); - } - } - indexRandom(true, requestBuilders); - - int size = randomIntBetween(0, numDocs); - BoolQueryBuilder boolQuery = new BoolQueryBuilder(); - boolQuery.should(constantScoreQuery(hasChildQuery("child1", matchAllQuery(), ScoreMode.None) - .innerHit(new InnerHitBuilder().setName("a") - .addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false))); - boolQuery.should(constantScoreQuery(hasChildQuery("child2", matchAllQuery(), ScoreMode.None) - .innerHit(new InnerHitBuilder().setName("b") - .addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false))); - SearchResponse searchResponse = client().prepareSearch("idx") - .setSize(numDocs) - .setTypes("parent") - .addSort("_uid", SortOrder.ASC) - .setQuery(boolQuery) - .get(); - - assertNoFailures(searchResponse); - assertHitCount(searchResponse, numDocs); - assertThat(searchResponse.getHits().getHits().length, equalTo(numDocs)); - - int offset1 = 0; - int offset2 = 0; - for (int parent = 0; parent < numDocs; parent++) { - SearchHit searchHit = searchResponse.getHits().getAt(parent); - assertThat(searchHit.getType(), equalTo("parent")); - assertThat(searchHit.getId(), equalTo(String.format(Locale.ENGLISH, "%03d", parent))); - assertThat(searchHit.getShard(), notNullValue()); - - SearchHits inner = searchHit.getInnerHits().get("a"); - assertThat(inner.getTotalHits(), equalTo((long) child1InnerObjects[parent])); - for (int child = 0; child < child1InnerObjects[parent] && child < size; child++) { - SearchHit innerHit = inner.getAt(child); - assertThat(innerHit.getType(), equalTo("child1")); - String childId = String.format(Locale.ENGLISH, "%04d", offset1 + child); - assertThat(innerHit.getId(), equalTo(childId)); - assertThat(innerHit.getNestedIdentity(), nullValue()); - } - offset1 += child1InnerObjects[parent]; - - inner = searchHit.getInnerHits().get("b"); - assertThat(inner.getTotalHits(), equalTo((long) child2InnerObjects[parent])); - for (int child = 0; child < child2InnerObjects[parent] && child < size; child++) { - SearchHit innerHit = inner.getAt(child); - assertThat(innerHit.getType(), equalTo("child2")); - String childId = String.format(Locale.ENGLISH, "%04d", offset2 + child); - assertThat(innerHit.getId(), equalTo(childId)); - assertThat(innerHit.getNestedIdentity(), nullValue()); - } - offset2 += child2InnerObjects[parent]; - } - } - - public void testInnerHitsOnHasParent() throws Exception { - assertAcked(prepareCreate("stack") - .setSettings("index.mapping.single_type", false) - .addMapping("question", "body", "type=text") - .addMapping("answer", "_parent", "type=question", "body", "type=text") - ); - List requests = new ArrayList<>(); - requests.add(client().prepareIndex("stack", "question", "1").setSource("body", "I'm using HTTPS + Basic authentication " - + "to protect a resource. How can I throttle authentication attempts to protect against brute force attacks?")); - requests.add(client().prepareIndex("stack", "answer", "1").setParent("1").setSource("body", - "install fail2ban and enable rules for apache")); - requests.add(client().prepareIndex("stack", "question", "2").setSource("body", - "I have firewall rules set up and also denyhosts installed.\\ndo I also need to install fail2ban?")); - requests.add(client().prepareIndex("stack", "answer", "2").setParent("2").setSource("body", - "Denyhosts protects only ssh; Fail2Ban protects all daemons.")); - indexRandom(true, requests); - - SearchResponse response = client().prepareSearch("stack") - .setTypes("answer") - .addSort("_uid", SortOrder.ASC) - .setQuery( - boolQuery() - .must(matchQuery("body", "fail2ban")) - .must(hasParentQuery("question", matchAllQuery(), false).innerHit(new InnerHitBuilder(), false)) - ).get(); - assertNoFailures(response); - assertHitCount(response, 2); - - SearchHit searchHit = response.getHits().getAt(0); - assertThat(searchHit.getId(), equalTo("1")); - assertThat(searchHit.getType(), equalTo("answer")); - assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L)); - assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question")); - assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("1")); - - searchHit = response.getHits().getAt(1); - assertThat(searchHit.getId(), equalTo("2")); - assertThat(searchHit.getType(), equalTo("answer")); - assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L)); - assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question")); - assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("2")); - } - - public void testParentChildMultipleLayers() throws Exception { - assertAcked(prepareCreate("articles") - .setSettings("index.mapping.single_type", false) - .addMapping("article", "title", "type=text") - .addMapping("comment", "_parent", "type=article", "message", "type=text") - .addMapping("remark", "_parent", "type=comment", "message", "type=text") - ); - - List requests = new ArrayList<>(); - requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox")); - requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick")); - requests.add(client().prepareIndex("articles", "remark", "1").setParent("1").setRouting("1").setSource("message", "good")); - requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant")); - requests.add(client().prepareIndex("articles", "comment", "2").setParent("2").setSource("message", "elephant captured")); - requests.add(client().prepareIndex("articles", "remark", "2").setParent("2").setRouting("2").setSource("message", "bad")); - indexRandom(true, requests); - - SearchResponse response = client().prepareSearch("articles") - .setQuery(hasChildQuery("comment", - hasChildQuery("remark", matchQuery("message", "good"), ScoreMode.None).innerHit(new InnerHitBuilder(), false), - ScoreMode.None).innerHit(new InnerHitBuilder(), false)) - .get(); - - assertNoFailures(response); - assertHitCount(response, 1); - assertSearchHit(response, 1, hasId("1")); - - assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); - SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); - assertThat(innerHits.getTotalHits(), equalTo(1L)); - assertThat(innerHits.getAt(0).getId(), equalTo("1")); - assertThat(innerHits.getAt(0).getType(), equalTo("comment")); - - innerHits = innerHits.getAt(0).getInnerHits().get("remark"); - assertThat(innerHits.getTotalHits(), equalTo(1L)); - assertThat(innerHits.getAt(0).getId(), equalTo("1")); - assertThat(innerHits.getAt(0).getType(), equalTo("remark")); - - response = client().prepareSearch("articles") - .setQuery(hasChildQuery("comment", - hasChildQuery("remark", matchQuery("message", "bad"), ScoreMode.None).innerHit(new InnerHitBuilder(), false), - ScoreMode.None).innerHit(new InnerHitBuilder(), false)) - .get(); - - assertNoFailures(response); - assertHitCount(response, 1); - assertSearchHit(response, 1, hasId("2")); - - assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); - innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); - assertThat(innerHits.getTotalHits(), equalTo(1L)); - assertThat(innerHits.getAt(0).getId(), equalTo("2")); - assertThat(innerHits.getAt(0).getType(), equalTo("comment")); - - innerHits = innerHits.getAt(0).getInnerHits().get("remark"); - assertThat(innerHits.getTotalHits(), equalTo(1L)); - assertThat(innerHits.getAt(0).getId(), equalTo("2")); - assertThat(innerHits.getAt(0).getType(), equalTo("remark")); - } - public void testNestedMultipleLayers() throws Exception { assertAcked(prepareCreate("articles").addMapping("article", jsonBuilder().startObject() .startObject("article").startObject("properties") @@ -724,92 +460,6 @@ public class InnerHitsIT extends ESIntegTestCase { assertThat(messages.getAt(0).getNestedIdentity().getChild(), nullValue()); } - public void testRoyals() throws Exception { - assertAcked( - prepareCreate("royals") - .setSettings("index.mapping.single_type", false) - .addMapping("king") - .addMapping("prince", "_parent", "type=king") - .addMapping("duke", "_parent", "type=prince") - .addMapping("earl", "_parent", "type=duke") - .addMapping("baron", "_parent", "type=earl") - ); - - List requests = new ArrayList<>(); - requests.add(client().prepareIndex("royals", "king", "king").setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "prince", "prince").setParent("king").setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "duke", "duke").setParent("prince").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "earl", "earl1").setParent("duke").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "earl", "earl2").setParent("duke").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "earl", "earl3").setParent("duke").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "earl", "earl4").setParent("duke").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "baron", "baron1").setParent("earl1").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "baron", "baron2").setParent("earl2").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "baron", "baron3").setParent("earl3").setRouting("king") - .setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("royals", "baron", "baron4").setParent("earl4").setRouting("king") - .setSource("{}", XContentType.JSON)); - indexRandom(true, requests); - - SearchResponse response = client().prepareSearch("royals") - .setTypes("duke") - .setQuery(boolQuery() - .filter(hasParentQuery("prince", - hasParentQuery("king", matchAllQuery(), false).innerHit(new InnerHitBuilder().setName("kings"), false), - false).innerHit(new InnerHitBuilder().setName("princes"), false) - ) - .filter(hasChildQuery("earl", - hasChildQuery("baron", matchAllQuery(), ScoreMode.None) - .innerHit(new InnerHitBuilder().setName("barons"), false), - ScoreMode.None).innerHit(new InnerHitBuilder() - .addSort(SortBuilders.fieldSort("_uid").order(SortOrder.ASC)) - .setName("earls") - .setSize(4), false) - ) - ) - .get(); - assertHitCount(response, 1); - assertThat(response.getHits().getAt(0).getId(), equalTo("duke")); - - SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("earls"); - assertThat(innerHits.getTotalHits(), equalTo(4L)); - assertThat(innerHits.getAt(0).getId(), equalTo("earl1")); - assertThat(innerHits.getAt(1).getId(), equalTo("earl2")); - assertThat(innerHits.getAt(2).getId(), equalTo("earl3")); - assertThat(innerHits.getAt(3).getId(), equalTo("earl4")); - - SearchHits innerInnerHits = innerHits.getAt(0).getInnerHits().get("barons"); - assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); - assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron1")); - - innerInnerHits = innerHits.getAt(1).getInnerHits().get("barons"); - assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); - assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron2")); - - innerInnerHits = innerHits.getAt(2).getInnerHits().get("barons"); - assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); - assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron3")); - - innerInnerHits = innerHits.getAt(3).getInnerHits().get("barons"); - assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); - assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron4")); - - innerHits = response.getHits().getAt(0).getInnerHits().get("princes"); - assertThat(innerHits.getTotalHits(), equalTo(1L)); - assertThat(innerHits.getAt(0).getId(), equalTo("prince")); - - innerInnerHits = innerHits.getAt(0).getInnerHits().get("kings"); - assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); - assertThat(innerInnerHits.getAt(0).getId(), equalTo("king")); - } - public void testMatchesQueriesNestedInnerHits() throws Exception { XContentBuilder builder = jsonBuilder().startObject() .startObject("type1") @@ -914,84 +564,6 @@ public class InnerHitsIT extends ESIntegTestCase { } } - public void testMatchesQueriesParentChildInnerHits() throws Exception { - assertAcked(prepareCreate("index") - .setSettings("index.mapping.single_type", false) - .addMapping("child", "_parent", "type=parent")); - List requests = new ArrayList<>(); - requests.add(client().prepareIndex("index", "parent", "1").setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("index", "child", "1").setParent("1").setSource("field", "value1")); - requests.add(client().prepareIndex("index", "child", "2").setParent("1").setSource("field", "value2")); - requests.add(client().prepareIndex("index", "parent", "2").setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("index", "child", "3").setParent("2").setSource("field", "value1")); - indexRandom(true, requests); - - SearchResponse response = client().prepareSearch("index") - .setQuery(hasChildQuery("child", matchQuery("field", "value1").queryName("_name1"), ScoreMode.None) - .innerHit(new InnerHitBuilder(), false)) - .addSort("_uid", SortOrder.ASC) - .get(); - assertHitCount(response, 2); - assertThat(response.getHits().getAt(0).getId(), equalTo("1")); - assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L)); - assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1)); - assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1")); - - assertThat(response.getHits().getAt(1).getId(), equalTo("2")); - assertThat(response.getHits().getAt(1).getInnerHits().get("child").getTotalHits(), equalTo(1L)); - assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1)); - assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1")); - - QueryBuilder query = hasChildQuery("child", matchQuery("field", "value2").queryName("_name2"), ScoreMode.None) - .innerHit(new InnerHitBuilder(), false); - response = client().prepareSearch("index") - .setQuery(query) - .addSort("_uid", SortOrder.ASC) - .get(); - assertHitCount(response, 1); - assertThat(response.getHits().getAt(0).getId(), equalTo("1")); - assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L)); - assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1)); - assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name2")); - } - - public void testDontExplode() throws Exception { - assertAcked(prepareCreate("index1") - .setSettings("index.mapping.single_type", false) - .addMapping("child", "_parent", "type=parent")); - List requests = new ArrayList<>(); - requests.add(client().prepareIndex("index1", "parent", "1").setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("index1", "child", "1").setParent("1").setSource("field", "value1")); - indexRandom(true, requests); - - QueryBuilder query = hasChildQuery("child", matchQuery("field", "value1"), ScoreMode.None) - .innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false); - SearchResponse response = client().prepareSearch("index1") - .setQuery(query) - .get(); - assertNoFailures(response); - assertHitCount(response, 1); - - assertAcked(prepareCreate("index2").addMapping("type", "nested", "type=nested")); - client().prepareIndex("index2", "type", "1").setSource(jsonBuilder().startObject() - .startArray("nested") - .startObject() - .field("field", "value1") - .endObject() - .endArray() - .endObject()) - .setRefreshPolicy(IMMEDIATE) - .get(); - - query = nestedQuery("nested", matchQuery("nested.field", "value1"), ScoreMode.Avg) - .innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false); - response = client().prepareSearch("index2") - .setQuery(query) - .get(); - assertNoFailures(response); - assertHitCount(response, 1); - } - public void testNestedSourceFiltering() throws Exception { assertAcked(prepareCreate("index1").addMapping("message", "comments", "type=nested")); client().prepareIndex("index1", "message", "1").setSource(jsonBuilder().startObject() @@ -1021,25 +593,6 @@ public class InnerHitsIT extends ESIntegTestCase { equalTo("fox ate rabbit x y z")); } - public void testNestedInnerHitWrappedInParentChildInnerhit() throws Exception { - assertAcked(prepareCreate("test") - .setSettings("index.mapping.single_type", false) - .addMapping("child_type", "_parent", "type=parent_type", "nested_type", "type=nested")); - client().prepareIndex("test", "parent_type", "1").setSource("key", "value").get(); - client().prepareIndex("test", "child_type", "2").setParent("1").setSource("nested_type", Collections.singletonMap("key", "value")) - .get(); - refresh(); - SearchResponse response = client().prepareSearch("test") - .setQuery(boolQuery().must(matchQuery("key", "value")) - .should(hasChildQuery("child_type", nestedQuery("nested_type", matchAllQuery(), ScoreMode.None) - .innerHit(new InnerHitBuilder(), false), ScoreMode.None).innerHit(new InnerHitBuilder(), false))) - .get(); - assertHitCount(response, 1); - SearchHit hit = response.getHits().getAt(0); - assertThat(hit.getInnerHits().get("child_type").getAt(0).field("_parent").getValue(), equalTo("1")); - assertThat(hit.getInnerHits().get("child_type").getAt(0).getInnerHits().get("nested_type").getAt(0).field("_parent"), nullValue()); - } - public void testInnerHitsWithIgnoreUnmapped() throws Exception { assertAcked(prepareCreate("index1") .setSettings("index.mapping.single_type", false) @@ -1062,17 +615,6 @@ public class InnerHitsIT extends ESIntegTestCase { assertNoFailures(response); assertHitCount(response, 2); assertSearchHits(response, "1", "3"); - - response = client().prepareSearch("index1", "index2") - .setQuery(boolQuery() - .should(hasChildQuery("child_type", matchAllQuery(), ScoreMode.None).ignoreUnmapped(true) - .innerHit(new InnerHitBuilder(), true)) - .should(termQuery("key", "value")) - ) - .get(); - assertNoFailures(response); - assertHitCount(response, 2); - assertSearchHits(response, "1", "3"); } } diff --git a/docs/java-api/aggregations/bucket/children-aggregation.asciidoc b/docs/java-api/aggregations/bucket/children-aggregation.asciidoc index 1bf8a5b26e6..f6a23fdafe9 100644 --- a/docs/java-api/aggregations/bucket/children-aggregation.asciidoc +++ b/docs/java-api/aggregations/bucket/children-aggregation.asciidoc @@ -24,7 +24,7 @@ Import Aggregation definition classes: [source,java] -------------------------------------------------- -import org.elasticsearch.search.aggregations.bucket.children.Children; +import org.elasticsearch.join.aggregations.Children; -------------------------------------------------- [source,java] diff --git a/modules/parent-join/build.gradle b/modules/parent-join/build.gradle new file mode 100644 index 00000000000..67bcc9d54e8 --- /dev/null +++ b/modules/parent-join/build.gradle @@ -0,0 +1,24 @@ +/* + * 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. + */ + +esplugin { + description 'This module adds the support parent-child queries and aggregations' + classname 'org.elasticsearch.join.ParentJoinPlugin' + hasClientJar = true +} diff --git a/modules/parent-join/src/main/java/org/elasticsearch/join/ParentJoinPlugin.java b/modules/parent-join/src/main/java/org/elasticsearch/join/ParentJoinPlugin.java new file mode 100644 index 00000000000..dec3950836a --- /dev/null +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/ParentJoinPlugin.java @@ -0,0 +1,54 @@ +/* + * 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.join; + +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.join.aggregations.ChildrenAggregationBuilder; +import org.elasticsearch.join.aggregations.InternalChildren; +import org.elasticsearch.join.query.HasChildQueryBuilder; +import org.elasticsearch.join.query.HasParentQueryBuilder; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.plugins.SearchPlugin; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +public class ParentJoinPlugin extends Plugin implements SearchPlugin { + public ParentJoinPlugin(Settings settings) {} + + @Override + public List> getQueries() { + return Arrays.asList( + new QuerySpec<>(HasChildQueryBuilder.NAME, HasChildQueryBuilder::new, HasChildQueryBuilder::fromXContent), + new QuerySpec<>(HasParentQueryBuilder.NAME, HasParentQueryBuilder::new, HasParentQueryBuilder::fromXContent) + ); + } + + @Override + public List getAggregations() { + return Collections.singletonList( + new AggregationSpec(ChildrenAggregationBuilder.NAME, ChildrenAggregationBuilder::new, ChildrenAggregationBuilder::parse) + .addResultReader(InternalChildren::new) + ); + } + + +} diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/Children.java b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/Children.java similarity index 94% rename from core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/Children.java rename to modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/Children.java index b1e4b2877a3..394c690709d 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/Children.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/Children.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket.children; +package org.elasticsearch.join.aggregations; import org.elasticsearch.search.aggregations.bucket.SingleBucketAggregation; diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregationBuilder.java b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ChildrenAggregationBuilder.java similarity index 99% rename from core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregationBuilder.java rename to modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ChildrenAggregationBuilder.java index 3a0d2fff982..d04b1f0a660 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregationBuilder.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ChildrenAggregationBuilder.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket.children; +package org.elasticsearch.join.aggregations; import org.apache.lucene.search.Query; import org.elasticsearch.common.ParsingException; diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregatorFactory.java b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ChildrenAggregatorFactory.java similarity index 98% rename from core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregatorFactory.java rename to modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ChildrenAggregatorFactory.java index b0a4c64305a..800be74ba6f 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ChildrenAggregatorFactory.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ChildrenAggregatorFactory.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket.children; +package org.elasticsearch.join.aggregations; import org.apache.lucene.search.Query; import org.elasticsearch.search.aggregations.Aggregator; diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/InternalChildren.java b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/InternalChildren.java similarity index 97% rename from core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/InternalChildren.java rename to modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/InternalChildren.java index 05a38c8cd59..05cd40e3d33 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/InternalChildren.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/InternalChildren.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket.children; +package org.elasticsearch.join.aggregations; import org.elasticsearch.common.io.stream.StreamInput; import org.elasticsearch.search.aggregations.InternalAggregations; diff --git a/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/JoinAggregationBuilders.java b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/JoinAggregationBuilders.java new file mode 100644 index 00000000000..73522a68b45 --- /dev/null +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/JoinAggregationBuilders.java @@ -0,0 +1,29 @@ +/* + * 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.join.aggregations; + +public abstract class JoinAggregationBuilders { + /** + * Create a new {@link Children} aggregation with the given name. + */ + public static ChildrenAggregationBuilder children(String name, String childType) { + return new ChildrenAggregationBuilder(name, childType); + } +} diff --git a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregator.java b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ParentToChildrenAggregator.java similarity index 99% rename from core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregator.java rename to modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ParentToChildrenAggregator.java index 37a443e9bab..c1ffb097abc 100644 --- a/core/src/main/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregator.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/aggregations/ParentToChildrenAggregator.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.elasticsearch.search.aggregations.bucket.children; +package org.elasticsearch.join.aggregations; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.LeafReaderContext; diff --git a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java b/modules/parent-join/src/main/java/org/elasticsearch/join/query/HasChildQueryBuilder.java similarity index 94% rename from core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java rename to modules/parent-join/src/main/java/org/elasticsearch/join/query/HasChildQueryBuilder.java index 18ad7f9f310..494c5e498e1 100644 --- a/core/src/main/java/org/elasticsearch/index/query/HasChildQueryBuilder.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/query/HasChildQueryBuilder.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.elasticsearch.index.query; +package org.elasticsearch.join.query; import org.apache.lucene.index.DirectoryReader; import org.apache.lucene.index.IndexReader; @@ -38,6 +38,14 @@ import org.elasticsearch.index.fielddata.IndexParentChildFieldData; import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData; import org.elasticsearch.index.mapper.DocumentMapper; import org.elasticsearch.index.mapper.ParentFieldMapper; +import org.elasticsearch.index.query.AbstractQueryBuilder; +import org.elasticsearch.index.query.InnerHitBuilder; +import org.elasticsearch.index.query.NestedQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.index.query.QueryRewriteContext; +import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.index.query.QueryShardException; import java.io.IOException; import java.util.Locale; @@ -210,7 +218,7 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder parameters() throws Exception { + return createParameters(); + } +} diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ChildrenIT.java b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ChildrenIT.java similarity index 92% rename from core/src/test/java/org/elasticsearch/search/aggregations/bucket/ChildrenIT.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ChildrenIT.java index bfe483ca890..8da6dbcdf6c 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ChildrenIT.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ChildrenIT.java @@ -16,7 +16,7 @@ * specific language governing permissions and limitations * under the License. */ -package org.elasticsearch.search.aggregations.bucket; +package org.elasticsearch.join.aggregations; import org.apache.lucene.search.join.ScoreMode; import org.elasticsearch.action.index.IndexRequestBuilder; @@ -26,27 +26,33 @@ import org.elasticsearch.client.Requests; import org.elasticsearch.cluster.metadata.IndexMetaData; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.aggregations.AggregationBuilders; import org.elasticsearch.search.aggregations.InternalAggregation; -import org.elasticsearch.search.aggregations.bucket.children.Children; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.aggregations.metrics.sum.Sum; import org.elasticsearch.search.aggregations.metrics.tophits.TopHits; import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.ESIntegTestCase.ClusterScope; +import org.elasticsearch.test.ESIntegTestCase.Scope; +import org.junit.Before; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; -import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; -import static org.elasticsearch.search.aggregations.AggregationBuilders.children; +import static org.elasticsearch.join.aggregations.JoinAggregationBuilders.children; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery; import static org.elasticsearch.search.aggregations.AggregationBuilders.sum; import static org.elasticsearch.search.aggregations.AggregationBuilders.terms; import static org.elasticsearch.search.aggregations.AggregationBuilders.topHits; @@ -59,13 +65,28 @@ import static org.hamcrest.Matchers.greaterThan; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.sameInstance; -@ESIntegTestCase.SuiteScopeTestCase +@ClusterScope(scope = Scope.SUITE) public class ChildrenIT extends ESIntegTestCase { - private static final Map categoryToControl = new HashMap<>(); @Override - public void setupSuiteScopeCluster() throws Exception { + protected boolean ignoreExternalCluster() { + return true; + } + + @Override + protected Collection> nodePlugins() { + return Collections.singleton(ParentJoinPlugin.class); + } + + @Override + protected Collection> transportClientPlugins() { + return nodePlugins(); + } + + @Before + public void setupCluster() throws Exception { + categoryToControl.clear(); assertAcked( prepareCreate("test") .setSettings("index.mapping.single_type", false) @@ -95,7 +116,8 @@ public class ChildrenIT extends ESIntegTestCase { control.articleIds.add(id); } - requests.add(client().prepareIndex("test", "article", id).setCreate(true).setSource("category", categories, "randomized", true)); + requests.add(client() + .prepareIndex("test", "article", id).setCreate(true).setSource("category", categories, "randomized", true)); } String[] commenters = new String[randomIntBetween(5, 50)]; @@ -116,17 +138,24 @@ public class ChildrenIT extends ESIntegTestCase { control.commenterToCommentId.put(commenter, ids = new HashSet<>()); } ids.add(idValue); - requests.add(client().prepareIndex("test", "comment", idValue).setCreate(true).setParent(articleId).setSource("commenter", commenter)); + requests.add(client().prepareIndex("test", "comment", idValue) + .setCreate(true).setParent(articleId).setSource("commenter", commenter)); } } } - requests.add(client().prepareIndex("test", "article", "a").setSource("category", new String[]{"a"}, "randomized", false)); - requests.add(client().prepareIndex("test", "article", "b").setSource("category", new String[]{"a", "b"}, "randomized", false)); - requests.add(client().prepareIndex("test", "article", "c").setSource("category", new String[]{"a", "b", "c"}, "randomized", false)); - requests.add(client().prepareIndex("test", "article", "d").setSource("category", new String[]{"c"}, "randomized", false)); - requests.add(client().prepareIndex("test", "comment", "a").setParent("a").setSource("{}", XContentType.JSON)); - requests.add(client().prepareIndex("test", "comment", "c").setParent("c").setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("test", "article", "a") + .setSource("category", new String[]{"a"}, "randomized", false)); + requests.add(client().prepareIndex("test", "article", "b") + .setSource("category", new String[]{"a", "b"}, "randomized", false)); + requests.add(client().prepareIndex("test", "article", "c") + .setSource("category", new String[]{"a", "b", "c"}, "randomized", false)); + requests.add(client().prepareIndex("test", "article", "d") + .setSource("category", new String[]{"c"}, "randomized", false)); + requests.add(client().prepareIndex("test", "comment", "a") + .setParent("a").setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("test", "comment", "c") + .setParent("c").setSource("{}", XContentType.JSON)); indexRandom(true, requests); ensureSearchable("test"); @@ -155,7 +184,8 @@ public class ChildrenIT extends ESIntegTestCase { Children childrenBucket = categoryBucket.getAggregations().get("to_comment"); assertThat(childrenBucket.getName(), equalTo("to_comment")); assertThat(childrenBucket.getDocCount(), equalTo((long) entry1.getValue().commentIds.size())); - assertThat((long) ((InternalAggregation)childrenBucket).getProperty("_count"), equalTo((long) entry1.getValue().commentIds.size())); + assertThat((long) ((InternalAggregation)childrenBucket).getProperty("_count"), + equalTo((long) entry1.getValue().commentIds.size())); Terms commentersTerms = childrenBucket.getAggregations().get("commenters"); assertThat((Terms) ((InternalAggregation)childrenBucket).getProperty("commenters"), sameInstance(commentersTerms)); @@ -283,7 +313,7 @@ public class ChildrenIT extends ESIntegTestCase { public void testNonExistingChildType() throws Exception { SearchResponse searchResponse = client().prepareSearch("test") .addAggregation( -children("non-existing", "xyz") + children("non-existing", "xyz") ).get(); assertSearchResponse(searchResponse); @@ -304,7 +334,8 @@ children("non-existing", "xyz") ); List requests = new ArrayList<>(); - requests.add(client().prepareIndex(indexName, masterType, "1").setSource("brand", "Levis", "name", "Style 501", "material", "Denim")); + requests.add(client().prepareIndex(indexName, masterType, "1") + .setSource("brand", "Levis", "name", "Style 501", "material", "Denim")); requests.add(client().prepareIndex(indexName, childType, "0").setParent("1").setSource("color", "blue", "size", "32")); requests.add(client().prepareIndex(indexName, childType, "1").setParent("1").setSource("color", "blue", "size", "34")); requests.add(client().prepareIndex(indexName, childType, "2").setParent("1").setSource("color", "blue", "size", "36")); @@ -312,7 +343,8 @@ children("non-existing", "xyz") requests.add(client().prepareIndex(indexName, childType, "4").setParent("1").setSource("color", "black", "size", "40")); requests.add(client().prepareIndex(indexName, childType, "5").setParent("1").setSource("color", "gray", "size", "36")); - requests.add(client().prepareIndex(indexName, masterType, "2").setSource("brand", "Wrangler", "name", "Regular Cut", "material", "Leather")); + requests.add(client().prepareIndex(indexName, masterType, "2") + .setSource("brand", "Wrangler", "name", "Regular Cut", "material", "Leather")); requests.add(client().prepareIndex(indexName, childType, "6").setParent("2").setSource("color", "blue", "size", "32")); requests.add(client().prepareIndex(indexName, childType, "7").setParent("2").setSource("color", "blue", "size", "34")); requests.add(client().prepareIndex(indexName, childType, "8").setParent("2").setSource("color", "black", "size", "36")); @@ -425,7 +457,7 @@ children("non-existing", "xyz") .setSize(0) .addAggregation(AggregationBuilders.terms("towns").field("town") .subAggregation(AggregationBuilders.terms("parent_names").field("name") -.subAggregation(AggregationBuilders.children("child_docs", "childType")) +.subAggregation(children("child_docs", "childType")) ) ) .get(); @@ -468,5 +500,4 @@ children("non-existing", "xyz") this.category = category; } } - } diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ChildrenTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ChildrenTests.java similarity index 78% rename from core/src/test/java/org/elasticsearch/search/aggregations/bucket/ChildrenTests.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ChildrenTests.java index 4098e85c62e..85a97c4b9b4 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/ChildrenTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ChildrenTests.java @@ -17,13 +17,22 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket; +package org.elasticsearch.join.aggregations; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.aggregations.BaseAggregationTestCase; -import org.elasticsearch.search.aggregations.bucket.children.ChildrenAggregationBuilder; + +import java.util.Collection; +import java.util.Collections; public class ChildrenTests extends BaseAggregationTestCase { + @Override + protected Collection> getPlugins() { + return Collections.singleton(ParentJoinPlugin.class); + } + @Override protected ChildrenAggregationBuilder createTestAggregatorBuilder() { String name = randomAlphaOfLengthBetween(3, 20); diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/InternalChildrenTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/InternalChildrenTests.java similarity index 91% rename from core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/InternalChildrenTests.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/InternalChildrenTests.java index b248d5ed981..afcbc953ebb 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/InternalChildrenTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/InternalChildrenTests.java @@ -17,11 +17,11 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket.children; +package org.elasticsearch.join.aggregations; import org.elasticsearch.common.io.stream.Writeable.Reader; import org.elasticsearch.search.aggregations.InternalAggregations; -import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase; +import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase; import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator; import java.util.List; diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregatorTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ParentToChildrenAggregatorTests.java similarity index 99% rename from core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregatorTests.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ParentToChildrenAggregatorTests.java index 17152bc450a..0a00b2d1c26 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/bucket/children/ParentToChildrenAggregatorTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/aggregations/ParentToChildrenAggregatorTests.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.search.aggregations.bucket.children; +package org.elasticsearch.join.aggregations; import org.apache.lucene.document.Field; import org.apache.lucene.document.SortedDocValuesField; diff --git a/core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/ChildQuerySearchIT.java similarity index 87% rename from core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/query/ChildQuerySearchIT.java index 697352c5edc..ed910ac89e6 100644 --- a/core/src/test/java/org/elasticsearch/search/child/ChildQuerySearchIT.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/ChildQuerySearchIT.java @@ -16,17 +16,20 @@ * specific language governing permissions and limitations * under the License. */ -package org.elasticsearch.search.child; +package org.elasticsearch.join.query; 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.bulk.BulkRequestBuilder; +import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.explain.ExplainResponse; 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.action.support.WriteRequest.RefreshPolicy; +import org.elasticsearch.common.bytes.BytesArray; import org.elasticsearch.common.lucene.search.function.CombineFunction; import org.elasticsearch.common.lucene.search.function.FiltersFunctionScoreQuery; import org.elasticsearch.common.settings.Settings; @@ -34,8 +37,6 @@ import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.IndexModule; import org.elasticsearch.index.query.BoolQueryBuilder; -import org.elasticsearch.index.query.HasChildQueryBuilder; -import org.elasticsearch.index.query.HasParentQueryBuilder; import org.elasticsearch.index.query.IdsQueryBuilder; import org.elasticsearch.index.query.InnerHitBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; @@ -43,6 +44,8 @@ import org.elasticsearch.index.query.MatchQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.SearchHit; import org.elasticsearch.search.aggregations.AggregationBuilders; @@ -62,6 +65,8 @@ import org.hamcrest.Matchers; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; @@ -72,8 +77,6 @@ import java.util.Set; import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; import static org.elasticsearch.index.query.QueryBuilders.boolQuery; import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; -import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery; -import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.idsQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; @@ -83,6 +86,8 @@ import static org.elasticsearch.index.query.QueryBuilders.prefixQuery; import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; import static org.elasticsearch.index.query.QueryBuilders.termsQuery; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.fieldValueFactorFunction; import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.weightFactorFunction; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; @@ -100,6 +105,21 @@ import static org.hamcrest.Matchers.notNullValue; @ClusterScope(scope = Scope.SUITE) public class ChildQuerySearchIT extends ESIntegTestCase { + + @Override + protected boolean ignoreExternalCluster() { + return true; + } + + @Override + protected Collection> nodePlugins() { + return Collections.singleton(ParentJoinPlugin.class); + } + + @Override + protected Collection> transportClientPlugins() { + return nodePlugins(); + } @Override public Settings indexSettings() { @@ -145,26 +165,30 @@ public class ChildQuerySearchIT extends ESIntegTestCase { assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); searchResponse = client().prepareSearch("test") - .setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("parent", termQuery("p_field", "p_value1"), false))).execute() + .setQuery(boolQuery().must(matchAllQuery()) + .filter(hasParentQuery("parent", termQuery("p_field", "p_value1"), false))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c1")); searchResponse = client().prepareSearch("test") - .setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("child", termQuery("c_field", "c_value1"), false))).execute() + .setQuery(boolQuery().must(matchAllQuery()) + .filter(hasParentQuery("child", termQuery("c_field", "c_value1"), false))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("gc1")); - searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", termQuery("p_field", "p_value1"), false)).execute() + searchResponse = client().prepareSearch("test") + .setQuery(hasParentQuery("parent", termQuery("p_field", "p_value1"), false)).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c1")); - searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("child", termQuery("c_field", "c_value1"), false)).execute() + searchResponse = client().prepareSearch("test") + .setQuery(hasParentQuery("child", termQuery("c_field", "c_value1"), false)).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); @@ -209,7 +233,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { refresh(); // TEST FETCHING _parent from child - SearchResponse searchResponse = client().prepareSearch("test").setQuery(idsQuery("child").addIds("c1")).storedFields("_parent").execute() + SearchResponse searchResponse = client().prepareSearch("test") + .setQuery(idsQuery("child").addIds("c1")).storedFields("_parent").execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); @@ -284,7 +309,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { builders.add(client().prepareIndex("test", "child", Integer.toString(i)).setSource("c_field", i).setParent("" + 0)); } for (int i = 0; i < 10; i++) { - builders.add(client().prepareIndex("test", "child", Integer.toString(i + 10)).setSource("c_field", i + 10).setParent(Integer.toString(i))); + builders.add(client().prepareIndex("test", "child", Integer.toString(i + 10)) + .setSource("c_field", i + 10).setParent(Integer.toString(i))); } if (randomBoolean()) { @@ -445,9 +471,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase { SearchResponse searchResponse = client() .prepareSearch("test") - .setQuery(hasChildQuery("child", boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow")), ScoreMode.None)) + .setQuery(hasChildQuery("child", + boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow")), ScoreMode.None)) .addAggregation(AggregationBuilders.global("global").subAggregation( - AggregationBuilders.filter("filter", boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow"))).subAggregation( + AggregationBuilders.filter("filter", + boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow"))).subAggregation( AggregationBuilders.terms("facet1").field("c_field")))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); @@ -523,7 +551,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { assertNoFailures(searchResponse); searchResponse = client().prepareSearch("test").setSearchType(SearchType.DFS_QUERY_THEN_FETCH) - .setQuery(boolQuery().mustNot(hasParentQuery("parent", boolQuery().should(queryStringQuery("p_field:*")), false))).execute() + .setQuery(boolQuery().mustNot(hasParentQuery("parent", + boolQuery().should(queryStringQuery("p_field:*")), false))).execute() .actionGet(); assertNoFailures(searchResponse); } @@ -570,7 +599,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { .get(); assertHitCount(countResponse, 1L); - countResponse = client().prepareSearch("test").setSize(0).setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true)) + countResponse = client().prepareSearch("test").setSize(0) + .setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true)) .get(); assertHitCount(countResponse, 1L); @@ -579,7 +609,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { .get(); assertHitCount(countResponse, 1L); - countResponse = client().prepareSearch("test").setSize(0).setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1"), false))) + countResponse = client().prepareSearch("test").setSize(0) + .setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1"), false))) .get(); assertHitCount(countResponse, 1L); } @@ -685,11 +716,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase { SearchResponse response = client() .prepareSearch("test") .setQuery( - QueryBuilders.hasChildQuery( - "child", - QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), - fieldValueFactorFunction("c_field1")) - .boostMode(CombineFunction.REPLACE), ScoreMode.Total)).get(); + hasChildQuery( + "child", + QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), + fieldValueFactorFunction("c_field1")) + .boostMode(CombineFunction.REPLACE), ScoreMode.Total)).get(); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("1")); @@ -702,11 +733,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase { response = client() .prepareSearch("test") .setQuery( - QueryBuilders.hasChildQuery( - "child", - QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), - fieldValueFactorFunction("c_field1")) - .boostMode(CombineFunction.REPLACE), ScoreMode.Max)).get(); + hasChildQuery( + "child", + QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), + fieldValueFactorFunction("c_field1")) + .boostMode(CombineFunction.REPLACE), ScoreMode.Max)).get(); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); @@ -719,11 +750,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase { response = client() .prepareSearch("test") .setQuery( - QueryBuilders.hasChildQuery( - "child", - QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), - fieldValueFactorFunction("c_field1")) - .boostMode(CombineFunction.REPLACE), ScoreMode.Avg)).get(); + hasChildQuery( + "child", + QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), + fieldValueFactorFunction("c_field1")) + .boostMode(CombineFunction.REPLACE), ScoreMode.Avg)).get(); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); @@ -736,11 +767,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase { response = client() .prepareSearch("test") .setQuery( - QueryBuilders.hasParentQuery( - "parent", - QueryBuilders.functionScoreQuery(matchQuery("p_field1", "p_value3"), - fieldValueFactorFunction("p_field2")) - .boostMode(CombineFunction.REPLACE), true)) + hasParentQuery( + "parent", + QueryBuilders.functionScoreQuery(matchQuery("p_field1", "p_value3"), + fieldValueFactorFunction("p_field2")) + .boostMode(CombineFunction.REPLACE), true)) .addSort(SortBuilders.fieldSort("c_field3")).addSort(SortBuilders.scoreSort()).get(); assertThat(response.getHits().getTotalHits(), equalTo(7L)); @@ -769,7 +800,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase { ensureGreen(); SearchResponse response = client().prepareSearch("test") - .setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get(); + .setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); @@ -777,20 +808,21 @@ public class ChildQuerySearchIT extends ESIntegTestCase { .setRefreshPolicy(RefreshPolicy.IMMEDIATE).get(); response = client().prepareSearch("test") - .setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get(); + .setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); - response = client().prepareSearch("test").setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"), ScoreMode.Max)) + response = client().prepareSearch("test").setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.Max)) .get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); - response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("parent", matchQuery("text", "value"), false)).get(); + response = client().prepareSearch("test") + .setQuery(hasParentQuery("parent", matchQuery("text", "value"), false)).get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); - response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("parent", matchQuery("text", "value"), true)) + response = client().prepareSearch("test").setQuery(hasParentQuery("parent", matchQuery("text", "value"), true)) .get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); @@ -818,7 +850,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("1")); searchResponse = client().prepareSearch("test") - .setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("parent", termQuery("p_field", 1), false))).get(); + .setQuery(boolQuery().must(matchAllQuery()) + .filter(hasParentQuery("parent", termQuery("p_field", 1), false))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("2")); @@ -873,12 +906,14 @@ public class ChildQuerySearchIT extends ESIntegTestCase { assertSearchHit(searchResponse, 1, hasId("2")); searchResponse = client().prepareSearch("test") - .setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery().must(hasChildQuery("child", matchQuery("c_field", 1), ScoreMode.None)))) + .setQuery(boolQuery().must(matchAllQuery()) + .filter(boolQuery().must(hasChildQuery("child", matchQuery("c_field", 1), ScoreMode.None)))) .get(); assertSearchHit(searchResponse, 1, hasId("1")); searchResponse = client().prepareSearch("test") - .setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery().must(hasParentQuery("parent", matchQuery("p_field", 1), false)))).get(); + .setQuery(boolQuery().must(matchAllQuery()) + .filter(boolQuery().must(hasParentQuery("parent", matchQuery("p_field", 1), false)))).get(); assertSearchHit(searchResponse, 1, hasId("2")); } @@ -974,7 +1009,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { client().admin().indices().prepareRefresh("test").get(); } - searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.Total)) + searchResponse = client().prepareSearch("test") + .setQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.Total)) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); @@ -1009,7 +1045,8 @@ 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(), ScoreMode.Total)) + SearchResponse searchResponse = client() + .prepareSearch("test").setQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.Total)) .setMinScore(3) // Score needs to be 3 or above! .get(); assertNoFailures(searchResponse); @@ -1219,7 +1256,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { createIndex("test"); ensureGreen(); - PutMappingResponse putMappingResponse = client().admin().indices().preparePutMapping("test").setType("child").setSource("number", "type=integer") + PutMappingResponse putMappingResponse = client().admin().indices() + .preparePutMapping("test").setType("child").setSource("number", "type=integer") .get(); assertThat(putMappingResponse.isAcknowledged(), equalTo(true)); @@ -1269,13 +1307,15 @@ public class ChildQuerySearchIT extends ESIntegTestCase { ScoreMode scoreMode = randomFrom(ScoreMode.values()); SearchResponse searchResponse = client().prepareSearch("test") - .setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "blue"), scoreMode)).filter(boolQuery().mustNot(termQuery("p_field", "3")))) + .setQuery(boolQuery().must(hasChildQuery("child", termQuery("c_field", "blue"), scoreMode)) + .filter(boolQuery().mustNot(termQuery("p_field", "3")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); searchResponse = client().prepareSearch("test") - .setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "red"), scoreMode)).filter(boolQuery().mustNot(termQuery("p_field", "3")))) + .setQuery(boolQuery().must(hasChildQuery("child", termQuery("c_field", "red"), scoreMode)) + .filter(boolQuery().mustNot(termQuery("p_field", "3")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); @@ -1293,25 +1333,29 @@ 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"), ScoreMode.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"), true).queryName("test")) + searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", + termQuery("p_field", "1"), true).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(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.None).queryName("test"))) + searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasChildQuery("child", + termQuery("c_field", "1"), ScoreMode.None).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(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1"), false).queryName("test"))) + searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasParentQuery("parent", + termQuery("p_field", "1"), false).queryName("test"))) .get(); assertHitCount(searchResponse, 1L); assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1)); @@ -1400,7 +1444,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase { for (int i = 0; i < 2; i++) { SearchResponse searchResponse = client().prepareSearch() .setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery() - .must(QueryBuilders.hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None)) + .must(hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None)) .must(matchAllQuery()))) .get(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); @@ -1412,7 +1456,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase { SearchResponse searchResponse = client().prepareSearch() .setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery() - .must(QueryBuilders.hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None)) + .must(hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None)) .must(matchAllQuery()))) .get(); @@ -1478,7 +1522,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase { SearchResponse resp; resp = client().prepareSearch("test") - .setSource(new SearchSourceBuilder().query(QueryBuilders.hasChildQuery("posts", QueryBuilders.matchQuery("field", "bar"), ScoreMode.None))) + .setSource(new SearchSourceBuilder().query(hasChildQuery("posts", + QueryBuilders.matchQuery("field", "bar"), ScoreMode.None))) .get(); assertHitCount(resp, 1L); } @@ -1580,8 +1625,10 @@ public class ChildQuerySearchIT extends ESIntegTestCase { QueryBuilders.functionScoreQuery(constantScoreQuery(QueryBuilders.termQuery("foo", "two")), new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{ new FunctionScoreQueryBuilder.FilterFunctionBuilder(weightFactorFunction(1)), - new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "three"), weightFactorFunction(1)), - new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "four"), weightFactorFunction(1)) + new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "three"), + weightFactorFunction(1)), + new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "four"), + weightFactorFunction(1)) }).boostMode(CombineFunction.REPLACE).scoreMode(FiltersFunctionScoreQuery.ScoreMode.SUM), scoreMode) .minMaxChildren(minChildren, maxChildren != null ? maxChildren : HasChildQueryBuilder.DEFAULT_MAX_CHILDREN); @@ -1916,7 +1963,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase { try { client().prepareSearch("test") - .setQuery(QueryBuilders.hasChildQuery("child", matchAllQuery(), ScoreMode.None)) + .setQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.None)) .get(); fail(); } catch (SearchPhaseExecutionException e) { @@ -1932,7 +1979,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase { refresh(); //make sure that when we explicitly set a type, the inner query is executed in the context of the parent type instead SearchResponse searchResponse = client().prepareSearch("test").setTypes("child-type").setQuery( - QueryBuilders.hasParentQuery("parent-type", new IdsQueryBuilder().addIds("parent-id"), false)).get(); + hasParentQuery("parent-type", new IdsQueryBuilder().addIds("parent-id"), false)).get(); assertSearchHits(searchResponse, "child-id"); } @@ -1945,7 +1992,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase { refresh(); //make sure that when we explicitly set a type, the inner query is executed in the context of the child type instead SearchResponse searchResponse = client().prepareSearch("test").setTypes("parent-type").setQuery( - QueryBuilders.hasChildQuery("child-type", new IdsQueryBuilder().addIds("child-id"), ScoreMode.None)).get(); + hasChildQuery("child-type", new IdsQueryBuilder().addIds("child-id"), ScoreMode.None)).get(); assertSearchHits(searchResponse, "parent-id"); } @@ -1955,8 +2002,10 @@ public class ChildQuerySearchIT extends ESIntegTestCase { .addMapping("parent-type", "searchText", "type=text,term_vector=with_positions_offsets,index_options=offsets") .addMapping("child-type", "_parent", "type=parent-type", "searchText", "type=text,term_vector=with_positions_offsets,index_options=offsets")); - client().prepareIndex("test", "parent-type", "parent-id").setSource("searchText", "quick brown fox").get(); - client().prepareIndex("test", "child-type", "child-id").setParent("parent-id").setSource("searchText", "quick brown fox").get(); + client().prepareIndex("test", "parent-type", "parent-id") + .setSource("searchText", "quick brown fox").get(); + client().prepareIndex("test", "child-type", "child-id") + .setParent("parent-id").setSource("searchText", "quick brown fox").get(); refresh(); String[] highlightTypes = new String[] {"plain", "fvh", "postings"}; @@ -1988,4 +2037,177 @@ public class ChildQuerySearchIT extends ESIntegTestCase { } } + public void testAliasesFilterWithHasChildQuery() throws Exception { + assertAcked(prepareCreate("my-index") + .setSettings("index.mapping.single_type", false) + .addMapping("parent") + .addMapping("child", "_parent", "type=parent") + ); + client().prepareIndex("my-index", "parent", "1").setSource("{}", XContentType.JSON).get(); + client().prepareIndex("my-index", "child", "2").setSource("{}", XContentType.JSON).setParent("1").get(); + refresh(); + + assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter1", + hasChildQuery("child", matchAllQuery(), ScoreMode.None))); + assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter2", + hasParentQuery("parent", matchAllQuery(), false))); + + SearchResponse response = client().prepareSearch("filter1").get(); + assertHitCount(response, 1); + assertThat(response.getHits().getAt(0).getId(), equalTo("1")); + response = client().prepareSearch("filter2").get(); + assertHitCount(response, 1); + assertThat(response.getHits().getAt(0).getId(), equalTo("2")); + } + + /* + Test for https://github.com/elastic/elasticsearch/issues/3444 + */ + public void testBulkUpdateDocAsUpsertWithParent() throws Exception { + client().admin().indices().prepareCreate("test") + .setSettings("index.mapping.single_type", false) + .addMapping("parent", "{\"parent\":{}}", XContentType.JSON) + .addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON) + .execute().actionGet(); + ensureGreen(); + + BulkRequestBuilder builder = client().prepareBulk(); + + // It's important to use JSON parsing here and request objects: issue 3444 is related to incomplete option parsing + byte[] addParent = new BytesArray( + "{" + + " \"index\" : {" + + " \"_index\" : \"test\"," + + " \"_type\" : \"parent\"," + + " \"_id\" : \"parent1\"" + + " }" + + "}" + + "\n" + + "{" + + " \"field1\" : \"value1\"" + + "}" + + "\n").array(); + + byte[] addChild = new BytesArray( + "{" + + " \"update\" : {" + + " \"_index\" : \"test\"," + + " \"_type\" : \"child\"," + + " \"_id\" : \"child1\"," + + " \"parent\" : \"parent1\"" + + " }" + + "}" + + "\n" + + "{" + + " \"doc\" : {" + + " \"field1\" : \"value1\"" + + " }," + + " \"doc_as_upsert\" : \"true\"" + + "}" + + "\n").array(); + + builder.add(addParent, 0, addParent.length, XContentType.JSON); + builder.add(addChild, 0, addChild.length, XContentType.JSON); + + BulkResponse bulkResponse = builder.get(); + assertThat(bulkResponse.getItems().length, equalTo(2)); + assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false)); + assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false)); + + client().admin().indices().prepareRefresh("test").get(); + + //we check that the _parent field was set on the child document by using the has parent query + SearchResponse searchResponse = client().prepareSearch("test") + .setQuery(hasParentQuery("parent", QueryBuilders.matchAllQuery(), false)) + .get(); + + assertNoFailures(searchResponse); + assertSearchHits(searchResponse, "child1"); + } + + /* + Test for https://github.com/elastic/elasticsearch/issues/3444 + */ + public void testBulkUpdateUpsertWithParent() throws Exception { + assertAcked(prepareCreate("test") + .setSettings("index.mapping.single_type", false) + .addMapping("parent", "{\"parent\":{}}", XContentType.JSON) + .addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON)); + ensureGreen(); + + BulkRequestBuilder builder = client().prepareBulk(); + + byte[] addParent = new BytesArray( + "{" + + " \"index\" : {" + + " \"_index\" : \"test\"," + + " \"_type\" : \"parent\"," + + " \"_id\" : \"parent1\"" + + " }" + + "}" + + "\n" + + "{" + + " \"field1\" : \"value1\"" + + "}" + + "\n").array(); + + byte[] addChild1 = new BytesArray( + "{" + + " \"update\" : {" + + " \"_index\" : \"test\"," + + " \"_type\" : \"child\"," + + " \"_id\" : \"child1\"," + + " \"parent\" : \"parent1\"" + + " }" + + "}" + + "\n" + + "{" + + " \"script\" : {" + + " \"inline\" : \"ctx._source.field2 = 'value2'\"" + + " }," + + " \"lang\" : \"" + InnerHitsIT.CustomScriptPlugin.NAME + "\"," + + " \"upsert\" : {" + + " \"field1\" : \"value1'\"" + + " }" + + "}" + + "\n").array(); + + byte[] addChild2 = new BytesArray( + "{" + + " \"update\" : {" + + " \"_index\" : \"test\"," + + " \"_type\" : \"child\"," + + " \"_id\" : \"child1\"," + + " \"parent\" : \"parent1\"" + + " }" + + "}" + + "\n" + + "{" + + " \"script\" : \"ctx._source.field2 = 'value2'\"," + + " \"upsert\" : {" + + " \"field1\" : \"value1'\"" + + " }" + + "}" + + "\n").array(); + + builder.add(addParent, 0, addParent.length, XContentType.JSON); + builder.add(addChild1, 0, addChild1.length, XContentType.JSON); + builder.add(addChild2, 0, addChild2.length, XContentType.JSON); + + BulkResponse bulkResponse = builder.get(); + assertThat(bulkResponse.getItems().length, equalTo(3)); + assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false)); + assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false)); + assertThat(bulkResponse.getItems()[2].isFailed(), equalTo(true)); + assertThat(bulkResponse.getItems()[2].getFailure().getCause().getCause().getMessage(), + equalTo("script_lang not supported [painless]")); + + client().admin().indices().prepareRefresh("test").get(); + + SearchResponse searchResponse = client().prepareSearch("test") + .setQuery(hasParentQuery("parent", QueryBuilders.matchAllQuery(), false)) + .get(); + + assertSearchHits(searchResponse, "child1"); + } } diff --git a/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java similarity index 83% rename from core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java index 49523fe923d..8f4fc9d0c34 100644 --- a/core/src/test/java/org/elasticsearch/index/query/HasChildQueryBuilderTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.index.query; +package org.elasticsearch.join.query; import com.carrotsearch.randomizedtesting.generators.RandomPicks; import org.apache.lucene.search.TermInSetQuery; @@ -40,7 +40,17 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.TypeFieldMapper; import org.elasticsearch.index.mapper.Uid; import org.elasticsearch.index.mapper.UidFieldMapper; +import org.elasticsearch.index.query.IdsQueryBuilder; +import org.elasticsearch.index.query.InnerHitBuilder; +import org.elasticsearch.index.query.MatchAllQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.index.query.QueryShardException; +import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.index.query.WrapperQueryBuilder; import org.elasticsearch.index.similarity.SimilarityService; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.fetch.subphase.InnerHitsContext; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.sort.FieldSortBuilder; @@ -48,10 +58,12 @@ import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.test.AbstractQueryTestCase; import java.io.IOException; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Map; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; @@ -65,6 +77,11 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase> getPlugins() { + return Collections.singletonList(ParentJoinPlugin.class); + } + @Override protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { similarity = randomFrom("classic", "BM25"); @@ -97,7 +114,7 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase QueryBuilders.hasChildQuery(null, query, ScoreMode.None)); + () -> hasChildQuery(null, query, ScoreMode.None)); assertEquals("[has_child] requires 'type' field", e.getMessage()); - e = expectThrows(IllegalArgumentException.class, () -> QueryBuilders.hasChildQuery("foo", null, ScoreMode.None)); + e = expectThrows(IllegalArgumentException.class, () -> hasChildQuery("foo", null, ScoreMode.None)); assertEquals("[has_child] requires 'query' field", e.getMessage()); - e = expectThrows(IllegalArgumentException.class, () -> QueryBuilders.hasChildQuery("foo", query, null)); + e = expectThrows(IllegalArgumentException.class, () -> hasChildQuery("foo", query, null)); assertEquals("[has_child] requires 'score_mode' field", e.getMessage()); int positiveValue = randomIntBetween(0, Integer.MAX_VALUE); - HasChildQueryBuilder foo = QueryBuilders.hasChildQuery("foo", query, ScoreMode.None); // all good + HasChildQueryBuilder foo = hasChildQuery("foo", query, ScoreMode.None); // all good e = expectThrows(IllegalArgumentException.class, () -> foo.minMaxChildren(randomIntBetween(Integer.MIN_VALUE, -1), positiveValue)); assertEquals("[has_child] requires non-negative 'min_children' field", e.getMessage()); @@ -225,7 +242,7 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase HasChildQueryBuilder.parseScoreMode(null)); - assertEquals("No score mode for child query [null] found", e.getMessage()); - } - - /** - * Failure should not change (and the value should never match anything...). - */ - public void testThatUnrecognizedFromStringThrowsException() { - IllegalArgumentException e = expectThrows(IllegalArgumentException.class, - () -> HasChildQueryBuilder.parseScoreMode("unrecognized value")); - assertEquals("No score mode for child query [unrecognized value] found", e.getMessage()); - } - public void testIgnoreUnmapped() throws IOException { final HasChildQueryBuilder queryBuilder = new HasChildQueryBuilder("unmapped", new MatchAllQueryBuilder(), ScoreMode.None); queryBuilder.ignoreUnmapped(true); diff --git a/core/src/test/java/org/elasticsearch/index/query/HasParentQueryBuilderTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java similarity index 90% rename from core/src/test/java/org/elasticsearch/index/query/HasParentQueryBuilderTests.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java index 22ea2cc9c44..825dfede61e 100644 --- a/core/src/test/java/org/elasticsearch/index/query/HasParentQueryBuilderTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.index.query; +package org.elasticsearch.join.query; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; @@ -28,6 +28,16 @@ import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.index.query.IdsQueryBuilder; +import org.elasticsearch.index.query.InnerHitBuilder; +import org.elasticsearch.index.query.MatchAllQueryBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.index.query.QueryShardException; +import org.elasticsearch.index.query.TermQueryBuilder; +import org.elasticsearch.index.query.WrapperQueryBuilder; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.fetch.subphase.InnerHitsContext; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.search.sort.FieldSortBuilder; @@ -35,9 +45,12 @@ import org.elasticsearch.search.sort.SortOrder; import org.elasticsearch.test.AbstractQueryTestCase; import java.io.IOException; +import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.Map; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.equalTo; import static org.hamcrest.CoreMatchers.instanceOf; @@ -49,6 +62,11 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase> getPlugins() { + return Collections.singletonList(ParentJoinPlugin.class); + } + @Override protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { mapperService.merge(PARENT_TYPE, new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef(PARENT_TYPE, @@ -79,7 +97,7 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase QueryBuilders.hasParentQuery(null, query, false)); + () -> hasParentQuery(null, query, false)); assertThat(e.getMessage(), equalTo("[has_parent] requires 'type' field")); e = expectThrows(IllegalArgumentException.class, - () -> QueryBuilders.hasParentQuery("foo", null, false)); + () -> hasParentQuery("foo", null, false)); assertThat(e.getMessage(), equalTo("[has_parent] requires 'query' field")); QueryShardContext context = createShardContext(); - HasParentQueryBuilder qb = QueryBuilders.hasParentQuery("just_a_type", new MatchAllQueryBuilder(), false); + HasParentQueryBuilder qb = hasParentQuery("just_a_type", new MatchAllQueryBuilder(), false); QueryShardException qse = expectThrows(QueryShardException.class, () -> qb.doToQuery(context)); assertThat(qse.getMessage(), equalTo("[has_parent] no child types found for type [just_a_type]")); } diff --git a/modules/parent-join/src/test/java/org/elasticsearch/join/query/InnerHitsIT.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/InnerHitsIT.java new file mode 100644 index 00000000000..ad8e49e9f5d --- /dev/null +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/InnerHitsIT.java @@ -0,0 +1,568 @@ +/* + * 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.join.query; + +import org.apache.lucene.search.join.ScoreMode; +import org.apache.lucene.util.ArrayUtil; +import org.elasticsearch.action.index.IndexRequestBuilder; +import org.elasticsearch.action.search.SearchResponse; +import org.elasticsearch.common.xcontent.XContentType; +import org.elasticsearch.index.query.BoolQueryBuilder; +import org.elasticsearch.index.query.InnerHitBuilder; +import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.script.MockScriptEngine; +import org.elasticsearch.script.MockScriptPlugin; +import org.elasticsearch.script.Script; +import org.elasticsearch.script.ScriptType; +import org.elasticsearch.search.SearchHit; +import org.elasticsearch.search.SearchHits; +import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; +import org.elasticsearch.search.sort.FieldSortBuilder; +import org.elasticsearch.search.sort.SortBuilders; +import org.elasticsearch.search.sort.SortOrder; +import org.elasticsearch.test.ESIntegTestCase; +import org.elasticsearch.test.ESIntegTestCase.ClusterScope; +import org.elasticsearch.test.ESIntegTestCase.Scope; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.function.Function; + +import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE; +import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder; +import static org.elasticsearch.index.query.QueryBuilders.boolQuery; +import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; +import static org.elasticsearch.index.query.QueryBuilders.matchQuery; +import static org.elasticsearch.index.query.QueryBuilders.nestedQuery; +import static org.elasticsearch.index.query.QueryBuilders.termQuery; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHit; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; +import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; + +@ClusterScope(scope = Scope.SUITE) +public class InnerHitsIT extends ESIntegTestCase { + @Override + protected boolean ignoreExternalCluster() { + return true; + } + + @Override + protected Collection> nodePlugins() { + return Arrays.asList(ParentJoinPlugin.class, CustomScriptPlugin.class); + } + + @Override + protected Collection> transportClientPlugins() { + return nodePlugins(); + } + + public static class CustomScriptPlugin extends MockScriptPlugin { + @Override + protected Map, Object>> pluginScripts() { + return Collections.singletonMap("5", script -> "5"); + } + } + + public void testSimpleParentChild() throws Exception { + assertAcked(prepareCreate("articles") + .setSettings("index.mapping.single_type", false) + .addMapping("article", "title", "type=text") + .addMapping("comment", "_parent", "type=article", "message", "type=text,fielddata=true") + ); + + List requests = new ArrayList<>(); + requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox")); + requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick")); + requests.add(client().prepareIndex("articles", "comment", "2").setParent("1").setSource("message", "fox ate rabbit x y z")); + requests.add(client().prepareIndex("articles", "comment", "3").setParent("1").setSource("message", "rabbit got away")); + requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant")); + requests.add(client().prepareIndex("articles", "comment", "4").setParent("2").setSource("message", "elephant captured")); + requests.add(client().prepareIndex("articles", "comment", "5").setParent("2").setSource("message", "mice squashed by elephant x")); + requests.add(client().prepareIndex("articles", "comment", "6").setParent("2").setSource("message", "elephant scared by mice x y")); + indexRandom(true, requests); + + SearchResponse response = client().prepareSearch("articles") + .setQuery(hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None) + .innerHit(new InnerHitBuilder(), false)) + .get(); + assertNoFailures(response); + assertHitCount(response, 1); + assertSearchHit(response, 1, hasId("1")); + assertThat(response.getHits().getAt(0).getShard(), notNullValue()); + + assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); + SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); + assertThat(innerHits.getTotalHits(), equalTo(2L)); + + assertThat(innerHits.getAt(0).getId(), equalTo("1")); + assertThat(innerHits.getAt(0).getType(), equalTo("comment")); + assertThat(innerHits.getAt(1).getId(), equalTo("2")); + assertThat(innerHits.getAt(1).getType(), equalTo("comment")); + + response = client().prepareSearch("articles") + .setQuery(hasChildQuery("comment", matchQuery("message", "elephant"), ScoreMode.None) + .innerHit(new InnerHitBuilder(), false)) + .get(); + assertNoFailures(response); + assertHitCount(response, 1); + assertSearchHit(response, 1, hasId("2")); + + assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); + innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); + assertThat(innerHits.getTotalHits(), equalTo(3L)); + + assertThat(innerHits.getAt(0).getId(), equalTo("4")); + assertThat(innerHits.getAt(0).getType(), equalTo("comment")); + assertThat(innerHits.getAt(1).getId(), equalTo("5")); + assertThat(innerHits.getAt(1).getType(), equalTo("comment")); + assertThat(innerHits.getAt(2).getId(), equalTo("6")); + assertThat(innerHits.getAt(2).getType(), equalTo("comment")); + + response = client().prepareSearch("articles") + .setQuery( + hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None).innerHit( + new InnerHitBuilder() + .addDocValueField("message") + .setHighlightBuilder(new HighlightBuilder().field("message")) + .setExplain(true).setSize(1) + .addScriptField("script", new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5", + Collections.emptyMap())), + false) + ).get(); + assertNoFailures(response); + innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); + assertThat(innerHits.getHits().length, equalTo(1)); + assertThat(innerHits.getAt(0).getHighlightFields().get("message").getFragments()[0].string(), equalTo("fox eat quick")); + assertThat(innerHits.getAt(0).getExplanation().toString(), containsString("weight(message:fox")); + assertThat(innerHits.getAt(0).getFields().get("message").getValue().toString(), equalTo("eat")); + assertThat(innerHits.getAt(0).getFields().get("script").getValue().toString(), equalTo("5")); + } + + public void testRandomParentChild() throws Exception { + assertAcked(prepareCreate("idx") + .setSettings("index.mapping.single_type", false) + .addMapping("parent") + .addMapping("child1", "_parent", "type=parent") + .addMapping("child2", "_parent", "type=parent") + ); + int numDocs = scaledRandomIntBetween(5, 50); + List requestBuilders = new ArrayList<>(); + + int child1 = 0; + int child2 = 0; + int[] child1InnerObjects = new int[numDocs]; + int[] child2InnerObjects = new int[numDocs]; + for (int parent = 0; parent < numDocs; parent++) { + String parentId = String.format(Locale.ENGLISH, "%03d", parent); + requestBuilders.add(client().prepareIndex("idx", "parent", parentId).setSource("{}", XContentType.JSON)); + + int numChildDocs = child1InnerObjects[parent] = scaledRandomIntBetween(1, numDocs); + int limit = child1 + numChildDocs; + for (; child1 < limit; child1++) { + requestBuilders.add(client().prepareIndex("idx", "child1", + String.format(Locale.ENGLISH, "%04d", child1)).setParent(parentId).setSource("{}", XContentType.JSON)); + } + numChildDocs = child2InnerObjects[parent] = scaledRandomIntBetween(1, numDocs); + limit = child2 + numChildDocs; + for (; child2 < limit; child2++) { + requestBuilders.add(client().prepareIndex("idx", "child2", + String.format(Locale.ENGLISH, "%04d", child2)).setParent(parentId).setSource("{}", XContentType.JSON)); + } + } + indexRandom(true, requestBuilders); + + int size = randomIntBetween(0, numDocs); + BoolQueryBuilder boolQuery = new BoolQueryBuilder(); + boolQuery.should(constantScoreQuery(hasChildQuery("child1", matchAllQuery(), ScoreMode.None) + .innerHit(new InnerHitBuilder().setName("a") + .addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false))); + boolQuery.should(constantScoreQuery(hasChildQuery("child2", matchAllQuery(), ScoreMode.None) + .innerHit(new InnerHitBuilder().setName("b") + .addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false))); + SearchResponse searchResponse = client().prepareSearch("idx") + .setSize(numDocs) + .setTypes("parent") + .addSort("_uid", SortOrder.ASC) + .setQuery(boolQuery) + .get(); + + assertNoFailures(searchResponse); + assertHitCount(searchResponse, numDocs); + assertThat(searchResponse.getHits().getHits().length, equalTo(numDocs)); + + int offset1 = 0; + int offset2 = 0; + for (int parent = 0; parent < numDocs; parent++) { + SearchHit searchHit = searchResponse.getHits().getAt(parent); + assertThat(searchHit.getType(), equalTo("parent")); + assertThat(searchHit.getId(), equalTo(String.format(Locale.ENGLISH, "%03d", parent))); + assertThat(searchHit.getShard(), notNullValue()); + + SearchHits inner = searchHit.getInnerHits().get("a"); + assertThat(inner.getTotalHits(), equalTo((long) child1InnerObjects[parent])); + for (int child = 0; child < child1InnerObjects[parent] && child < size; child++) { + SearchHit innerHit = inner.getAt(child); + assertThat(innerHit.getType(), equalTo("child1")); + String childId = String.format(Locale.ENGLISH, "%04d", offset1 + child); + assertThat(innerHit.getId(), equalTo(childId)); + assertThat(innerHit.getNestedIdentity(), nullValue()); + } + offset1 += child1InnerObjects[parent]; + + inner = searchHit.getInnerHits().get("b"); + assertThat(inner.getTotalHits(), equalTo((long) child2InnerObjects[parent])); + for (int child = 0; child < child2InnerObjects[parent] && child < size; child++) { + SearchHit innerHit = inner.getAt(child); + assertThat(innerHit.getType(), equalTo("child2")); + String childId = String.format(Locale.ENGLISH, "%04d", offset2 + child); + assertThat(innerHit.getId(), equalTo(childId)); + assertThat(innerHit.getNestedIdentity(), nullValue()); + } + offset2 += child2InnerObjects[parent]; + } + } + + public void testInnerHitsOnHasParent() throws Exception { + assertAcked(prepareCreate("stack") + .setSettings("index.mapping.single_type", false) + .addMapping("question", "body", "type=text") + .addMapping("answer", "_parent", "type=question", "body", "type=text") + ); + List requests = new ArrayList<>(); + requests.add(client().prepareIndex("stack", "question", "1").setSource("body", "I'm using HTTPS + Basic authentication " + + "to protect a resource. How can I throttle authentication attempts to protect against brute force attacks?")); + requests.add(client().prepareIndex("stack", "answer", "1").setParent("1").setSource("body", + "install fail2ban and enable rules for apache")); + requests.add(client().prepareIndex("stack", "question", "2").setSource("body", + "I have firewall rules set up and also denyhosts installed.\\ndo I also need to install fail2ban?")); + requests.add(client().prepareIndex("stack", "answer", "2").setParent("2").setSource("body", + "Denyhosts protects only ssh; Fail2Ban protects all daemons.")); + indexRandom(true, requests); + + SearchResponse response = client().prepareSearch("stack") + .setTypes("answer") + .addSort("_uid", SortOrder.ASC) + .setQuery( + boolQuery() + .must(matchQuery("body", "fail2ban")) + .must(hasParentQuery("question", matchAllQuery(), false).innerHit(new InnerHitBuilder(), false)) + ).get(); + assertNoFailures(response); + assertHitCount(response, 2); + + SearchHit searchHit = response.getHits().getAt(0); + assertThat(searchHit.getId(), equalTo("1")); + assertThat(searchHit.getType(), equalTo("answer")); + assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L)); + assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question")); + assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("1")); + + searchHit = response.getHits().getAt(1); + assertThat(searchHit.getId(), equalTo("2")); + assertThat(searchHit.getType(), equalTo("answer")); + assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L)); + assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question")); + assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("2")); + } + + public void testParentChildMultipleLayers() throws Exception { + assertAcked(prepareCreate("articles") + .setSettings("index.mapping.single_type", false) + .addMapping("article", "title", "type=text") + .addMapping("comment", "_parent", "type=article", "message", "type=text") + .addMapping("remark", "_parent", "type=comment", "message", "type=text") + ); + + List requests = new ArrayList<>(); + requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox")); + requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick")); + requests.add(client().prepareIndex("articles", "remark", "1").setParent("1").setRouting("1").setSource("message", "good")); + requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant")); + requests.add(client().prepareIndex("articles", "comment", "2").setParent("2").setSource("message", "elephant captured")); + requests.add(client().prepareIndex("articles", "remark", "2").setParent("2").setRouting("2").setSource("message", "bad")); + indexRandom(true, requests); + + SearchResponse response = client().prepareSearch("articles") + .setQuery(hasChildQuery("comment", + hasChildQuery("remark", matchQuery("message", "good"), ScoreMode.None).innerHit(new InnerHitBuilder(), false), + ScoreMode.None).innerHit(new InnerHitBuilder(), false)) + .get(); + + assertNoFailures(response); + assertHitCount(response, 1); + assertSearchHit(response, 1, hasId("1")); + + assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); + SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); + assertThat(innerHits.getTotalHits(), equalTo(1L)); + assertThat(innerHits.getAt(0).getId(), equalTo("1")); + assertThat(innerHits.getAt(0).getType(), equalTo("comment")); + + innerHits = innerHits.getAt(0).getInnerHits().get("remark"); + assertThat(innerHits.getTotalHits(), equalTo(1L)); + assertThat(innerHits.getAt(0).getId(), equalTo("1")); + assertThat(innerHits.getAt(0).getType(), equalTo("remark")); + + response = client().prepareSearch("articles") + .setQuery(hasChildQuery("comment", + hasChildQuery("remark", matchQuery("message", "bad"), ScoreMode.None).innerHit(new InnerHitBuilder(), false), + ScoreMode.None).innerHit(new InnerHitBuilder(), false)) + .get(); + + assertNoFailures(response); + assertHitCount(response, 1); + assertSearchHit(response, 1, hasId("2")); + + assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1)); + innerHits = response.getHits().getAt(0).getInnerHits().get("comment"); + assertThat(innerHits.getTotalHits(), equalTo(1L)); + assertThat(innerHits.getAt(0).getId(), equalTo("2")); + assertThat(innerHits.getAt(0).getType(), equalTo("comment")); + + innerHits = innerHits.getAt(0).getInnerHits().get("remark"); + assertThat(innerHits.getTotalHits(), equalTo(1L)); + assertThat(innerHits.getAt(0).getId(), equalTo("2")); + assertThat(innerHits.getAt(0).getType(), equalTo("remark")); + } + + public void testRoyals() throws Exception { + assertAcked( + prepareCreate("royals") + .setSettings("index.mapping.single_type", false) + .addMapping("king") + .addMapping("prince", "_parent", "type=king") + .addMapping("duke", "_parent", "type=prince") + .addMapping("earl", "_parent", "type=duke") + .addMapping("baron", "_parent", "type=earl") + ); + + List requests = new ArrayList<>(); + requests.add(client().prepareIndex("royals", "king", "king").setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "prince", "prince").setParent("king").setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "duke", "duke").setParent("prince").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "earl", "earl1").setParent("duke").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "earl", "earl2").setParent("duke").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "earl", "earl3").setParent("duke").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "earl", "earl4").setParent("duke").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "baron", "baron1").setParent("earl1").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "baron", "baron2").setParent("earl2").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "baron", "baron3").setParent("earl3").setRouting("king") + .setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("royals", "baron", "baron4").setParent("earl4").setRouting("king") + .setSource("{}", XContentType.JSON)); + indexRandom(true, requests); + + SearchResponse response = client().prepareSearch("royals") + .setTypes("duke") + .setQuery(boolQuery() + .filter(hasParentQuery("prince", + hasParentQuery("king", matchAllQuery(), false).innerHit(new InnerHitBuilder().setName("kings"), false), + false).innerHit(new InnerHitBuilder().setName("princes"), false) + ) + .filter(hasChildQuery("earl", + hasChildQuery("baron", matchAllQuery(), ScoreMode.None) + .innerHit(new InnerHitBuilder().setName("barons"), false), + ScoreMode.None).innerHit(new InnerHitBuilder() + .addSort(SortBuilders.fieldSort("_uid").order(SortOrder.ASC)) + .setName("earls") + .setSize(4), false) + ) + ) + .get(); + assertHitCount(response, 1); + assertThat(response.getHits().getAt(0).getId(), equalTo("duke")); + + SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("earls"); + assertThat(innerHits.getTotalHits(), equalTo(4L)); + assertThat(innerHits.getAt(0).getId(), equalTo("earl1")); + assertThat(innerHits.getAt(1).getId(), equalTo("earl2")); + assertThat(innerHits.getAt(2).getId(), equalTo("earl3")); + assertThat(innerHits.getAt(3).getId(), equalTo("earl4")); + + SearchHits innerInnerHits = innerHits.getAt(0).getInnerHits().get("barons"); + assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); + assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron1")); + + innerInnerHits = innerHits.getAt(1).getInnerHits().get("barons"); + assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); + assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron2")); + + innerInnerHits = innerHits.getAt(2).getInnerHits().get("barons"); + assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); + assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron3")); + + innerInnerHits = innerHits.getAt(3).getInnerHits().get("barons"); + assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); + assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron4")); + + innerHits = response.getHits().getAt(0).getInnerHits().get("princes"); + assertThat(innerHits.getTotalHits(), equalTo(1L)); + assertThat(innerHits.getAt(0).getId(), equalTo("prince")); + + innerInnerHits = innerHits.getAt(0).getInnerHits().get("kings"); + assertThat(innerInnerHits.getTotalHits(), equalTo(1L)); + assertThat(innerInnerHits.getAt(0).getId(), equalTo("king")); + } + + public void testMatchesQueriesParentChildInnerHits() throws Exception { + assertAcked(prepareCreate("index") + .setSettings("index.mapping.single_type", false) + .addMapping("child", "_parent", "type=parent")); + List requests = new ArrayList<>(); + requests.add(client().prepareIndex("index", "parent", "1").setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("index", "child", "1").setParent("1").setSource("field", "value1")); + requests.add(client().prepareIndex("index", "child", "2").setParent("1").setSource("field", "value2")); + requests.add(client().prepareIndex("index", "parent", "2").setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("index", "child", "3").setParent("2").setSource("field", "value1")); + indexRandom(true, requests); + + SearchResponse response = client().prepareSearch("index") + .setQuery(hasChildQuery("child", matchQuery("field", "value1").queryName("_name1"), ScoreMode.None) + .innerHit(new InnerHitBuilder(), false)) + .addSort("_uid", SortOrder.ASC) + .get(); + assertHitCount(response, 2); + assertThat(response.getHits().getAt(0).getId(), equalTo("1")); + assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L)); + assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1)); + assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1")); + + assertThat(response.getHits().getAt(1).getId(), equalTo("2")); + assertThat(response.getHits().getAt(1).getInnerHits().get("child").getTotalHits(), equalTo(1L)); + assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1)); + assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1")); + + QueryBuilder query = hasChildQuery("child", matchQuery("field", "value2").queryName("_name2"), ScoreMode.None) + .innerHit(new InnerHitBuilder(), false); + response = client().prepareSearch("index") + .setQuery(query) + .addSort("_uid", SortOrder.ASC) + .get(); + assertHitCount(response, 1); + assertThat(response.getHits().getAt(0).getId(), equalTo("1")); + assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L)); + assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1)); + assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name2")); + } + + public void testDontExplode() throws Exception { + assertAcked(prepareCreate("index1") + .setSettings("index.mapping.single_type", false) + .addMapping("child", "_parent", "type=parent")); + List requests = new ArrayList<>(); + requests.add(client().prepareIndex("index1", "parent", "1").setSource("{}", XContentType.JSON)); + requests.add(client().prepareIndex("index1", "child", "1").setParent("1").setSource("field", "value1")); + indexRandom(true, requests); + + QueryBuilder query = hasChildQuery("child", matchQuery("field", "value1"), ScoreMode.None) + .innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false); + SearchResponse response = client().prepareSearch("index1") + .setQuery(query) + .get(); + assertNoFailures(response); + assertHitCount(response, 1); + + assertAcked(prepareCreate("index2").addMapping("type", "nested", "type=nested")); + client().prepareIndex("index2", "type", "1").setSource(jsonBuilder().startObject() + .startArray("nested") + .startObject() + .field("field", "value1") + .endObject() + .endArray() + .endObject()) + .setRefreshPolicy(IMMEDIATE) + .get(); + + query = nestedQuery("nested", matchQuery("nested.field", "value1"), ScoreMode.Avg) + .innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false); + response = client().prepareSearch("index2") + .setQuery(query) + .get(); + assertNoFailures(response); + assertHitCount(response, 1); + } + + public void testNestedInnerHitWrappedInParentChildInnerhit() throws Exception { + assertAcked(prepareCreate("test") + .setSettings("index.mapping.single_type", false) + .addMapping("child_type", "_parent", "type=parent_type", "nested_type", "type=nested")); + client().prepareIndex("test", "parent_type", "1").setSource("key", "value").get(); + client().prepareIndex("test", "child_type", "2").setParent("1").setSource("nested_type", Collections.singletonMap("key", "value")) + .get(); + refresh(); + SearchResponse response = client().prepareSearch("test") + .setQuery(boolQuery().must(matchQuery("key", "value")) + .should(hasChildQuery("child_type", nestedQuery("nested_type", matchAllQuery(), ScoreMode.None) + .innerHit(new InnerHitBuilder(), false), ScoreMode.None).innerHit(new InnerHitBuilder(), false))) + .get(); + assertHitCount(response, 1); + SearchHit hit = response.getHits().getAt(0); + assertThat(hit.getInnerHits().get("child_type").getAt(0).field("_parent").getValue(), equalTo("1")); + assertThat(hit.getInnerHits().get("child_type").getAt(0).getInnerHits().get("nested_type").getAt(0).field("_parent"), nullValue()); + } + + public void testInnerHitsWithIgnoreUnmapped() throws Exception { + assertAcked(prepareCreate("index1") + .setSettings("index.mapping.single_type", false) + .addMapping("parent_type", "nested_type", "type=nested") + .addMapping("child_type", "_parent", "type=parent_type") + ); + createIndex("index2"); + client().prepareIndex("index1", "parent_type", "1").setSource("nested_type", Collections.singletonMap("key", "value")).get(); + client().prepareIndex("index1", "child_type", "2").setParent("1").setSource("{}", XContentType.JSON).get(); + client().prepareIndex("index2", "type", "3").setSource("key", "value").get(); + refresh(); + + SearchResponse response = client().prepareSearch("index1", "index2") + .setQuery(boolQuery() + .should(hasChildQuery("child_type", matchAllQuery(), ScoreMode.None).ignoreUnmapped(true) + .innerHit(new InnerHitBuilder(), true)) + .should(termQuery("key", "value")) + ) + .get(); + assertNoFailures(response); + assertHitCount(response, 2); + assertSearchHits(response, "1", "3"); + } +} diff --git a/modules/parent-join/src/test/resources/rest-api-spec/test/10_basic.yaml b/modules/parent-join/src/test/resources/rest-api-spec/test/10_basic.yaml new file mode 100644 index 00000000000..f5a58080129 --- /dev/null +++ b/modules/parent-join/src/test/resources/rest-api-spec/test/10_basic.yaml @@ -0,0 +1,48 @@ +setup: + - do: + indices.create: + index: test + body: + settings: + mapping.single_type: false + mappings: + type_2: {} + type_3: + _parent: + type: type_2 + +--- +"Parent/child inner hits": + - skip: + version: " - 5.99.99" + reason: mapping.single_type was added in 6.0 + + - do: + index: + index: test + type: type_2 + id: 1 + body: {"foo": "bar"} + + - do: + index: + index: test + type: type_3 + id: 1 + parent: 1 + body: {"bar": "baz"} + + - do: + indices.refresh: {} + + - do: + search: + body: { "query" : { "has_child" : { "type" : "type_3", "query" : { "match_all" : {} }, "inner_hits" : {} } } } + - match: { hits.total: 1 } + - match: { hits.hits.0._index: "test" } + - match: { hits.hits.0._type: "type_2" } + - match: { hits.hits.0._id: "1" } + - is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._index + - match: { hits.hits.0.inner_hits.type_3.hits.hits.0._type: "type_3" } + - match: { hits.hits.0.inner_hits.type_3.hits.hits.0._id: "1" } + - is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._nested diff --git a/modules/percolator/build.gradle b/modules/percolator/build.gradle index 60fb82bdf4e..cf55368861a 100644 --- a/modules/percolator/build.gradle +++ b/modules/percolator/build.gradle @@ -23,5 +23,9 @@ esplugin { hasClientJar = true } +dependencies { + // for testing hasChild and hasParent rejections + testCompile project(path: ':modules:parent-join', configuration: 'runtime') +} compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes" compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes" diff --git a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java index f33aca55bc1..1865f68158e 100644 --- a/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java +++ b/modules/percolator/src/main/java/org/elasticsearch/percolator/PercolatorFieldMapper.java @@ -57,8 +57,6 @@ import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.BoostingQueryBuilder; import org.elasticsearch.index.query.ConstantScoreQueryBuilder; import org.elasticsearch.index.query.DisMaxQueryBuilder; -import org.elasticsearch.index.query.HasChildQueryBuilder; -import org.elasticsearch.index.query.HasParentQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.index.query.QueryShardContext; @@ -372,15 +370,16 @@ public class PercolatorFieldMapper extends FieldMapper { return CONTENT_TYPE; } + /** * Fails if a percolator contains an unsupported query. The following queries are not supported: * 1) a has_child query * 2) a has_parent query */ static void verifyQuery(QueryBuilder queryBuilder) { - if (queryBuilder instanceof HasChildQueryBuilder) { + if (queryBuilder.getName().equals("has_child")) { throw new IllegalArgumentException("the [has_child] query is unsupported inside a percolator query"); - } else if (queryBuilder instanceof HasParentQueryBuilder) { + } else if (queryBuilder.getName().equals("has_parent")) { throw new IllegalArgumentException("the [has_parent] query is unsupported inside a percolator query"); } else if (queryBuilder instanceof BoolQueryBuilder) { BoolQueryBuilder boolQueryBuilder = (BoolQueryBuilder) queryBuilder; diff --git a/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java b/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java index ae585dc9dc7..5a150349ed2 100644 --- a/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java +++ b/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolatorFieldMapperTests.java @@ -52,13 +52,10 @@ import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.ParseContext; import org.elasticsearch.index.mapper.ParsedDocument; import org.elasticsearch.index.mapper.SourceToParse; -import org.elasticsearch.index.mapper.MapperService.MergeReason; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.BoostingQueryBuilder; import org.elasticsearch.index.query.ConstantScoreQueryBuilder; import org.elasticsearch.index.query.DisMaxQueryBuilder; -import org.elasticsearch.index.query.HasChildQueryBuilder; -import org.elasticsearch.index.query.HasParentQueryBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryParseContext; @@ -67,6 +64,9 @@ import org.elasticsearch.index.query.RangeQueryBuilder; import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder; import org.elasticsearch.index.query.functionscore.RandomScoreFunctionBuilder; import org.elasticsearch.indices.TermsLookup; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.join.query.HasChildQueryBuilder; +import org.elasticsearch.join.query.HasParentQueryBuilder; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.script.MockScriptPlugin; import org.elasticsearch.script.Script; @@ -109,7 +109,7 @@ public class PercolatorFieldMapperTests extends ESSingleNodeTestCase { @Override protected Collection> getPlugins() { - return pluginList(InternalSettingsPlugin.class, PercolatorPlugin.class, FoolMeScriptPlugin.class); + return pluginList(InternalSettingsPlugin.class, PercolatorPlugin.class, FoolMeScriptPlugin.class, ParentJoinPlugin.class); } @Before diff --git a/modules/reindex/build.gradle b/modules/reindex/build.gradle index eba8b964617..b636c46d3af 100644 --- a/modules/reindex/build.gradle +++ b/modules/reindex/build.gradle @@ -39,6 +39,8 @@ dependencies { compile "org.elasticsearch.client:rest:${version}" // for http - testing reindex from remote testCompile project(path: ':modules:transport-netty4', configuration: 'runtime') + // for parent/child testing + testCompile project(path: ':modules:parent-join', configuration: 'runtime') } dependencyLicenses { diff --git a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexParentChildTests.java b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexParentChildTests.java index d0eb1dcd75e..8c4135f1f26 100644 --- a/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexParentChildTests.java +++ b/modules/reindex/src/test/java/org/elasticsearch/index/reindex/ReindexParentChildTests.java @@ -22,9 +22,16 @@ package org.elasticsearch.index.reindex; import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder; import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.index.query.QueryBuilder; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; -import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.idsQuery; +import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits; import static org.hamcrest.Matchers.containsString; @@ -40,6 +47,23 @@ public class ReindexParentChildTests extends ReindexTestCase { QueryBuilder findsCity; QueryBuilder findsNeighborhood; + @Override + protected boolean ignoreExternalCluster() { + return true; + } + + @Override + protected Collection> nodePlugins() { + final List> plugins = new ArrayList<>(super.nodePlugins()); + plugins.add(ParentJoinPlugin.class); + return Collections.unmodifiableList(plugins); + } + + @Override + protected Collection> transportClientPlugins() { + return nodePlugins(); + } + public void testParentChild() throws Exception { createParentChildIndex("source"); createParentChildIndex("dest"); diff --git a/modules/reindex/src/test/resources/rest-api-spec/test/reindex/90_remote.yaml b/modules/reindex/src/test/resources/rest-api-spec/test/reindex/90_remote.yaml index b30f263e869..32de51d022a 100644 --- a/modules/reindex/src/test/resources/rest-api-spec/test/reindex/90_remote.yaml +++ b/modules/reindex/src/test/resources/rest-api-spec/test/reindex/90_remote.yaml @@ -158,85 +158,6 @@ metric: search - match: {indices.source.total.search.open_contexts: 0} ---- -"Reindex from remote with parent/child": - - do: - indices.create: - index: source - body: - settings: - mapping.single_type: false - mappings: - foo: {} - bar: - _parent: - type: foo - - do: - indices.create: - index: dest - body: - settings: - mapping.single_type: false - mappings: - foo: {} - bar: - _parent: - type: foo - - do: - index: - index: source - type: foo - id: 1 - body: { "text": "test" } - - do: - index: - index: source - type: bar - id: 1 - parent: 1 - body: { "text": "test2" } - - do: - indices.refresh: {} - - # Fetch the http host. We use the host of the master because we know there will always be a master. - - do: - cluster.state: {} - - set: { master_node: master } - - do: - nodes.info: - metric: [ http ] - - is_true: nodes.$master.http.publish_address - - set: {nodes.$master.http.publish_address: host} - - do: - reindex: - refresh: true - body: - source: - remote: - host: http://${host} - index: source - dest: - index: dest - - match: {created: 2} - - - do: - search: - index: dest - body: - query: - has_parent: - parent_type: foo - query: - match: - text: test - - match: {hits.total: 1} - - # Make sure reindex closed all the scroll contexts - - do: - indices.stats: - index: source - metric: search - - match: {indices.source.total.search.open_contexts: 0} --- "Reindex from remote with timeouts": diff --git a/qa/smoke-test-reindex-with-painless/build.gradle b/qa/smoke-test-reindex-with-all-modules/build.gradle similarity index 89% rename from qa/smoke-test-reindex-with-painless/build.gradle rename to qa/smoke-test-reindex-with-all-modules/build.gradle index b32f4ee80be..cab01cb9412 100644 --- a/qa/smoke-test-reindex-with-painless/build.gradle +++ b/qa/smoke-test-reindex-with-all-modules/build.gradle @@ -22,4 +22,6 @@ apply plugin: 'elasticsearch.rest-test' integTestCluster { setting 'script.max_compilations_per_minute', '1000' -} + // Whitelist reindexing from the local node so we can test it. + setting 'reindex.remote.whitelist', '127.0.0.1:*' +} \ No newline at end of file diff --git a/qa/smoke-test-reindex-with-painless/src/test/java/org/elasticsearch/smoketest/SmokeTestReindexWithPainlessClientYamlTestSuiteIT.java b/qa/smoke-test-reindex-with-all-modules/src/test/java/org/elasticsearch/smoketest/SmokeTestReindexWithPainlessClientYamlTestSuiteIT.java similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/java/org/elasticsearch/smoketest/SmokeTestReindexWithPainlessClientYamlTestSuiteIT.java rename to qa/smoke-test-reindex-with-all-modules/src/test/java/org/elasticsearch/smoketest/SmokeTestReindexWithPainlessClientYamlTestSuiteIT.java diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/10_script.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/10_script.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/10_script.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/10_script.yaml diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/20_broken.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/20_broken.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/20_broken.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/20_broken.yaml diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/30_timeout.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/30_timeout.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/30_timeout.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/30_timeout.yaml diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/40_search_failures.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/40_search_failures.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/reindex/40_search_failures.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/40_search_failures.yaml diff --git a/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/50_reindex_with_parentchild.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/50_reindex_with_parentchild.yaml new file mode 100644 index 00000000000..81e142c9195 --- /dev/null +++ b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/reindex/50_reindex_with_parentchild.yaml @@ -0,0 +1,79 @@ +--- +"Reindex from remote with parent/child": + - do: + indices.create: + index: source + body: + settings: + mapping.single_type: false + mappings: + foo: {} + bar: + _parent: + type: foo + - do: + indices.create: + index: dest + body: + settings: + mapping.single_type: false + mappings: + foo: {} + bar: + _parent: + type: foo + - do: + index: + index: source + type: foo + id: 1 + body: { "text": "test" } + - do: + index: + index: source + type: bar + id: 1 + parent: 1 + body: { "text": "test2" } + - do: + indices.refresh: {} + + # Fetch the http host. We use the host of the master because we know there will always be a master. + - do: + cluster.state: {} + - set: { master_node: master } + - do: + nodes.info: + metric: [ http ] + - is_true: nodes.$master.http.publish_address + - set: {nodes.$master.http.publish_address: host} + - do: + reindex: + refresh: true + body: + source: + remote: + host: http://${host} + index: source + dest: + index: dest + - match: {created: 2} + + - do: + search: + index: dest + body: + query: + has_parent: + parent_type: foo + query: + match: + text: test + - match: {hits.total: 1} + + # Make sure reindex closed all the scroll contexts + - do: + indices.stats: + index: source + metric: search + - match: {indices.source.total.search.open_contexts: 0} diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/10_script.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/10_script.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/10_script.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/10_script.yaml diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/20_broken.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/20_broken.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/20_broken.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/20_broken.yaml diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/30_timeout.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/30_timeout.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/30_timeout.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/30_timeout.yaml diff --git a/qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/40_search_failure.yaml b/qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/40_search_failure.yaml similarity index 100% rename from qa/smoke-test-reindex-with-painless/src/test/resources/rest-api-spec/test/update_by_query/40_search_failure.yaml rename to qa/smoke-test-reindex-with-all-modules/src/test/resources/rest-api-spec/test/update_by_query/40_search_failure.yaml diff --git a/rest-api-spec/src/main/resources/rest-api-spec/test/search.inner_hits/10_basic.yaml b/rest-api-spec/src/main/resources/rest-api-spec/test/search.inner_hits/10_basic.yaml index d50c3dcb574..45524366342 100644 --- a/rest-api-spec/src/main/resources/rest-api-spec/test/search.inner_hits/10_basic.yaml +++ b/rest-api-spec/src/main/resources/rest-api-spec/test/search.inner_hits/10_basic.yaml @@ -11,10 +11,6 @@ setup: properties: nested_field: type: nested - type_2: {} - type_3: - _parent: - type: type_2 --- "Nested inner hits": @@ -47,38 +43,3 @@ setup: - match: { hits.hits.0.inner_hits.nested_field.hits.hits.0._nested.offset: 0 } - is_false: hits.hits.0.inner_hits.nested_field.hits.hits.0._nested.child ---- -"Parent/child inner hits": - - skip: - version: " - 5.99.99" - reason: mapping.single_type was added in 6.0 - - - do: - index: - index: test - type: type_2 - id: 1 - body: {"foo": "bar"} - - - do: - index: - index: test - type: type_3 - id: 1 - parent: 1 - body: {"bar": "baz"} - - - do: - indices.refresh: {} - - - do: - search: - body: { "query" : { "has_child" : { "type" : "type_3", "query" : { "match_all" : {} }, "inner_hits" : {} } } } - - match: { hits.total: 1 } - - match: { hits.hits.0._index: "test" } - - match: { hits.hits.0._type: "type_2" } - - match: { hits.hits.0._id: "1" } - - is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._index - - match: { hits.hits.0.inner_hits.type_3.hits.hits.0._type: "type_3" } - - match: { hits.hits.0.inner_hits.type_3.hits.hits.0._id: "1" } - - is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._nested diff --git a/settings.gradle b/settings.gradle index 7acedd9c98b..b2ef30b99dd 100644 --- a/settings.gradle +++ b/settings.gradle @@ -34,6 +34,7 @@ List projects = [ 'modules:lang-expression', 'modules:lang-mustache', 'modules:lang-painless', + 'modules:parent-join', 'modules:percolator', 'modules:reindex', 'modules:repository-url', @@ -72,7 +73,7 @@ List projects = [ 'qa:smoke-test-ingest-disabled', 'qa:smoke-test-multinode', 'qa:smoke-test-plugins', - 'qa:smoke-test-reindex-with-painless', + 'qa:smoke-test-reindex-with-all-modules', 'qa:smoke-test-tribe-node', 'qa:vagrant', 'qa:wildfly' diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java b/test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java similarity index 100% rename from core/src/test/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java rename to test/framework/src/main/java/org/elasticsearch/search/aggregations/AggregatorTestCase.java diff --git a/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java b/test/framework/src/main/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java similarity index 95% rename from core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java rename to test/framework/src/main/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java index c76d1a5f0dd..e27199918f4 100644 --- a/core/src/test/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/search/aggregations/BaseAggregationTestCase.java @@ -33,6 +33,9 @@ import org.elasticsearch.common.xcontent.XContentType; import org.elasticsearch.env.Environment; import org.elasticsearch.index.query.QueryParseContext; import org.elasticsearch.indices.IndicesModule; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.plugins.PluginsService; +import org.elasticsearch.plugins.SearchPlugin; import org.elasticsearch.search.SearchModule; import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder; import org.elasticsearch.test.AbstractQueryTestCase; @@ -40,6 +43,7 @@ import org.elasticsearch.test.ESTestCase; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; @@ -66,6 +70,10 @@ public abstract class BaseAggregationTestCase> getPlugins() { + return Collections.emptyList(); + } + /** * Setup for the whole base test class. */ @@ -77,7 +85,8 @@ public abstract class BaseAggregationTestCase entries = new ArrayList<>(); entries.addAll(indicesModule.getNamedWriteables()); entries.addAll(searchModule.getNamedWriteables()); @@ -145,7 +154,6 @@ public abstract class BaseAggregationTestCase