/* * 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.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; 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.IdsQueryBuilder; import org.elasticsearch.index.query.InnerHitBuilder; import org.elasticsearch.index.query.MatchAllQueryBuilder; 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; import org.elasticsearch.search.aggregations.bucket.filter.Filter; import org.elasticsearch.search.aggregations.bucket.global.Global; import org.elasticsearch.search.aggregations.bucket.terms.Terms; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder; import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder.Field; import org.elasticsearch.search.fetch.subphase.highlight.HighlightField; 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 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; import java.util.Locale; import java.util.Map; 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.idsQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery; 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; 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; 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.anyOf; import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.greaterThanOrEqualTo; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; @ClusterScope(scope = Scope.SUITE) public class ChildQuerySearchIT extends ESIntegTestCase { @Override protected boolean ignoreExternalCluster() { return true; } @Override protected Collection<Class<? extends Plugin>> nodePlugins() { return Collections.singleton(ParentJoinPlugin.class); } @Override protected Collection<Class<? extends Plugin>> transportClientPlugins() { return nodePlugins(); } @Override public Settings indexSettings() { return Settings.builder().put(super.indexSettings()) // aggressive filter caching so that we can assert on the filter cache size .put(IndexModule.INDEX_QUERY_CACHE_ENABLED_SETTING.getKey(), true) .put(IndexModule.INDEX_QUERY_CACHE_EVERYTHING_SETTING.getKey(), true) .build(); } public void testSelfReferentialIsForbidden() { IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> prepareCreate("test").addMapping("type", "_parent", "type=type").get()); assertThat(e.getMessage(), equalTo("The [_parent.type] option can't point to the same type")); } public void testMultiLevelChild() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent") .addMapping("grandchild", "_parent", "type=child")); ensureGreen(); client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "c_value1").setParent("p1").get(); client().prepareIndex("test", "grandchild", "gc1").setSource("gc_field", "gc_value1") .setParent("c1").setRouting("p1").get(); refresh(); SearchResponse searchResponse = client() .prepareSearch("test") .setQuery( boolQuery() .must(matchAllQuery()) .filter(hasChildQuery( "child", boolQuery().must(termQuery("c_field", "c_value1")) .filter(hasChildQuery("grandchild", termQuery("gc_field", "gc_value1"), ScoreMode.None)) , ScoreMode.None))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); 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() .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() .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() .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() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("gc1")); } // see #2744 public void test2744() throws IOException { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("foo") .addMapping("test", "_parent", "type=foo")); ensureGreen(); // index simple data client().prepareIndex("test", "foo", "1").setSource("foo", 1).get(); client().prepareIndex("test", "test").setSource("foo", 1).setParent("1").get(); refresh(); SearchResponse searchResponse = client().prepareSearch("test"). setQuery(hasChildQuery("test", matchQuery("foo", 1), ScoreMode.None)) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("1")); } public void testSimpleChildQuery() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "red").setParent("p1").get(); client().prepareIndex("test", "child", "c2").setSource("c_field", "yellow").setParent("p1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "blue").setParent("p2").get(); client().prepareIndex("test", "child", "c4").setSource("c_field", "red").setParent("p2").get(); refresh(); // TEST FETCHING _parent from child SearchResponse searchResponse = client().prepareSearch("test") .setQuery(idsQuery("child").addIds("c1")).storedFields("_parent").execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c1")); assertThat(searchResponse.getHits().getAt(0).field("_parent").getValue().toString(), equalTo("p1")); // TEST matching on parent searchResponse = client().prepareSearch("test").setQuery(termQuery("_parent#parent", "p1")).storedFields("_parent").get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); assertThat(searchResponse.getHits().getAt(0).getId(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(0).field("_parent").getValue().toString(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(1).getId(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(1).field("_parent").getValue().toString(), equalTo("p1")); searchResponse = client().prepareSearch("test").setQuery(queryStringQuery("_parent#parent:p1")).storedFields("_parent").get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); assertThat(searchResponse.getHits().getAt(0).getId(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(0).field("_parent").getValue().toString(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(1).getId(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(1).field("_parent").getValue().toString(), equalTo("p1")); // HAS CHILD searchResponse = client().prepareSearch("test").setQuery(randomHasChild("child", "c_field", "yellow")) .get(); assertHitCount(searchResponse, 1L); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); searchResponse = client().prepareSearch("test").setQuery(randomHasChild("child", "c_field", "blue")).execute() .actionGet(); assertHitCount(searchResponse, 1L); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p2")); searchResponse = client().prepareSearch("test").setQuery(randomHasChild("child", "c_field", "red")).get(); assertHitCount(searchResponse, 2L); assertThat(searchResponse.getHits().getAt(0).getId(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).getId(), anyOf(equalTo("p2"), equalTo("p1"))); // HAS PARENT searchResponse = client().prepareSearch("test") .setQuery(randomHasParent("parent", "p_field", "p_value2")).get(); assertNoFailures(searchResponse); assertHitCount(searchResponse, 2L); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c3")); assertThat(searchResponse.getHits().getAt(1).getId(), equalTo("c4")); searchResponse = client().prepareSearch("test") .setQuery(randomHasParent("parent", "p_field", "p_value1")).get(); assertHitCount(searchResponse, 2L); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c1")); assertThat(searchResponse.getHits().getAt(1).getId(), equalTo("c2")); } // Issue #3290 public void testCachingBugWithFqueryFilter() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); List<IndexRequestBuilder> builders = new ArrayList<>(); // index simple data for (int i = 0; i < 10; i++) { builders.add(client().prepareIndex("test", "parent", Integer.toString(i)).setSource("p_field", i)); } indexRandom(randomBoolean(), builders); builders.clear(); for (int j = 0; j < 2; j++) { for (int i = 0; i < 10; i++) { 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))); } if (randomBoolean()) { break; // randomly break out and dont' have deletes / updates } } indexRandom(true, builders); for (int i = 1; i <= 10; i++) { logger.info("Round {}", i); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.Max))) .get(); assertNoFailures(searchResponse); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasParentQuery("parent", matchAllQuery(), true))) .get(); assertNoFailures(searchResponse); } } public void testHasParentFilter() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); Map<String, Set<String>> parentToChildren = new HashMap<>(); // Childless parent client().prepareIndex("test", "parent", "p0").setSource("p_field", "p0").get(); parentToChildren.put("p0", new HashSet<>()); String previousParentId = null; int numChildDocs = 32; int numChildDocsPerParent = 0; List<IndexRequestBuilder> builders = new ArrayList<>(); for (int i = 1; i <= numChildDocs; i++) { if (previousParentId == null || i % numChildDocsPerParent == 0) { previousParentId = "p" + i; builders.add(client().prepareIndex("test", "parent", previousParentId).setSource("p_field", previousParentId)); numChildDocsPerParent++; } String childId = "c" + i; builders.add(client().prepareIndex("test", "child", childId).setSource("c_field", childId).setParent(previousParentId)); if (!parentToChildren.containsKey(previousParentId)) { parentToChildren.put(previousParentId, new HashSet<>()); } assertThat(parentToChildren.get(previousParentId).add(childId), is(true)); } indexRandom(true, builders.toArray(new IndexRequestBuilder[builders.size()])); assertThat(parentToChildren.isEmpty(), equalTo(false)); for (Map.Entry<String, Set<String>> parentToChildrenEntry : parentToChildren.entrySet()) { SearchResponse searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", parentToChildrenEntry.getKey()), false))) .setSize(numChildDocsPerParent).get(); assertNoFailures(searchResponse); Set<String> childIds = parentToChildrenEntry.getValue(); assertThat(searchResponse.getHits().getTotalHits(), equalTo((long) childIds.size())); for (int i = 0; i < searchResponse.getHits().getTotalHits(); i++) { assertThat(childIds.remove(searchResponse.getHits().getAt(i).getId()), is(true)); assertThat(searchResponse.getHits().getAt(i).getScore(), is(1.0f)); } assertThat(childIds.size(), is(0)); } } public void testSimpleChildQueryWithFlush() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data with flushes, so we have many segments client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().admin().indices().prepareFlush().get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "red").setParent("p1").get(); client().admin().indices().prepareFlush().get(); client().prepareIndex("test", "child", "c2").setSource("c_field", "yellow").setParent("p1").get(); client().admin().indices().prepareFlush().get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().admin().indices().prepareFlush().get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "blue").setParent("p2").get(); client().admin().indices().prepareFlush().get(); client().prepareIndex("test", "child", "c4").setSource("c_field", "red").setParent("p2").get(); client().admin().indices().prepareFlush().get(); refresh(); // HAS CHILD QUERY SearchResponse searchResponse = client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.None)) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); searchResponse = client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "blue"), ScoreMode.None)) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p2")); searchResponse = client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "red"), ScoreMode.None)) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); assertThat(searchResponse.getHits().getAt(0).getId(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).getId(), anyOf(equalTo("p2"), equalTo("p1"))); // HAS CHILD FILTER searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.None))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "blue"), ScoreMode.None))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p2")); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "red"), ScoreMode.None))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); assertThat(searchResponse.getHits().getAt(0).getId(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).getId(), anyOf(equalTo("p2"), equalTo("p1"))); } public void testScopedFacet() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent", "c_field", "type=keyword")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "red").setParent("p1").get(); client().prepareIndex("test", "child", "c2").setSource("c_field", "yellow").setParent("p1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "blue").setParent("p2").get(); client().prepareIndex("test", "child", "c4").setSource("c_field", "red").setParent("p2").get(); refresh(); SearchResponse searchResponse = client() .prepareSearch("test") .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.terms("facet1").field("c_field")))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); assertThat(searchResponse.getHits().getAt(0).getId(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).getId(), anyOf(equalTo("p2"), equalTo("p1"))); Global global = searchResponse.getAggregations().get("global"); Filter filter = global.getAggregations().get("filter"); Terms termsFacet = filter.getAggregations().get("facet1"); assertThat(termsFacet.getBuckets().size(), equalTo(2)); assertThat(termsFacet.getBuckets().get(0).getKeyAsString(), equalTo("red")); assertThat(termsFacet.getBuckets().get(0).getDocCount(), equalTo(2L)); assertThat(termsFacet.getBuckets().get(1).getKeyAsString(), equalTo("yellow")); assertThat(termsFacet.getBuckets().get(1).getDocCount(), equalTo(1L)); } public void testDeletedParent() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "red").setParent("p1").get(); client().prepareIndex("test", "child", "c2").setSource("c_field", "yellow").setParent("p1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "blue").setParent("p2").get(); client().prepareIndex("test", "child", "c4").setSource("c_field", "red").setParent("p2").get(); refresh(); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.None))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).getSourceAsString(), containsString("\"p_value1\"")); // update p1 and see what that we get updated values... client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1_updated").get(); client().admin().indices().prepareRefresh().get(); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.None))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).getSourceAsString(), containsString("\"p_value1_updated\"")); } public void testDfsSearchType() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "red").setParent("p1").get(); client().prepareIndex("test", "child", "c2").setSource("c_field", "yellow").setParent("p1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "blue").setParent("p2").get(); client().prepareIndex("test", "child", "c4").setSource("c_field", "red").setParent("p2").get(); refresh(); SearchResponse searchResponse = client().prepareSearch("test").setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(boolQuery().mustNot(hasChildQuery("child", boolQuery().should(queryStringQuery("c_field:*")), ScoreMode.None))) .get(); assertNoFailures(searchResponse); searchResponse = client().prepareSearch("test").setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(boolQuery().mustNot(hasParentQuery("parent", boolQuery().should(queryStringQuery("p_field:*")), false))).execute() .actionGet(); assertNoFailures(searchResponse); } public void testHasChildAndHasParentFailWhenSomeSegmentsDontContainAnyParentOrChildDocs() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); client().prepareIndex("test", "parent", "1").setSource("p_field", 1).get(); client().prepareIndex("test", "child", "1").setParent("1").setSource("c_field", 1).get(); client().admin().indices().prepareFlush("test").get(); client().prepareIndex("test", "type1", "1").setSource("p_field", 1).get(); client().admin().indices().prepareFlush("test").get(); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(boolQuery().must(matchAllQuery()).filter(hasChildQuery("child", matchAllQuery(), ScoreMode.None))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); searchResponse = client().prepareSearch("test") .setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("parent", matchAllQuery(), false))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); } public void testCountApiUsage() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); String parentId = "p1"; client().prepareIndex("test", "parent", parentId).setSource("p_field", "1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "1").setParent(parentId).get(); refresh(); SearchResponse countResponse = client().prepareSearch("test").setSize(0) .setQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.Max)) .get(); assertHitCount(countResponse, 1L); countResponse = client().prepareSearch("test").setSize(0) .setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true)) .get(); assertHitCount(countResponse, 1L); countResponse = client().prepareSearch("test").setSize(0) .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.None))) .get(); assertHitCount(countResponse, 1L); countResponse = client().prepareSearch("test").setSize(0) .setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1"), false))) .get(); assertHitCount(countResponse, 1L); } public void testExplainUsage() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); String parentId = "p1"; client().prepareIndex("test", "parent", parentId).setSource("p_field", "1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "1").setParent(parentId).get(); refresh(); SearchResponse searchResponse = client().prepareSearch("test") .setExplain(true) .setQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.Max)) .get(); assertHitCount(searchResponse, 1L); assertThat(searchResponse.getHits().getAt(0).getExplanation().getDescription(), containsString("join value p1")); searchResponse = client().prepareSearch("test") .setExplain(true) .setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true)) .get(); assertHitCount(searchResponse, 1L); assertThat(searchResponse.getHits().getAt(0).getExplanation().getDescription(), containsString("join value p1")); ExplainResponse explainResponse = client().prepareExplain("test", "parent", parentId) .setQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.Max)) .get(); assertThat(explainResponse.isExists(), equalTo(true)); assertThat(explainResponse.getExplanation().getDetails()[0].getDescription(), containsString("join value p1")); } List<IndexRequestBuilder> createDocBuilders() { List<IndexRequestBuilder> indexBuilders = new ArrayList<>(); // Parent 1 and its children indexBuilders.add(client().prepareIndex().setType("parent").setId("1").setIndex("test").setSource("p_field", "p_value1")); indexBuilders.add(client().prepareIndex().setType("child").setId("1").setIndex("test") .setSource("c_field1", 1, "c_field2", 0).setParent("1")); indexBuilders.add(client().prepareIndex().setType("child").setId("2").setIndex("test") .setSource("c_field1", 1, "c_field2", 0).setParent("1")); indexBuilders.add(client().prepareIndex().setType("child").setId("3").setIndex("test") .setSource("c_field1", 2, "c_field2", 0).setParent("1")); indexBuilders.add(client().prepareIndex().setType("child").setId("4").setIndex("test") .setSource("c_field1", 2, "c_field2", 0).setParent("1")); indexBuilders.add(client().prepareIndex().setType("child").setId("5").setIndex("test") .setSource("c_field1", 1, "c_field2", 1).setParent("1")); indexBuilders.add(client().prepareIndex().setType("child").setId("6").setIndex("test") .setSource("c_field1", 1, "c_field2", 2).setParent("1")); // Parent 2 and its children indexBuilders.add(client().prepareIndex().setType("parent").setId("2").setIndex("test").setSource("p_field", "p_value2")); indexBuilders.add(client().prepareIndex().setType("child").setId("7").setIndex("test") .setSource("c_field1", 3, "c_field2", 0).setParent("2")); indexBuilders.add(client().prepareIndex().setType("child").setId("8").setIndex("test") .setSource("c_field1", 1, "c_field2", 1).setParent("2")); indexBuilders.add(client().prepareIndex().setType("child").setId("9").setIndex("test") .setSource("c_field1", 1, "c_field2", 1).setParent("p")); // why // "p"???? indexBuilders.add(client().prepareIndex().setType("child").setId("10").setIndex("test") .setSource("c_field1", 1, "c_field2", 1).setParent("2")); indexBuilders.add(client().prepareIndex().setType("child").setId("11").setIndex("test") .setSource("c_field1", 1, "c_field2", 1).setParent("2")); indexBuilders.add(client().prepareIndex().setType("child").setId("12").setIndex("test") .setSource("c_field1", 1, "c_field2", 2).setParent("2")); // Parent 3 and its children indexBuilders.add(client().prepareIndex().setType("parent").setId("3").setIndex("test") .setSource("p_field1", "p_value3", "p_field2", 5)); indexBuilders.add(client().prepareIndex().setType("child").setId("13").setIndex("test") .setSource("c_field1", 4, "c_field2", 0, "c_field3", 0).setParent("3")); indexBuilders.add(client().prepareIndex().setType("child").setId("14").setIndex("test") .setSource("c_field1", 1, "c_field2", 1, "c_field3", 1).setParent("3")); indexBuilders.add(client().prepareIndex().setType("child").setId("15").setIndex("test") .setSource("c_field1", 1, "c_field2", 2, "c_field3", 2).setParent("3")); // why // "p"???? indexBuilders.add(client().prepareIndex().setType("child").setId("16").setIndex("test") .setSource("c_field1", 1, "c_field2", 2, "c_field3", 3).setParent("3")); indexBuilders.add(client().prepareIndex().setType("child").setId("17").setIndex("test") .setSource("c_field1", 1, "c_field2", 2, "c_field3", 4).setParent("3")); indexBuilders.add(client().prepareIndex().setType("child").setId("18").setIndex("test") .setSource("c_field1", 1, "c_field2", 2, "c_field3", 5).setParent("3")); indexBuilders.add(client().prepareIndex().setType("child1").setId("1").setIndex("test") .setSource("c_field1", 1, "c_field2", 2, "c_field3", 6).setParent("3")); return indexBuilders; } public void testScoreForParentChildQueriesWithFunctionScore() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent") .addMapping("child1", "_parent", "type=parent")); ensureGreen(); indexRandom(true, createDocBuilders().toArray(new IndexRequestBuilder[0])); SearchResponse response = client() .prepareSearch("test") .setQuery( 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")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(6f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(4f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(3f)); response = client() .prepareSearch("test") .setQuery( 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")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(4f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("2")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("1")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(2f)); response = client() .prepareSearch("test") .setQuery( 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")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(4f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("2")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("1")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1.5f)); response = client() .prepareSearch("test") .setQuery( 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)); assertThat(response.getHits().getHits()[0].getId(), equalTo("13")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(5f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("14")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(5f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("15")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(5f)); assertThat(response.getHits().getHits()[3].getId(), equalTo("16")); assertThat(response.getHits().getHits()[3].getScore(), equalTo(5f)); assertThat(response.getHits().getHits()[4].getId(), equalTo("17")); assertThat(response.getHits().getHits()[4].getScore(), equalTo(5f)); assertThat(response.getHits().getHits()[5].getId(), equalTo("18")); assertThat(response.getHits().getHits()[5].getScore(), equalTo(5f)); assertThat(response.getHits().getHits()[6].getId(), equalTo("1")); assertThat(response.getHits().getHits()[6].getScore(), equalTo(5f)); } // Issue #2536 public void testParentChildQueriesCanHandleNoRelevantTypesInIndex() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); SearchResponse response = client().prepareSearch("test") .setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); client().prepareIndex("test", "child1").setSource(jsonBuilder().startObject().field("text", "value").endObject()) .setRefreshPolicy(RefreshPolicy.IMMEDIATE).get(); response = client().prepareSearch("test") .setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); 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(hasParentQuery("parent", matchQuery("text", "value"), false)).get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); response = client().prepareSearch("test").setQuery(hasParentQuery("parent", matchQuery("text", "value"), true)) .get(); assertNoFailures(response); assertThat(response.getHits().getTotalHits(), equalTo(0L)); } public void testHasChildAndHasParentFilter_withFilter() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); client().prepareIndex("test", "parent", "1").setSource("p_field", 1).get(); client().prepareIndex("test", "child", "2").setParent("1").setSource("c_field", 1).get(); client().admin().indices().prepareFlush("test").get(); client().prepareIndex("test", "type1", "3").setSource("p_field", 2).get(); client().admin().indices().prepareFlush("test").get(); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(boolQuery().must(matchAllQuery()).filter(hasChildQuery("child", termQuery("c_field", 1), ScoreMode.None))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); 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(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("2")); } public void testHasChildInnerHitsHighlighting() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); client().prepareIndex("test", "parent", "1").setSource("p_field", 1).get(); client().prepareIndex("test", "child", "2").setParent("1").setSource("c_field", "foo bar").get(); client().admin().indices().prepareFlush("test").get(); SearchResponse searchResponse = client().prepareSearch("test").setQuery( hasChildQuery("child", matchQuery("c_field", "foo"), ScoreMode.None) .innerHit(new InnerHitBuilder().setHighlightBuilder( new HighlightBuilder().field(new Field("c_field") .highlightQuery(QueryBuilders.matchQuery("c_field", "bar")))), false)) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("1")); SearchHit[] searchHits = searchResponse.getHits().getHits()[0].getInnerHits().get("child").getHits(); assertThat(searchHits.length, equalTo(1)); assertThat(searchHits[0].getHighlightFields().get("c_field").getFragments().length, equalTo(1)); assertThat(searchHits[0].getHighlightFields().get("c_field").getFragments()[0].string(), equalTo("foo <em>bar</em>")); } public void testHasChildAndHasParentWrappedInAQueryFilter() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // query filter in case for p/c shouldn't execute per segment, but rather client().prepareIndex("test", "parent", "1").setSource("p_field", 1).get(); client().admin().indices().prepareFlush("test").setForce(true).get(); client().prepareIndex("test", "child", "2").setParent("1").setSource("c_field", 1).get(); refresh(); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(boolQuery().must(matchAllQuery()).filter(hasChildQuery("child", matchQuery("c_field", 1), ScoreMode.None))) .get(); assertSearchHit(searchResponse, 1, hasId("1")); searchResponse = client().prepareSearch("test") .setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("parent", matchQuery("p_field", 1), false))).get(); assertSearchHit(searchResponse, 1, hasId("2")); searchResponse = client().prepareSearch("test") .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(); assertSearchHit(searchResponse, 1, hasId("2")); } public void testSimpleQueryRewrite() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent", "p_field", "type=keyword") .addMapping("child", "_parent", "type=parent", "c_field", "type=keyword")); ensureGreen(); // index simple data int childId = 0; for (int i = 0; i < 10; i++) { String parentId = String.format(Locale.ROOT, "p%03d", i); client().prepareIndex("test", "parent", parentId).setSource("p_field", parentId).get(); int j = childId; for (; j < childId + 50; j++) { String childUid = String.format(Locale.ROOT, "c%03d", j); client().prepareIndex("test", "child", childUid).setSource("c_field", childUid).setParent(parentId).get(); } childId = j; } refresh(); SearchType[] searchTypes = new SearchType[]{SearchType.QUERY_THEN_FETCH, SearchType.DFS_QUERY_THEN_FETCH}; for (SearchType searchType : searchTypes) { SearchResponse searchResponse = client().prepareSearch("test").setSearchType(searchType) .setQuery(hasChildQuery("child", prefixQuery("c_field", "c"), ScoreMode.Max)) .addSort("p_field", SortOrder.ASC) .setSize(5).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(10L)); assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("p000")); assertThat(searchResponse.getHits().getHits()[1].getId(), equalTo("p001")); assertThat(searchResponse.getHits().getHits()[2].getId(), equalTo("p002")); assertThat(searchResponse.getHits().getHits()[3].getId(), equalTo("p003")); assertThat(searchResponse.getHits().getHits()[4].getId(), equalTo("p004")); searchResponse = client().prepareSearch("test").setSearchType(searchType) .setQuery(hasParentQuery("parent", prefixQuery("p_field", "p"), true)).addSort("c_field", SortOrder.ASC) .setSize(5).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(500L)); assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("c000")); assertThat(searchResponse.getHits().getHits()[1].getId(), equalTo("c001")); assertThat(searchResponse.getHits().getHits()[2].getId(), equalTo("c002")); assertThat(searchResponse.getHits().getHits()[3].getId(), equalTo("c003")); assertThat(searchResponse.getHits().getHits()[4].getId(), equalTo("c004")); } } // Issue #3144 public void testReIndexingParentAndChildDocuments() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "red").setParent("p1").get(); client().prepareIndex("test", "child", "c2").setSource("c_field", "yellow").setParent("p1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "x").setParent("p2").get(); client().prepareIndex("test", "child", "c4").setSource("c_field", "x").setParent("p2").get(); refresh(); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.Total)).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).getSourceAsString(), containsString("\"p_value1\"")); searchResponse = client() .prepareSearch("test") .setQuery( boolQuery().must(matchQuery("c_field", "x")).must( hasParentQuery("parent", termQuery("p_field", "p_value2"), true))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c3")); assertThat(searchResponse.getHits().getAt(1).getId(), equalTo("c4")); // re-index for (int i = 0; i < 10; i++) { client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "d" + i).setSource("c_field", "red").setParent("p1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "x").setParent("p2").get(); client().admin().indices().prepareRefresh("test").get(); } searchResponse = client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.Total)) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).getSourceAsString(), containsString("\"p_value1\"")); searchResponse = client() .prepareSearch("test") .setQuery( boolQuery().must(matchQuery("c_field", "x")).must( hasParentQuery("parent", termQuery("p_field", "p_value2"), true))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); assertThat(searchResponse.getHits().getAt(0).getId(), Matchers.anyOf(equalTo("c3"), equalTo("c4"))); assertThat(searchResponse.getHits().getAt(1).getId(), Matchers.anyOf(equalTo("c3"), equalTo("c4"))); } // Issue #3203 public void testHasChildQueryWithMinimumScore() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "x").setParent("p1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c3").setSource("c_field", "x").setParent("p2").get(); client().prepareIndex("test", "child", "c4").setSource("c_field", "x").setParent("p2").get(); client().prepareIndex("test", "child", "c5").setSource("c_field", "x").setParent("p2").get(); refresh(); SearchResponse searchResponse = client() .prepareSearch("test").setQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.Total)) .setMinScore(3) // Score needs to be 3 or above! .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p2")); assertThat(searchResponse.getHits().getAt(0).getScore(), equalTo(3.0f)); } public void testParentFieldQuery() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.refresh_interval", -1, "index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); SearchResponse response = client().prepareSearch("test").setQuery(termQuery("_parent", "p1")) .get(); assertHitCount(response, 0L); client().prepareIndex("test", "child", "c1").setSource("{}", XContentType.JSON).setParent("p1").get(); refresh(); response = client().prepareSearch("test").setQuery(termQuery("_parent#parent", "p1")).get(); assertHitCount(response, 1L); response = client().prepareSearch("test").setQuery(queryStringQuery("_parent#parent:p1")).get(); assertHitCount(response, 1L); client().prepareIndex("test", "child", "c2").setSource("{}", XContentType.JSON).setParent("p2").get(); refresh(); response = client().prepareSearch("test").setQuery(termsQuery("_parent#parent", "p1", "p2")).get(); assertHitCount(response, 2L); response = client().prepareSearch("test") .setQuery(boolQuery() .should(termQuery("_parent#parent", "p1")) .should(termQuery("_parent#parent", "p2")) ).get(); assertHitCount(response, 2L); } public void testParentIdQuery() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.refresh_interval", -1, "index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); client().prepareIndex("test", "child", "c1").setSource("{}", XContentType.JSON).setParent("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(); refresh(); response = client().prepareSearch("test") .setQuery(boolQuery() .should(parentId("child", "p1")) .should(parentId("child", "p2")) ).get(); assertHitCount(response, 2L); } public void testHasChildNotBeingCached() throws IOException { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "parent", "p3").setSource("p_field", "p_value3").get(); client().prepareIndex("test", "parent", "p4").setSource("p_field", "p_value4").get(); client().prepareIndex("test", "parent", "p5").setSource("p_field", "p_value5").get(); client().prepareIndex("test", "parent", "p6").setSource("p_field", "p_value6").get(); client().prepareIndex("test", "parent", "p7").setSource("p_field", "p_value7").get(); client().prepareIndex("test", "parent", "p8").setSource("p_field", "p_value8").get(); client().prepareIndex("test", "parent", "p9").setSource("p_field", "p_value9").get(); client().prepareIndex("test", "parent", "p10").setSource("p_field", "p_value10").get(); client().prepareIndex("test", "child", "c1").setParent("p1").setSource("c_field", "blue").get(); client().admin().indices().prepareFlush("test").get(); client().admin().indices().prepareRefresh("test").get(); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "blue"), ScoreMode.None))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); client().prepareIndex("test", "child", "c2").setParent("p2").setSource("c_field", "blue").get(); client().admin().indices().prepareRefresh("test").get(); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "blue"), ScoreMode.None))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); } private QueryBuilder randomHasChild(String type, String field, String value) { if (randomBoolean()) { if (randomBoolean()) { return constantScoreQuery(hasChildQuery(type, termQuery(field, value), ScoreMode.None)); } else { return boolQuery().must(matchAllQuery()).filter(hasChildQuery(type, termQuery(field, value), ScoreMode.None)); } } else { return hasChildQuery(type, termQuery(field, value), ScoreMode.None); } } private QueryBuilder randomHasParent(String type, String field, String value) { if (randomBoolean()) { if (randomBoolean()) { return constantScoreQuery(hasParentQuery(type, termQuery(field, value), false)); } else { return boolQuery().must(matchAllQuery()).filter(hasParentQuery(type, termQuery(field, value), false)); } } else { return hasParentQuery(type, termQuery(field, value), false); } } // Issue #3818 public void testHasChildQueryOnlyReturnsSingleChildType() { assertAcked(prepareCreate("grandissue") .setSettings("index.mapping.single_type", false) .addMapping("grandparent", "name", "type=text") .addMapping("parent", "_parent", "type=grandparent") .addMapping("child_type_one", "_parent", "type=parent") .addMapping("child_type_two", "_parent", "type=parent")); client().prepareIndex("grandissue", "grandparent", "1").setSource("name", "Grandpa").get(); client().prepareIndex("grandissue", "parent", "2").setParent("1").setSource("name", "Dana").get(); client().prepareIndex("grandissue", "child_type_one", "3").setParent("2").setRouting("1") .setSource("name", "William") .get(); client().prepareIndex("grandissue", "child_type_two", "4").setParent("2").setRouting("1") .setSource("name", "Kate") .get(); refresh(); SearchResponse searchResponse = client().prepareSearch("grandissue").setQuery( boolQuery().must( hasChildQuery( "parent", boolQuery().must( hasChildQuery( "child_type_one", boolQuery().must( queryStringQuery("name:William*") ), ScoreMode.None) ), ScoreMode.None) ) ).get(); assertHitCount(searchResponse, 1L); searchResponse = client().prepareSearch("grandissue").setQuery( boolQuery().must( hasChildQuery( "parent", boolQuery().must( hasChildQuery( "child_type_two", boolQuery().must( queryStringQuery("name:William*") ), ScoreMode.None) ), ScoreMode.None) ) ).get(); assertHitCount(searchResponse, 0L); } public void testIndexChildDocWithNoParentMapping() throws IOException { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child1")); ensureGreen(); client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); try { client().prepareIndex("test", "child1", "c1").setParent("p1").setSource("c_field", "blue").get(); fail(); } catch (IllegalArgumentException e) { assertThat(e.toString(), containsString("can't specify parent if no parent field has been configured")); } try { client().prepareIndex("test", "child2", "c2").setParent("p1").setSource("c_field", "blue").get(); fail(); } catch (IllegalArgumentException e) { assertThat(e.toString(), containsString("can't specify parent if no parent field has been configured")); } refresh(); } public void testAddingParentToExistingMapping() throws IOException { createIndex("test"); ensureGreen(); PutMappingResponse putMappingResponse = client().admin().indices() .preparePutMapping("test").setType("child").setSource("number", "type=integer") .get(); assertThat(putMappingResponse.isAcknowledged(), equalTo(true)); GetMappingsResponse getMappingsResponse = client().admin().indices().prepareGetMappings("test").get(); Map<String, Object> mapping = getMappingsResponse.getMappings().get("test").get("child").getSourceAsMap(); assertThat(mapping.size(), greaterThanOrEqualTo(1)); // there are potentially some meta fields configured randomly assertThat(mapping.get("properties"), notNullValue()); try { // Adding _parent metadata field to existing mapping is prohibited: client().admin().indices().preparePutMapping("test").setType("child").setSource(jsonBuilder().startObject().startObject("child") .startObject("_parent").field("type", "parent").endObject() .endObject().endObject()).get(); fail(); } catch (IllegalArgumentException e) { assertThat(e.toString(), containsString("The _parent field's type option can't be changed: [null]->[parent]")); } } public void testHasChildQueryWithNestedInnerObjects() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent", "objects", "type=nested") .addMapping("child", "_parent", "type=parent")); ensureGreen(); client().prepareIndex("test", "parent", "p1") .setSource(jsonBuilder().startObject().field("p_field", "1").startArray("objects") .startObject().field("i_field", "1").endObject() .startObject().field("i_field", "2").endObject() .startObject().field("i_field", "3").endObject() .startObject().field("i_field", "4").endObject() .startObject().field("i_field", "5").endObject() .startObject().field("i_field", "6").endObject() .endArray().endObject()) .get(); client().prepareIndex("test", "parent", "p2") .setSource(jsonBuilder().startObject().field("p_field", "2").startArray("objects") .startObject().field("i_field", "1").endObject() .startObject().field("i_field", "2").endObject() .endArray().endObject()) .get(); client().prepareIndex("test", "child", "c1").setParent("p1").setSource("c_field", "blue").get(); client().prepareIndex("test", "child", "c2").setParent("p1").setSource("c_field", "red").get(); client().prepareIndex("test", "child", "c3").setParent("p2").setSource("c_field", "red").get(); refresh(); ScoreMode scoreMode = randomFrom(ScoreMode.values()); SearchResponse searchResponse = client().prepareSearch("test") .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(hasChildQuery("child", termQuery("c_field", "red"), scoreMode)) .filter(boolQuery().mustNot(termQuery("p_field", "3")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); } public void testNamedFilters() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); String parentId = "p1"; client().prepareIndex("test", "parent", parentId).setSource("p_field", "1").get(); 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")) .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")) .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"))) .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"))) .get(); assertHitCount(searchResponse, 1L); assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("test")); } public void testParentChildQueriesNoParentType() throws Exception { assertAcked(prepareCreate("test") .setSettings(Settings.builder() .put(indexSettings()) .put("index.refresh_interval", -1))); ensureGreen(); String parentId = "p1"; client().prepareIndex("test", "parent", parentId).setSource("p_field", "1").get(); refresh(); try { client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.None)) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.Max)) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setPostFilter(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.None)) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true)) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setPostFilter(hasParentQuery("parent", termQuery("p_field", "1"), false)) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } } public void testParentChildCaching() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.refresh_interval", -1, "index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); // index simple data client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "parent", "p2").setSource("p_field", "p_value2").get(); client().prepareIndex("test", "child", "c1").setParent("p1").setSource("c_field", "blue").get(); client().prepareIndex("test", "child", "c2").setParent("p1").setSource("c_field", "red").get(); client().prepareIndex("test", "child", "c3").setParent("p2").setSource("c_field", "red").get(); client().admin().indices().prepareForceMerge("test").setMaxNumSegments(1).setFlush(true).get(); client().prepareIndex("test", "parent", "p3").setSource("p_field", "p_value3").get(); client().prepareIndex("test", "parent", "p4").setSource("p_field", "p_value4").get(); client().prepareIndex("test", "child", "c4").setParent("p3").setSource("c_field", "green").get(); client().prepareIndex("test", "child", "c5").setParent("p3").setSource("c_field", "blue").get(); client().prepareIndex("test", "child", "c6").setParent("p4").setSource("c_field", "blue").get(); client().admin().indices().prepareFlush("test").get(); client().admin().indices().prepareRefresh("test").get(); for (int i = 0; i < 2; i++) { SearchResponse searchResponse = client().prepareSearch() .setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery() .must(hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None)) .must(matchAllQuery()))) .get(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L)); } client().prepareIndex("test", "child", "c3").setParent("p2").setSource("c_field", "blue").get(); client().admin().indices().prepareRefresh("test").get(); SearchResponse searchResponse = client().prepareSearch() .setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery() .must(hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None)) .must(matchAllQuery()))) .get(); assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L)); } public void testParentChildQueriesViaScrollApi() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); for (int i = 0; i < 10; i++) { client().prepareIndex("test", "parent", "p" + i).setSource("{}", XContentType.JSON).get(); client().prepareIndex("test", "child", "c" + i).setSource("{}", XContentType.JSON).setParent("p" + i).get(); } refresh(); QueryBuilder[] queries = new QueryBuilder[]{ hasChildQuery("child", matchAllQuery(), ScoreMode.None), boolQuery().must(matchAllQuery()).filter(hasChildQuery("child", matchAllQuery(), ScoreMode.None)), hasParentQuery("parent", matchAllQuery(), false), boolQuery().must(matchAllQuery()).filter(hasParentQuery("parent", matchAllQuery(), false)) }; for (QueryBuilder query : queries) { SearchResponse scrollResponse = client().prepareSearch("test") .setScroll(TimeValue.timeValueSeconds(30)) .setSize(1) .addStoredField("_id") .setQuery(query) .execute() .actionGet(); assertNoFailures(scrollResponse); assertThat(scrollResponse.getHits().getTotalHits(), equalTo(10L)); int scannedDocs = 0; do { assertThat(scrollResponse.getHits().getTotalHits(), equalTo(10L)); scannedDocs += scrollResponse.getHits().getHits().length; scrollResponse = client() .prepareSearchScroll(scrollResponse.getScrollId()) .setScroll(TimeValue.timeValueSeconds(30)).get(); } while (scrollResponse.getHits().getHits().length > 0); clearScroll(scrollResponse.getScrollId()); assertThat(scannedDocs, equalTo(10)); } } // Issue #5783 public void testQueryBeforeChildType() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("features") .addMapping("posts", "_parent", "type=features") .addMapping("specials")); ensureGreen(); client().prepareIndex("test", "features", "1").setSource("field", "foo").get(); client().prepareIndex("test", "posts", "1").setParent("1").setSource("field", "bar").get(); refresh(); SearchResponse resp; resp = client().prepareSearch("test") .setSource(new SearchSourceBuilder().query(hasChildQuery("posts", QueryBuilders.matchQuery("field", "bar"), ScoreMode.None))) .get(); assertHitCount(resp, 1L); } // Issue #6256 public void testParentFieldInMultiMatchField() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("type1") .addMapping("type2", "_parent", "type=type1") ); ensureGreen(); client().prepareIndex("test", "type2", "1").setParent("1").setSource("field", "value").get(); refresh(); SearchResponse response = client().prepareSearch("test") .setQuery(multiMatchQuery("1", "_parent#type1")) .get(); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getAt(0).getId(), equalTo("1")); } public void testTypeIsAppliedInHasParentInnerQuery() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); List<IndexRequestBuilder> indexRequests = new ArrayList<>(); indexRequests.add(client().prepareIndex("test", "parent", "1").setSource("field1", "a")); indexRequests.add(client().prepareIndex("test", "child", "1").setParent("1").setSource("{}", XContentType.JSON)); indexRequests.add(client().prepareIndex("test", "child", "2").setParent("1").setSource("{}", XContentType.JSON)); indexRandom(true, indexRequests); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasParentQuery("parent", boolQuery().mustNot(termQuery("field1", "a")), false))) .get(); assertHitCount(searchResponse, 0L); searchResponse = client().prepareSearch("test") .setQuery(hasParentQuery("parent", constantScoreQuery(boolQuery().mustNot(termQuery("field1", "a"))), false)) .get(); assertHitCount(searchResponse, 0L); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("field1", "a"), false))) .get(); assertHitCount(searchResponse, 2L); searchResponse = client().prepareSearch("test") .setQuery(hasParentQuery("parent", constantScoreQuery(termQuery("field1", "a")), false)) .get(); assertHitCount(searchResponse, 2L); } private List<IndexRequestBuilder> createMinMaxDocBuilders() { List<IndexRequestBuilder> indexBuilders = new ArrayList<>(); // Parent 1 and its children indexBuilders.add(client().prepareIndex().setType("parent").setId("1").setIndex("test").setSource("id",1)); indexBuilders.add(client().prepareIndex().setType("child").setId("10").setIndex("test") .setSource("foo", "one").setParent("1")); // Parent 2 and its children indexBuilders.add(client().prepareIndex().setType("parent").setId("2").setIndex("test").setSource("id",2)); indexBuilders.add(client().prepareIndex().setType("child").setId("11").setIndex("test") .setSource("foo", "one").setParent("2")); indexBuilders.add(client().prepareIndex().setType("child").setId("12").setIndex("test") .setSource("foo", "one two").setParent("2")); // Parent 3 and its children indexBuilders.add(client().prepareIndex().setType("parent").setId("3").setIndex("test").setSource("id",3)); indexBuilders.add(client().prepareIndex().setType("child").setId("13").setIndex("test") .setSource("foo", "one").setParent("3")); indexBuilders.add(client().prepareIndex().setType("child").setId("14").setIndex("test") .setSource("foo", "one two").setParent("3")); indexBuilders.add(client().prepareIndex().setType("child").setId("15").setIndex("test") .setSource("foo", "one two three").setParent("3")); // Parent 4 and its children indexBuilders.add(client().prepareIndex().setType("parent").setId("4").setIndex("test").setSource("id",4)); indexBuilders.add(client().prepareIndex().setType("child").setId("16").setIndex("test") .setSource("foo", "one").setParent("4")); indexBuilders.add(client().prepareIndex().setType("child").setId("17").setIndex("test") .setSource("foo", "one two").setParent("4")); indexBuilders.add(client().prepareIndex().setType("child").setId("18").setIndex("test") .setSource("foo", "one two three").setParent("4")); indexBuilders.add(client().prepareIndex().setType("child").setId("19").setIndex("test") .setSource("foo", "one two three four").setParent("4")); return indexBuilders; } private SearchResponse minMaxQuery(ScoreMode scoreMode, int minChildren, Integer maxChildren) throws SearchPhaseExecutionException { HasChildQueryBuilder hasChildQuery = hasChildQuery( "child", 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)) }).boostMode(CombineFunction.REPLACE).scoreMode(FiltersFunctionScoreQuery.ScoreMode.SUM), scoreMode) .minMaxChildren(minChildren, maxChildren != null ? maxChildren : HasChildQueryBuilder.DEFAULT_MAX_CHILDREN); return client() .prepareSearch("test") .setQuery(hasChildQuery) .addSort("_score", SortOrder.DESC).addSort("id", SortOrder.ASC).get(); } public void testMinMaxChildren() throws Exception { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent", "id", "type=long") .addMapping("child", "_parent", "type=parent")); ensureGreen(); indexRandom(true, createMinMaxDocBuilders().toArray(new IndexRequestBuilder[0])); SearchResponse response; // Score mode = NONE response = minMaxQuery(ScoreMode.None, 0, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("2")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("4")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.None, 1, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("2")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("4")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.None, 2, null); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("4")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.None, 3, null); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.None, 4, null); assertThat(response.getHits().getTotalHits(), equalTo(0L)); response = minMaxQuery(ScoreMode.None, 0, 4); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("2")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("4")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.None, 0, 3); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("2")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("4")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.None, 0, 2); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("2")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.None, 2, 2); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1f)); IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> minMaxQuery(ScoreMode.None, 3, 2)); assertThat(e.getMessage(), equalTo("[has_child] 'max_children' is less than 'min_children'")); // Score mode = SUM response = minMaxQuery(ScoreMode.Total, 0, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(6f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Total, 1, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(6f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Total, 2, null); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(6f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(3f)); response = minMaxQuery(ScoreMode.Total, 3, null); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(6f)); response = minMaxQuery(ScoreMode.Total, 4, null); assertThat(response.getHits().getTotalHits(), equalTo(0L)); response = minMaxQuery(ScoreMode.Total, 0, 4); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(6f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Total, 0, 3); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(6f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Total, 0, 2); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("2")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Total, 2, 2); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); e = expectThrows(IllegalArgumentException.class, () -> minMaxQuery(ScoreMode.Total, 3, 2)); assertThat(e.getMessage(), equalTo("[has_child] 'max_children' is less than 'min_children'")); // Score mode = MAX response = minMaxQuery(ScoreMode.Max, 0, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Max, 1, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Max, 2, null); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(2f)); response = minMaxQuery(ScoreMode.Max, 3, null); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); response = minMaxQuery(ScoreMode.Max, 4, null); assertThat(response.getHits().getTotalHits(), equalTo(0L)); response = minMaxQuery(ScoreMode.Max, 0, 4); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Max, 0, 3); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(3f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Max, 0, 2); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("2")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Max, 2, 2); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); e = expectThrows(IllegalArgumentException.class, () -> minMaxQuery(ScoreMode.Max, 3, 2)); assertThat(e.getMessage(), equalTo("[has_child] 'max_children' is less than 'min_children'")); // Score mode = AVG response = minMaxQuery(ScoreMode.Avg, 0, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1.5f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Avg, 1, null); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1.5f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Avg, 2, null); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1.5f)); response = minMaxQuery(ScoreMode.Avg, 3, null); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); response = minMaxQuery(ScoreMode.Avg, 4, null); assertThat(response.getHits().getTotalHits(), equalTo(0L)); response = minMaxQuery(ScoreMode.Avg, 0, 4); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1.5f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Avg, 0, 3); assertThat(response.getHits().getTotalHits(), equalTo(3L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("4")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(2f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("3")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1.5f)); assertThat(response.getHits().getHits()[2].getId(), equalTo("2")); assertThat(response.getHits().getHits()[2].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Avg, 0, 2); assertThat(response.getHits().getTotalHits(), equalTo(2L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1.5f)); assertThat(response.getHits().getHits()[1].getId(), equalTo("2")); assertThat(response.getHits().getHits()[1].getScore(), equalTo(1f)); response = minMaxQuery(ScoreMode.Avg, 2, 2); assertThat(response.getHits().getTotalHits(), equalTo(1L)); assertThat(response.getHits().getHits()[0].getId(), equalTo("3")); assertThat(response.getHits().getHits()[0].getScore(), equalTo(1.5f)); e = expectThrows(IllegalArgumentException.class, () -> minMaxQuery(ScoreMode.Avg, 3, 2)); assertThat(e.getMessage(), equalTo("[has_child] 'max_children' is less than 'min_children'")); } public void testParentFieldToNonExistingType() { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent").addMapping("child", "_parent", "type=parent2")); client().prepareIndex("test", "parent", "1").setSource("{}", XContentType.JSON).get(); client().prepareIndex("test", "child", "1").setParent("1").setSource("{}", XContentType.JSON).get(); refresh(); try { client().prepareSearch("test") .setQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.None)) .get(); fail(); } catch (SearchPhaseExecutionException e) { } } public void testHasParentInnerQueryType() { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent-type").addMapping("child-type", "_parent", "type=parent-type")); client().prepareIndex("test", "child-type", "child-id").setParent("parent-id").setSource("{}", XContentType.JSON).get(); client().prepareIndex("test", "parent-type", "parent-id").setSource("{}", XContentType.JSON).get(); 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( hasParentQuery("parent-type", new IdsQueryBuilder().addIds("parent-id"), false)).get(); assertSearchHits(searchResponse, "child-id"); } public void testHasChildInnerQueryType() { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .addMapping("parent-type").addMapping("child-type", "_parent", "type=parent-type")); client().prepareIndex("test", "child-type", "child-id").setParent("parent-id").setSource("{}", XContentType.JSON).get(); client().prepareIndex("test", "parent-type", "parent-id").setSource("{}", XContentType.JSON).get(); 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( hasChildQuery("child-type", new IdsQueryBuilder().addIds("child-id"), ScoreMode.None)).get(); assertSearchHits(searchResponse, "parent-id"); } public void testHighlightersIgnoreParentChild() { assertAcked(prepareCreate("test") .setSettings("index.mapping.single_type", false) .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(); refresh(); String[] highlightTypes = new String[] {"plain", "fvh", "postings"}; for (String highlightType : highlightTypes) { logger.info("Testing with highlight type [{}]", highlightType); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(new BoolQueryBuilder() .must(new MatchQueryBuilder("searchText", "fox")) .must(new HasChildQueryBuilder("child-type", new MatchAllQueryBuilder(), ScoreMode.None)) ) .highlighter(new HighlightBuilder().field(new HighlightBuilder.Field("searchText").highlighterType(highlightType))) .get(); assertHitCount(searchResponse, 1); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("parent-id")); HighlightField highlightField = searchResponse.getHits().getAt(0).getHighlightFields().get("searchText"); assertThat(highlightField.getFragments()[0].string(), equalTo("quick brown <em>fox</em>")); searchResponse = client().prepareSearch("test") .setQuery(new BoolQueryBuilder() .must(new MatchQueryBuilder("searchText", "fox")) .must(new HasParentQueryBuilder("parent-type", new MatchAllQueryBuilder(), false)) ) .highlighter(new HighlightBuilder().field(new HighlightBuilder.Field("searchText").highlighterType(highlightType))) .get(); assertHitCount(searchResponse, 1); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("child-id")); highlightField = searchResponse.getHits().getAt(0).getHighlightFields().get("searchText"); assertThat(highlightField.getFragments()[0].string(), equalTo("quick brown <em>fox</em>")); } } 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"); } }