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 f9b711e72f692..e7eacfb995c52 100644 --- a/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java +++ b/core/src/main/java/org/elasticsearch/index/query/QueryBuilders.java @@ -471,14 +471,6 @@ public static MoreLikeThisQueryBuilder moreLikeThisQuery(Item[] likeItems) { return moreLikeThisQuery(null, null, likeItems); } - /** - * Constructs a new parent id query that returns all child documents of the specified type that - * point to the specified id. - */ - public static ParentIdQueryBuilder parentId(String type, String id) { - return new ParentIdQueryBuilder(type, id); - } - public static NestedQueryBuilder nestedQuery(String path, QueryBuilder query, ScoreMode scoreMode) { return new NestedQueryBuilder(path, query, scoreMode); } diff --git a/core/src/main/java/org/elasticsearch/search/SearchModule.java b/core/src/main/java/org/elasticsearch/search/SearchModule.java index c15a60e586cb7..a68a5b7fa17de 100644 --- a/core/src/main/java/org/elasticsearch/search/SearchModule.java +++ b/core/src/main/java/org/elasticsearch/search/SearchModule.java @@ -55,7 +55,6 @@ import org.elasticsearch.index.query.MoreLikeThisQueryBuilder; import org.elasticsearch.index.query.MultiMatchQueryBuilder; import org.elasticsearch.index.query.NestedQueryBuilder; -import org.elasticsearch.index.query.ParentIdQueryBuilder; import org.elasticsearch.index.query.PrefixQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryParseContext; @@ -749,7 +748,6 @@ private void registerQueryParsers(List plugins) { registerQuery(new QuerySpec<>(GeoPolygonQueryBuilder.NAME, GeoPolygonQueryBuilder::new, GeoPolygonQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(ExistsQueryBuilder.NAME, ExistsQueryBuilder::new, ExistsQueryBuilder::fromXContent)); registerQuery(new QuerySpec<>(MatchNoneQueryBuilder.NAME, MatchNoneQueryBuilder::new, MatchNoneQueryBuilder::fromXContent)); - registerQuery(new QuerySpec<>(ParentIdQueryBuilder.NAME, ParentIdQueryBuilder::new, ParentIdQueryBuilder::fromXContent)); if (ShapesAvailability.JTS_AVAILABLE && ShapesAvailability.SPATIAL4J_AVAILABLE) { registerQuery(new QuerySpec<>(GeoShapeQueryBuilder.NAME, GeoShapeQueryBuilder::new, GeoShapeQueryBuilder::fromXContent)); diff --git a/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java index 89ffea08681a5..f6122e5a1f9c9 100644 --- a/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/MatchQueryBuilderTests.java @@ -454,7 +454,7 @@ public void testExceptionUsingAnalyzerOnNumericField() { @Override protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { - mapperService.merge("t_boost", new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef("t_boost", + mapperService.merge("doc", new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef("doc", "string_boost", "type=text,boost=4").string()), MapperService.MergeReason.MAPPING_UPDATE, false); } diff --git a/core/src/test/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilderTests.java index a3a9ad3bda04d..5529a64d57f64 100644 --- a/core/src/test/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/MoreLikeThisQueryBuilderTests.java @@ -94,7 +94,7 @@ private static String[] randomStringFields() { private Item generateRandomItem() { String index = randomBoolean() ? getIndex().getName() : null; - String type = getRandomType(); // set to one type to avoid ambiguous types + String type = "doc"; // indexed item or artificial document Item item; if (randomBoolean()) { 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 95f600f035e11..065b8d20ff6e6 100644 --- a/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/NestedQueryBuilderTests.java @@ -59,7 +59,7 @@ protected void initializeAdditionalMappings(MapperService mapperService) throws String geoFieldMapping = (mapperService.getIndexSettings().getIndexVersionCreated() .before(LatLonPointFieldMapper.LAT_LON_FIELD_VERSION)) ? LEGACY_GEO_POINT_FIELD_MAPPING : "type=geo_point"; - mapperService.merge("nested_doc", new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef("nested_doc", + mapperService.merge("doc", new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef("doc", STRING_FIELD_NAME, "type=text", INT_FIELD_NAME, "type=integer", DOUBLE_FIELD_NAME, "type=double", diff --git a/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java index b56b29cfc4034..01c3546ef7de7 100644 --- a/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/QueryStringQueryBuilderTests.java @@ -894,9 +894,9 @@ public void testExistsFieldQuery() throws Exception { public void testDisabledFieldNamesField() throws Exception { QueryShardContext context = createShardContext(); - context.getMapperService().merge("new_type", + context.getMapperService().merge("doc", new CompressedXContent( - PutMappingRequest.buildFromSimplifiedDef("new_type", + PutMappingRequest.buildFromSimplifiedDef("doc", "foo", "type=text", "_field_names", "enabled=false").string()), MapperService.MergeReason.MAPPING_UPDATE, true); @@ -904,9 +904,9 @@ public void testDisabledFieldNamesField() throws Exception { Query query = queryBuilder.toQuery(context); Query expected = new WildcardQuery(new Term("foo", "*")); assertThat(query, equalTo(expected)); - context.getMapperService().merge("new_type", + context.getMapperService().merge("doc", new CompressedXContent( - PutMappingRequest.buildFromSimplifiedDef("new_type", + PutMappingRequest.buildFromSimplifiedDef("doc", "foo", "type=text", "_field_names", "enabled=true").string()), MapperService.MergeReason.MAPPING_UPDATE, true); diff --git a/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java index 7739620534da7..d21a18c083977 100644 --- a/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/SpanTermQueryBuilderTests.java @@ -133,7 +133,7 @@ public void testParseFailsWithMultipleFields() throws IOException { public void testWithMetaDataField() throws IOException { QueryShardContext context = createShardContext(); - for (String field : new String[]{"_type", "_all"}) { + for (String field : new String[]{"field1", "field2"}) { SpanTermQueryBuilder spanTermQueryBuilder = new SpanTermQueryBuilder(field, "toto"); Query query = spanTermQueryBuilder.toQuery(context); Query expected = new SpanTermQuery(new Term(field, "toto")); diff --git a/core/src/test/java/org/elasticsearch/index/query/TypeQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/TypeQueryBuilderTests.java index b01860808ae8c..d2aec9747653d 100644 --- a/core/src/test/java/org/elasticsearch/index/query/TypeQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/TypeQueryBuilderTests.java @@ -19,6 +19,7 @@ package org.elasticsearch.index.query; +import org.apache.lucene.search.MatchAllDocsQuery; import org.apache.lucene.search.MatchNoDocsQuery; import org.apache.lucene.search.Query; import org.apache.lucene.util.BytesRef; @@ -28,11 +29,15 @@ import java.io.IOException; +import static org.hamcrest.Matchers.anyOf; +import static org.hamcrest.Matchers.equalTo; + + public class TypeQueryBuilderTests extends AbstractQueryTestCase { @Override protected TypeQueryBuilder doCreateTestQueryBuilder() { - return new TypeQueryBuilder(getRandomType()); + return new TypeQueryBuilder("doc"); } @Override @@ -40,7 +45,11 @@ protected void doAssertLuceneQuery(TypeQueryBuilder queryBuilder, Query query, S if (createShardContext().getMapperService().documentMapper(queryBuilder.type()) == null) { assertEquals(new MatchNoDocsQuery(), query); } else { - assertEquals(new TypeFieldMapper.TypesQuery(new BytesRef(queryBuilder.type())), query); + assertThat(query, + anyOf( + equalTo(new TypeFieldMapper.TypesQuery(new BytesRef(queryBuilder.type()))), + equalTo(new MatchAllDocsQuery())) + ); } } diff --git a/core/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java b/core/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java index 05264cc8ebfb6..8f24bfb4541b2 100644 --- a/core/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java +++ b/core/src/test/java/org/elasticsearch/index/query/WildcardQueryBuilderTests.java @@ -89,7 +89,7 @@ public void testIllegalArguments() { public void testEmptyValue() throws IOException { QueryShardContext context = createShardContext(); context.setAllowUnmappedFields(true); - WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder(getRandomType(), ""); + WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder("doc", ""); assertEquals(wildcardQueryBuilder.toQuery(context).getClass(), WildcardQuery.class); } @@ -129,7 +129,7 @@ public void testParseFailsWithMultipleFields() throws IOException { public void testWithMetaDataField() throws IOException { QueryShardContext context = createShardContext(); - for (String field : new String[]{"_type", "_all"}) { + for (String field : new String[]{"field1", "field2"}) { WildcardQueryBuilder wildcardQueryBuilder = new WildcardQueryBuilder(field, "toto"); Query query = wildcardQueryBuilder.toQuery(context); Query expected = new WildcardQuery(new Term(field, "toto")); diff --git a/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java b/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java index 05126ca3a1b09..6065cbbdc45ad 100644 --- a/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java +++ b/core/src/test/java/org/elasticsearch/search/SearchModuleTests.java @@ -285,7 +285,6 @@ public List getPipelineAggregations() { "more_like_this", "multi_match", "nested", - "parent_id", "prefix", "query_string", "range", 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 index 83033545cfbb7..d4ee17bc9a171 100644 --- a/modules/parent-join/src/main/java/org/elasticsearch/join/ParentJoinPlugin.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/ParentJoinPlugin.java @@ -27,6 +27,7 @@ import org.elasticsearch.join.mapper.ParentJoinFieldMapper; import org.elasticsearch.join.query.HasChildQueryBuilder; import org.elasticsearch.join.query.HasParentQueryBuilder; +import org.elasticsearch.join.query.ParentIdQueryBuilder; import org.elasticsearch.plugins.MapperPlugin; import org.elasticsearch.plugins.Plugin; import org.elasticsearch.plugins.SearchPlugin; @@ -44,7 +45,8 @@ public ParentJoinPlugin(Settings settings) {} public List> getQueries() { return Arrays.asList( new QuerySpec<>(HasChildQueryBuilder.NAME, HasChildQueryBuilder::new, HasChildQueryBuilder::fromXContent), - new QuerySpec<>(HasParentQueryBuilder.NAME, HasParentQueryBuilder::new, HasParentQueryBuilder::fromXContent) + new QuerySpec<>(HasParentQueryBuilder.NAME, HasParentQueryBuilder::new, HasParentQueryBuilder::fromXContent), + new QuerySpec<>(ParentIdQueryBuilder.NAME, ParentIdQueryBuilder::new, ParentIdQueryBuilder::fromXContent) ); } diff --git a/modules/parent-join/src/main/java/org/elasticsearch/join/query/JoinQueryBuilders.java b/modules/parent-join/src/main/java/org/elasticsearch/join/query/JoinQueryBuilders.java index af778f400f7b3..d3ef43b7f2f1a 100644 --- a/modules/parent-join/src/main/java/org/elasticsearch/join/query/JoinQueryBuilders.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/query/JoinQueryBuilders.java @@ -47,4 +47,11 @@ public static HasParentQueryBuilder hasParentQuery(String type, QueryBuilder que 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. + */ + public static ParentIdQueryBuilder parentId(String type, String id) { + return new ParentIdQueryBuilder(type, id); + } } diff --git a/core/src/main/java/org/elasticsearch/index/query/ParentIdQueryBuilder.java b/modules/parent-join/src/main/java/org/elasticsearch/join/query/ParentIdQueryBuilder.java similarity index 75% rename from core/src/main/java/org/elasticsearch/index/query/ParentIdQueryBuilder.java rename to modules/parent-join/src/main/java/org/elasticsearch/join/query/ParentIdQueryBuilder.java index 7a88e94406cb3..29ff3d38cbedc 100644 --- a/core/src/main/java/org/elasticsearch/index/query/ParentIdQueryBuilder.java +++ b/modules/parent-join/src/main/java/org/elasticsearch/join/query/ParentIdQueryBuilder.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.index.query; +package org.elasticsearch.join.query; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; @@ -35,6 +35,12 @@ import org.elasticsearch.index.mapper.DocumentMapper; import org.elasticsearch.index.mapper.ParentFieldMapper; import org.elasticsearch.index.mapper.TypeFieldMapper; +import org.elasticsearch.index.query.AbstractQueryBuilder; +import org.elasticsearch.index.query.QueryParseContext; +import org.elasticsearch.index.query.QueryShardContext; +import org.elasticsearch.index.query.QueryShardException; +import org.elasticsearch.join.mapper.ParentIdFieldMapper; +import org.elasticsearch.join.mapper.ParentJoinFieldMapper; import java.io.IOException; import java.util.Objects; @@ -156,6 +162,40 @@ public static Optional fromXContent(QueryParseContext pars @Override protected Query doToQuery(QueryShardContext context) throws IOException { + if (context.getIndexSettings().isSingleType() == false) { + // BWC for indices with multiple types + return doToQueryBWC(context); + } + + ParentJoinFieldMapper joinFieldMapper = ParentJoinFieldMapper.getMapper(context.getMapperService()); + if (joinFieldMapper == null) { + if (ignoreUnmapped) { + return new MatchNoDocsQuery(); + } else { + final String indexName = context.getIndexSettings().getIndex().getName(); + throw new QueryShardException(context, "[" + NAME + "] no join field found for index [" + indexName + "]"); + } + } + final ParentIdFieldMapper childMapper = joinFieldMapper.getParentIdFieldMapper(type, false); + if (childMapper == null) { + if (ignoreUnmapped) { + return new MatchNoDocsQuery(); + } else { + throw new QueryShardException(context, "[" + NAME + "] no relation found for child [" + type + "]"); + } + } + return new BooleanQuery.Builder() + .add(childMapper.fieldType().termQuery(id, context), BooleanClause.Occur.MUST) + // Need to take child type into account, otherwise a child doc of different type with the same id could match + .add(joinFieldMapper.fieldType().termQuery(type, context), BooleanClause.Occur.FILTER) + .build(); + } + + /** + * Creates parent_id query from a {@link ParentFieldMapper} + * Only used for BWC with multi-types indices + */ + private Query doToQueryBWC(QueryShardContext context) throws IOException { DocumentMapper childDocMapper = context.getMapperService().documentMapper(type); if (childDocMapper == null) { if (ignoreUnmapped) { @@ -170,11 +210,11 @@ protected Query doToQuery(QueryShardContext context) throws IOException { } String fieldName = ParentFieldMapper.joinField(parentFieldMapper.type()); - BooleanQuery.Builder query = new BooleanQuery.Builder(); - query.add(new DocValuesTermsQuery(fieldName, id), BooleanClause.Occur.MUST); - // Need to take child type into account, otherwise a child doc of different type with the same id could match - query.add(new TermQuery(new Term(TypeFieldMapper.NAME, type)), BooleanClause.Occur.FILTER); - return query.build(); + return new BooleanQuery.Builder() + .add(new DocValuesTermsQuery(fieldName, id), BooleanClause.Occur.MUST) + // Need to take child type into account, otherwise a child doc of different type with the same id could match + .add(new TermQuery(new Term(TypeFieldMapper.NAME, type)), BooleanClause.Occur.FILTER) + .build(); } @Override diff --git a/modules/parent-join/src/test/java/org/elasticsearch/join/query/ChildQuerySearchIT.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/ChildQuerySearchIT.java index 22ec7d50fd5e0..58c0d4b2f5bf1 100644 --- a/modules/parent-join/src/test/java/org/elasticsearch/join/query/ChildQuerySearchIT.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/ChildQuerySearchIT.java @@ -77,7 +77,6 @@ import static org.elasticsearch.index.query.QueryBuilders.idsQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; -import static org.elasticsearch.index.query.QueryBuilders.parentId; import static org.elasticsearch.index.query.QueryBuilders.prefixQuery; import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery; import static org.elasticsearch.index.query.QueryBuilders.termQuery; @@ -86,6 +85,7 @@ import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.weightFactorFunction; import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery; import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery; +import static org.elasticsearch.join.query.JoinQueryBuilders.parentId; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; @@ -1261,27 +1261,31 @@ public void testParentFieldQuery() throws Exception { } public void testParentIdQuery() throws Exception { - if (legacy() == false) { - // Fix parent_id query - return; + if (legacy()) { + assertAcked(prepareCreate("test") + .setSettings(Settings.builder() + .put(indexSettings()) + .put("index.refresh_interval", -1) + ) + .addMapping("parent") + .addMapping("child", "_parent", "type=parent")); + } else { + assertAcked(prepareCreate("test") + .setSettings(Settings.builder() + .put(indexSettings()) + .put("index.refresh_interval", -1) + ) + .addMapping("doc", "join_field", "type=join,parent=child")); } - - assertAcked(prepareCreate("test") - .setSettings(Settings.builder() - .put(indexSettings()) - .put("index.refresh_interval", -1) - ) - .addMapping("parent") - .addMapping("child", "_parent", "type=parent")); ensureGreen(); - client().prepareIndex("test", "child", "c1").setSource("{}", XContentType.JSON).setParent("p1").get(); + createIndexRequest("test", "child", "c1", "p1").get(); refresh(); SearchResponse response = client().prepareSearch("test").setQuery(parentId("child", "p1")).get(); assertHitCount(response, 1L); - client().prepareIndex("test", "child", "c2").setSource("{}", XContentType.JSON).setParent("p2").get(); + createIndexRequest("test", "child", "c2", "p2").get(); refresh(); response = client().prepareSearch("test") diff --git a/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java index 883602bcfb2e8..1e604ee439d7d 100644 --- a/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasChildQueryBuilderTests.java @@ -87,6 +87,14 @@ protected Collection> getPlugins() { return Collections.singletonList(ParentJoinPlugin.class); } + @Override + protected Settings indexSettings() { + return Settings.builder() + .put(super.indexSettings()) + .put("index.mapping.single_type", false) + .build(); + } + @Override protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { similarity = randomFrom("classic", "BM25"); diff --git a/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java index 407928a45419e..186233a97b646 100644 --- a/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/HasParentQueryBuilderTests.java @@ -25,6 +25,7 @@ import org.elasticsearch.Version; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.common.compress.CompressedXContent; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.xcontent.ToXContent; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; @@ -74,6 +75,14 @@ protected Collection> getPlugins() { return Collections.singletonList(ParentJoinPlugin.class); } + @Override + protected Settings indexSettings() { + return Settings.builder() + .put(super.indexSettings()) + .put("index.mapping.single_type", false) + .build(); + } + @Override protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { // TODO: use a single type when inner hits have been changed to work with join field, diff --git a/core/src/test/java/org/elasticsearch/index/query/ParentIdQueryBuilderTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/LegacyParentIdQueryBuilderTests.java similarity index 83% rename from core/src/test/java/org/elasticsearch/index/query/ParentIdQueryBuilderTests.java rename to modules/parent-join/src/test/java/org/elasticsearch/join/query/LegacyParentIdQueryBuilderTests.java index dc220df2d0329..5342e6b0c5d1d 100644 --- a/core/src/test/java/org/elasticsearch/index/query/ParentIdQueryBuilderTests.java +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/LegacyParentIdQueryBuilderTests.java @@ -17,7 +17,7 @@ * under the License. */ -package org.elasticsearch.index.query; +package org.elasticsearch.join.query; import org.apache.lucene.search.BooleanQuery; import org.apache.lucene.search.DocValuesTermsQuery; @@ -26,23 +26,42 @@ import org.apache.lucene.search.TermQuery; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; import org.elasticsearch.common.compress.CompressedXContent; +import org.elasticsearch.common.settings.Settings; import org.elasticsearch.index.mapper.MapperService; import org.elasticsearch.index.mapper.TypeFieldMapper; +import org.elasticsearch.index.query.QueryShardException; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; import org.elasticsearch.search.internal.SearchContext; import org.elasticsearch.test.AbstractQueryTestCase; import org.hamcrest.Matchers; import java.io.IOException; +import java.util.Collection; +import java.util.Collections; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.CoreMatchers.instanceOf; import static org.hamcrest.CoreMatchers.notNullValue; -public class ParentIdQueryBuilderTests extends AbstractQueryTestCase { +public class LegacyParentIdQueryBuilderTests extends AbstractQueryTestCase { protected static final String PARENT_TYPE = "parent"; protected static final String CHILD_TYPE = "child"; + @Override + protected Collection> getPlugins() { + return Collections.singletonList(ParentJoinPlugin.class); + } + + @Override + protected Settings indexSettings() { + return Settings.builder() + .put(super.indexSettings()) + .put("index.mapping.single_type", false) + .build(); + } + @Override protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { mapperService.merge(PARENT_TYPE, new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef(PARENT_TYPE, @@ -84,25 +103,6 @@ protected void doAssertLuceneQuery(ParentIdQueryBuilder queryBuilder, Query quer assertThat(typeQuery.getTerm().text(), Matchers.equalTo(queryBuilder.getType())); } - public void testFromJson() throws IOException { - String query = - "{\n" + - " \"parent_id\" : {\n" + - " \"type\" : \"child\",\n" + - " \"id\" : \"123\",\n" + - " \"ignore_unmapped\" : false,\n" + - " \"boost\" : 3.0,\n" + - " \"_name\" : \"name\"" + - " }\n" + - "}"; - ParentIdQueryBuilder queryBuilder = (ParentIdQueryBuilder) parseQuery(query); - checkGeneratedJson(query, queryBuilder); - assertThat(queryBuilder.getType(), Matchers.equalTo("child")); - assertThat(queryBuilder.getId(), Matchers.equalTo("123")); - assertThat(queryBuilder.boost(), Matchers.equalTo(3f)); - assertThat(queryBuilder.queryName(), Matchers.equalTo("name")); - } - public void testIgnoreUnmapped() throws IOException { final ParentIdQueryBuilder queryBuilder = new ParentIdQueryBuilder("unmapped", "foo"); queryBuilder.ignoreUnmapped(true); diff --git a/modules/parent-join/src/test/java/org/elasticsearch/join/query/ParentIdQueryBuilderTests.java b/modules/parent-join/src/test/java/org/elasticsearch/join/query/ParentIdQueryBuilderTests.java new file mode 100644 index 0000000000000..43d036458b492 --- /dev/null +++ b/modules/parent-join/src/test/java/org/elasticsearch/join/query/ParentIdQueryBuilderTests.java @@ -0,0 +1,134 @@ +/* + * 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.index.Term; +import org.apache.lucene.search.BooleanClause; +import org.apache.lucene.search.BooleanQuery; +import org.apache.lucene.search.DocValuesTermsQuery; +import org.apache.lucene.search.MatchNoDocsQuery; +import org.apache.lucene.search.Query; +import org.apache.lucene.search.TermQuery; +import org.elasticsearch.Version; +import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest; +import org.elasticsearch.cluster.metadata.IndexMetaData; +import org.elasticsearch.common.compress.CompressedXContent; +import org.elasticsearch.common.settings.Settings; +import org.elasticsearch.index.mapper.MapperService; +import org.elasticsearch.index.mapper.TypeFieldMapper; +import org.elasticsearch.index.query.QueryShardException; +import org.elasticsearch.join.ParentJoinPlugin; +import org.elasticsearch.plugins.Plugin; +import org.elasticsearch.search.internal.SearchContext; +import org.elasticsearch.test.AbstractQueryTestCase; +import org.hamcrest.Matchers; + +import java.io.IOException; +import java.util.Collection; +import java.util.Collections; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.notNullValue; + +public class ParentIdQueryBuilderTests extends AbstractQueryTestCase { + + private static final String TYPE = "doc"; + private static final String JOIN_FIELD_NAME = "join_field"; + private static final String PARENT_NAME = "parent"; + private static final String CHILD_NAME = "child"; + + @Override + protected Collection> getPlugins() { + return Collections.singletonList(ParentJoinPlugin.class); + } + + @Override + protected Settings indexSettings() { + return Settings.builder() + .put(super.indexSettings()) + .put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT) + .build(); + } + + @Override + protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { + mapperService.merge(TYPE, new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef(TYPE, + STRING_FIELD_NAME, "type=text", + INT_FIELD_NAME, "type=integer", + DOUBLE_FIELD_NAME, "type=double", + BOOLEAN_FIELD_NAME, "type=boolean", + DATE_FIELD_NAME, "type=date", + OBJECT_FIELD_NAME, "type=object", + JOIN_FIELD_NAME, "type=join,parent=child" + ).string()), MapperService.MergeReason.MAPPING_UPDATE, false); + } + + @Override + protected ParentIdQueryBuilder doCreateTestQueryBuilder() { + return new ParentIdQueryBuilder(CHILD_NAME, randomAlphaOfLength(4)).ignoreUnmapped(randomBoolean()); + } + + @Override + protected void doAssertLuceneQuery(ParentIdQueryBuilder queryBuilder, Query query, SearchContext context) throws IOException { + assertThat(query, Matchers.instanceOf(BooleanQuery.class)); + BooleanQuery booleanQuery = (BooleanQuery) query; + assertThat(booleanQuery.clauses().size(), Matchers.equalTo(2)); + BooleanQuery expected = new BooleanQuery.Builder() + .add(new TermQuery(new Term(JOIN_FIELD_NAME + "#" + PARENT_NAME, queryBuilder.getId())), BooleanClause.Occur.MUST) + .add(new TermQuery(new Term(JOIN_FIELD_NAME, queryBuilder.getType())), BooleanClause.Occur.FILTER) + .build(); + assertThat(expected, equalTo(query)); + } + + public void testFromJson() throws IOException { + String query = + "{\n" + + " \"parent_id\" : {\n" + + " \"type\" : \"child\",\n" + + " \"id\" : \"123\",\n" + + " \"ignore_unmapped\" : false,\n" + + " \"boost\" : 3.0,\n" + + " \"_name\" : \"name\"" + + " }\n" + + "}"; + ParentIdQueryBuilder queryBuilder = (ParentIdQueryBuilder) parseQuery(query); + checkGeneratedJson(query, queryBuilder); + assertThat(queryBuilder.getType(), Matchers.equalTo("child")); + assertThat(queryBuilder.getId(), Matchers.equalTo("123")); + assertThat(queryBuilder.boost(), Matchers.equalTo(3f)); + assertThat(queryBuilder.queryName(), Matchers.equalTo("name")); + } + + public void testIgnoreUnmapped() throws IOException { + final ParentIdQueryBuilder queryBuilder = new ParentIdQueryBuilder("unmapped", "foo"); + queryBuilder.ignoreUnmapped(true); + Query query = queryBuilder.toQuery(createShardContext()); + assertThat(query, notNullValue()); + assertThat(query, instanceOf(MatchNoDocsQuery.class)); + + final ParentIdQueryBuilder failingQueryBuilder = new ParentIdQueryBuilder("unmapped", "foo"); + failingQueryBuilder.ignoreUnmapped(false); + QueryShardException e = expectThrows(QueryShardException.class, () -> failingQueryBuilder.toQuery(createShardContext())); + assertThat(e.getMessage(), containsString("[" + ParentIdQueryBuilder.NAME + "] no relation found for child [unmapped]")); + } + +} diff --git a/modules/parent-join/src/test/resources/rest-api-spec/test/20_parent_join.yml b/modules/parent-join/src/test/resources/rest-api-spec/test/20_parent_join.yml index 97af63ab00722..8f6907e323716 100644 --- a/modules/parent-join/src/test/resources/rest-api-spec/test/20_parent_join.yml +++ b/modules/parent-join/src/test/resources/rest-api-spec/test/20_parent_join.yml @@ -20,6 +20,13 @@ setup: index: test type: doc id: 2 + body: { "join_field": { "name": "parent" } } + + - do: + index: + index: test + type: doc + id: 3 routing: 1 body: { "join_field": { "name": "child", "parent": "1" } } @@ -27,9 +34,25 @@ setup: index: index: test type: doc - id: 3 + id: 4 + routing: 1 + body: { "join_field": { "name": "child", "parent": "1" } } + + - do: + index: + index: test + type: doc + id: 5 + routing: 1 + body: { "join_field": { "name": "child", "parent": "2" } } + + - do: + index: + index: test + type: doc + id: 6 routing: 1 - body: { "join_field": { "name": "grand_child", "parent": "2" } } + body: { "join_field": { "name": "grand_child", "parent": "5" } } - do: indices.refresh: {} @@ -42,24 +65,68 @@ setup: - do: search: - body: { sort: ["join_field"] } + body: { sort: ["join_field", "_id"] } - - match: { hits.total: 3 } + - match: { hits.total: 6 } - match: { hits.hits.0._index: "test" } - match: { hits.hits.0._type: "doc" } - - match: { hits.hits.0._id: "2" } + - match: { hits.hits.0._id: "3" } - match: { hits.hits.0.fields.join_field: ["child"] } - match: { hits.hits.0.fields.join_field#parent: ["1"] } - is_false: hits.hits.0.fields.join_field#child } - match: { hits.hits.1._index: "test" } - match: { hits.hits.1._type: "doc" } - - match: { hits.hits.1._id: "3" } - - match: { hits.hits.1.fields.join_field: ["grand_child"] } - - match: { hits.hits.1.fields.join_field#child: ["2"] } + - match: { hits.hits.1._id: "4" } + - match: { hits.hits.1.fields.join_field: ["child"] } + - match: { hits.hits.1.fields.join_field#parent: ["1"] } + - is_false: hits.hits.1.fields.join_field#child } - match: { hits.hits.2._index: "test" } - match: { hits.hits.2._type: "doc" } - - match: { hits.hits.2._id: "1" } - - match: { hits.hits.2.fields.join_field: ["parent"] } - - is_false: hits.hits.2.fields.join_field#parent + - match: { hits.hits.2._id: "5" } + - match: { hits.hits.2.fields.join_field: ["child"] } + - match: { hits.hits.2.fields.join_field#parent: ["2"] } + - is_false: hits.hits.2.fields.join_field#child } + - match: { hits.hits.3._index: "test" } + - match: { hits.hits.3._type: "doc" } + - match: { hits.hits.3._id: "6" } + - match: { hits.hits.3.fields.join_field: ["grand_child"] } + - match: { hits.hits.3.fields.join_field#child: ["5"] } + - match: { hits.hits.4._index: "test" } + - match: { hits.hits.4._type: "doc" } + - match: { hits.hits.4._id: "1" } + - match: { hits.hits.4.fields.join_field: ["parent"] } + - is_false: hits.hits.4.fields.join_field#parent + - match: { hits.hits.5._index: "test" } + - match: { hits.hits.5._type: "doc" } + - match: { hits.hits.5._id: "2" } + - match: { hits.hits.5.fields.join_field: ["parent"] } + - is_false: hits.hits.5.fields.join_field#parent + +--- +"Test parent_id query": + - skip: + version: " - 5.99.99" + reason: parent-join was added in 6.0 + + - do: + search: + body: + sort: [ "_id" ] + query: + parent_id: + type: child + id: 1 + + - match: { hits.total: 2 } + - match: { hits.hits.0._index: "test" } + - match: { hits.hits.0._type: "doc" } + - match: { hits.hits.0._id: "3" } + - match: { hits.hits.0.fields.join_field: ["child"] } + - match: { hits.hits.0.fields.join_field#parent: ["1"] } + - match: { hits.hits.1._index: "test" } + - match: { hits.hits.1._type: "doc" } + - match: { hits.hits.1._id: "4" } + - match: { hits.hits.1.fields.join_field: ["child"] } + - match: { hits.hits.1.fields.join_field#parent: ["1"] } diff --git a/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolateQueryBuilderTests.java b/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolateQueryBuilderTests.java index 0aaa4a9119dd9..cc5d28c4095b1 100644 --- a/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolateQueryBuilderTests.java +++ b/modules/percolator/src/test/java/org/elasticsearch/percolator/PercolateQueryBuilderTests.java @@ -86,8 +86,8 @@ protected Collection> getPlugins() { @Override protected void initializeAdditionalMappings(MapperService mapperService) throws IOException { queryField = randomAlphaOfLength(4); - docType = randomAlphaOfLength(4); - mapperService.merge("query_type", new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef("query_type", + docType = "doc"; + mapperService.merge("doc", new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef("doc", queryField, "type=percolator" ).string()), MapperService.MergeReason.MAPPING_UPDATE, false); mapperService.merge(docType, new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef(docType, @@ -104,7 +104,7 @@ private PercolateQueryBuilder doCreateTestQueryBuilder(boolean indexedDocument) documentSource = randomSource(); if (indexedDocument) { indexedDocumentIndex = randomAlphaOfLength(4); - indexedDocumentType = randomAlphaOfLength(4); + indexedDocumentType = "doc"; indexedDocumentId = randomAlphaOfLength(4); indexedDocumentRouting = randomAlphaOfLength(4); indexedDocumentPreference = randomAlphaOfLength(4); diff --git a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java index 3ddfb1c0f80ba..77ed5f3d04cf1 100644 --- a/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java +++ b/test/framework/src/main/java/org/elasticsearch/test/AbstractQueryTestCase.java @@ -152,7 +152,6 @@ public abstract class AbstractQueryTestCase> private static ServiceHolder serviceHolder; private static int queryNameId = 0; private static Settings nodeSettings; - private static Settings indexSettings; private static Index index; private static String[] currentTypes; private static String[] randomTypes; @@ -174,28 +173,27 @@ protected void initializeAdditionalMappings(MapperService mapperService) throws @BeforeClass public static void beforeClass() { - // we have to prefer CURRENT since with the range of versions we support it's rather unlikely to get the current actually. - Version indexVersionCreated = randomBoolean() ? Version.CURRENT - : VersionUtils.randomVersionBetween(random(), Version.V_2_0_0_beta1, Version.CURRENT); nodeSettings = Settings.builder() .put("node.name", AbstractQueryTestCase.class.toString()) .put(Environment.PATH_HOME_SETTING.getKey(), createTempDir()) .build(); - indexSettings = Settings.builder() - .put(IndexMetaData.SETTING_VERSION_CREATED, indexVersionCreated).build(); - + index = new Index(randomAlphaOfLengthBetween(1, 10), "_na_"); - //create some random type with some default field, those types will stick around for all of the subclasses - currentTypes = new String[randomIntBetween(0, 5)]; - for (int i = 0; i < currentTypes.length; i++) { - String type = randomAlphaOfLengthBetween(1, 10); - currentTypes[i] = type; - } - //set some random types to be queried as part the search request, before each test + // Set a single type in the index + currentTypes = new String[] { "doc" }; randomTypes = getRandomTypes(); } + protected Settings indexSettings() { + // we have to prefer CURRENT since with the range of versions we support it's rather unlikely to get the current actually. + Version indexVersionCreated = randomBoolean() ? Version.CURRENT + : VersionUtils.randomVersionBetween(random(), null, Version.CURRENT); + return Settings.builder() + .put(IndexMetaData.SETTING_VERSION_CREATED, indexVersionCreated) + .build(); + } + @AfterClass public static void afterClass() throws Exception { IOUtils.close(serviceHolder); @@ -205,7 +203,7 @@ public static void afterClass() throws Exception { @Before public void beforeTest() throws IOException { if (serviceHolder == null) { - serviceHolder = new ServiceHolder(nodeSettings, indexSettings, getPlugins(), this); + serviceHolder = new ServiceHolder(nodeSettings, indexSettings(), getPlugins(), this); } serviceHolder.clientInvocationHandler.delegate = this; } @@ -857,10 +855,6 @@ private static String[] getRandomTypes() { return types; } - protected static String getRandomType() { - return (currentTypes.length == 0) ? MetaData.ALL : randomFrom(currentTypes); - } - protected static Fuzziness randomFuzziness(String fieldName) { switch (fieldName) { case INT_FIELD_NAME: