/* * 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.search.child; import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse; import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse; import org.elasticsearch.action.count.CountResponse; 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.common.lucene.search.function.CombineFunction; import org.elasticsearch.common.settings.Settings; import org.elasticsearch.common.unit.TimeValue; import org.elasticsearch.index.cache.IndexCacheModule; import org.elasticsearch.index.query.HasChildQueryBuilder; import org.elasticsearch.index.query.IdsQueryBuilder; import org.elasticsearch.index.query.QueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.search.child.ScoreType; 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.highlight.HighlightBuilder; import org.elasticsearch.search.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 org.junit.Test; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import static com.google.common.collect.Maps.newHashMap; import static org.elasticsearch.common.settings.Settings.settingsBuilder; 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.filteredQuery; import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery; import static org.elasticsearch.index.query.QueryBuilders.idsQuery; import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery; import static org.elasticsearch.index.query.QueryBuilders.matchQuery; import static org.elasticsearch.index.query.QueryBuilders.multiMatchQuery; import static org.elasticsearch.index.query.QueryBuilders.notQuery; 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.index.query.functionscore.ScoreFunctionBuilders.fieldValueFactorFunction; import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.weightFactorFunction; import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount; import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures; 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.instanceOf; import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.notNullValue; /** * */ @ClusterScope(scope = Scope.SUITE) public class ChildQuerySearchIT extends ESIntegTestCase { @Override protected Settings nodeSettings(int nodeOrdinal) { return Settings.settingsBuilder().put(super.nodeSettings(nodeOrdinal)) // aggressive filter caching so that we can assert on the filter cache size .put(IndexCacheModule.QUERY_CACHE_TYPE, IndexCacheModule.INDEX_QUERY_CACHE) .put(IndexCacheModule.QUERY_CACHE_EVERYTHING, true) .build(); } @Test public void testSelfReferentialIsForbidden() { try { prepareCreate("test").addMapping("type", "_parent", "type=type").get(); fail("self referential should be forbidden"); } catch (Exception e) { Throwable cause = e.getCause(); assertThat(cause, instanceOf(IllegalArgumentException.class)); assertThat(cause.getMessage(), equalTo("The [_parent.type] option can't point to the same type")); } } @Test public void multiLevelChild() throws Exception { assertAcked(prepareCreate("test") .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( filteredQuery( matchAllQuery(), hasChildQuery( "child", filteredQuery(termQuery("c_field", "c_value1"), hasChildQuery("grandchild", termQuery("gc_field", "gc_value1")))))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), hasParentQuery("parent", termQuery("p_field", "p_value1")))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c1")); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), hasParentQuery("child", termQuery("c_field", "c_value1")))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("gc1")); searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", termQuery("p_field", "p_value1"))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c1")); searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("child", termQuery("c_field", "c_value1"))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("gc1")); } @Test // see #6722 public void test6722() throws IOException { assertAcked(prepareCreate("test") .addMapping("foo") .addMapping("test", "_parent", "type=foo")); ensureGreen(); // index simple data client().prepareIndex("test", "foo", "1").setSource("foo", 1).get(); client().prepareIndex("test", "test", "2").setSource("foo", 1).setParent("1").get(); refresh(); String query = copyToStringFromClasspath("/org/elasticsearch/search/child/bool-query-with-empty-clauses.json"); SearchResponse searchResponse = client().prepareSearch("test").setSource(query).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("2")); } @Test // see #2744 public void test2744() throws IOException { assertAcked(prepareCreate("test") .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))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("1")); } @Test public void simpleChildQuery() throws Exception { assertAcked(prepareCreate("test") .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").ids("c1")).addFields("_parent").execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c1")); assertThat(searchResponse.getHits().getAt(0).field("_parent").value().toString(), equalTo("p1")); // TEST matching on parent searchResponse = client().prepareSearch("test").setQuery(termQuery("_parent", "p1")).addFields("_parent").get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); assertThat(searchResponse.getHits().getAt(0).id(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(0).field("_parent").value().toString(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(1).id(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(1).field("_parent").value().toString(), equalTo("p1")); searchResponse = client().prepareSearch("test").setQuery(queryStringQuery("_parent:p1")).addFields("_parent").get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); assertThat(searchResponse.getHits().getAt(0).id(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(0).field("_parent").value().toString(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(1).id(), anyOf(equalTo("c1"), equalTo("c2"))); assertThat(searchResponse.getHits().getAt(1).field("_parent").value().toString(), equalTo("p1")); // HAS CHILD searchResponse = client().prepareSearch("test").setQuery(randomHasChild("child", "c_field", "yellow")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); searchResponse = client().prepareSearch("test").setQuery(randomHasChild("child", "c_field", "blue")).execute() .actionGet(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p2")); searchResponse = client().prepareSearch("test").setQuery(randomHasChild("child", "c_field", "red")).get(); assertHitCount(searchResponse, 2l); assertThat(searchResponse.getHits().getAt(0).id(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).id(), 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).id(), equalTo("c3")); assertThat(searchResponse.getHits().getAt(1).id(), equalTo("c4")); searchResponse = client().prepareSearch("test") .setQuery(randomHasParent("parent", "p_field", "p_value1")).get(); assertHitCount(searchResponse, 2l); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c1")); assertThat(searchResponse.getHits().getAt(1).id(), equalTo("c2")); } @Test // See: https://github.com/elasticsearch/elasticsearch/issues/3290 public void testCachingBug_withFqueryFilter() throws Exception { assertAcked(prepareCreate("test") .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()).scoreType("max"))) .get(); assertNoFailures(searchResponse); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasParentQuery("parent", matchAllQuery()).scoreType("score"))) .get(); assertNoFailures(searchResponse); } } @Test public void testHasParentFilter() throws Exception { assertAcked(prepareCreate("test") .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); Map<String, Set<String>> parentToChildren = newHashMap(); // Childless parent client().prepareIndex("test", "parent", "p0").setSource("p_field", "p0").get(); parentToChildren.put("p0", new HashSet<String>()); 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<String>()); } 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())))) .setSize(numChildDocsPerParent).get(); assertNoFailures(searchResponse); Set<String> childIds = parentToChildrenEntry.getValue(); assertThat(searchResponse.getHits().totalHits(), equalTo((long) childIds.size())); for (int i = 0; i < searchResponse.getHits().totalHits(); i++) { assertThat(childIds.remove(searchResponse.getHits().getAt(i).id()), is(true)); assertThat(searchResponse.getHits().getAt(i).score(), is(1.0f)); } assertThat(childIds.size(), is(0)); } } @Test public void simpleChildQueryWithFlush() throws Exception { assertAcked(prepareCreate("test") .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"))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "blue"))).execute() .actionGet(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p2")); searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "red"))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); assertThat(searchResponse.getHits().getAt(0).id(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).id(), anyOf(equalTo("p2"), equalTo("p1"))); // HAS CHILD FILTER searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "yellow")))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "blue")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p2")); searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "red")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); assertThat(searchResponse.getHits().getAt(0).id(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).id(), anyOf(equalTo("p2"), equalTo("p1"))); } @Test public void testScopedFacet() throws Exception { assertAcked(prepareCreate("test") .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(hasChildQuery("child", boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow")))) .addAggregation(AggregationBuilders.global("global").subAggregation( AggregationBuilders.filter("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().totalHits(), equalTo(2l)); assertThat(searchResponse.getHits().getAt(0).id(), anyOf(equalTo("p2"), equalTo("p1"))); assertThat(searchResponse.getHits().getAt(1).id(), 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)); } @Test public void testDeletedParent() throws Exception { assertAcked(prepareCreate("test") .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")))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).sourceAsString(), 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")))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).sourceAsString(), containsString("\"p_value1_updated\"")); } @Test public void testDfsSearchType() throws Exception { assertAcked(prepareCreate("test") .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:*"))))).get(); assertNoFailures(searchResponse); searchResponse = client().prepareSearch("test").setSearchType(SearchType.DFS_QUERY_THEN_FETCH) .setQuery(boolQuery().mustNot(hasParentQuery("parent", boolQuery().should(queryStringQuery("p_field:*"))))).execute() .actionGet(); assertNoFailures(searchResponse); } @Test public void testHasChildAndHasParentFailWhenSomeSegmentsDontContainAnyParentOrChildDocs() throws Exception { assertAcked(prepareCreate("test") .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(filteredQuery(matchAllQuery(), hasChildQuery("child", matchAllQuery()))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), hasParentQuery("parent", matchAllQuery()))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); } @Test public void testCountApiUsage() throws Exception { assertAcked(prepareCreate("test") .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(); CountResponse countResponse = client().prepareCount("test").setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max")) .get(); assertHitCount(countResponse, 1l); countResponse = client().prepareCount("test").setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score")) .get(); assertHitCount(countResponse, 1l); countResponse = client().prepareCount("test").setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "1")))) .get(); assertHitCount(countResponse, 1l); countResponse = client().prepareCount("test").setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1")))) .get(); assertHitCount(countResponse, 1l); } @Test public void testExplainUsage() throws Exception { assertAcked(prepareCreate("test") .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")).scoreType("max")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).explanation().getDescription(), equalTo("A match, join value p1")); searchResponse = client().prepareSearch("test") .setExplain(true) .setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).explanation().getDescription(), equalTo("A match, join value p1")); ExplainResponse explainResponse = client().prepareExplain("test", "parent", parentId) .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max")) .get(); assertThat(explainResponse.isExists(), equalTo(true)); assertThat(explainResponse.getExplanation().getDetails()[0].getDescription(), equalTo("A match, 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; } @Test public void testScoreForParentChildQueries_withFunctionScore() throws Exception { assertAcked(prepareCreate("test") .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( QueryBuilders.hasChildQuery( "child", QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), fieldValueFactorFunction("c_field1")) .boostMode(CombineFunction.REPLACE)).scoreMode("sum")).get(); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("1")); assertThat(response.getHits().hits()[0].score(), equalTo(6f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(4f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(3f)); response = client() .prepareSearch("test") .setQuery( QueryBuilders.hasChildQuery( "child", QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), fieldValueFactorFunction("c_field1")) .boostMode(CombineFunction.REPLACE)).scoreMode("max")).get(); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(4f)); assertThat(response.getHits().hits()[1].id(), equalTo("2")); assertThat(response.getHits().hits()[1].score(), equalTo(3f)); assertThat(response.getHits().hits()[2].id(), equalTo("1")); assertThat(response.getHits().hits()[2].score(), equalTo(2f)); response = client() .prepareSearch("test") .setQuery( QueryBuilders.hasChildQuery( "child", QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0), fieldValueFactorFunction("c_field1")) .boostMode(CombineFunction.REPLACE)).scoreMode("avg")).get(); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(4f)); assertThat(response.getHits().hits()[1].id(), equalTo("2")); assertThat(response.getHits().hits()[1].score(), equalTo(3f)); assertThat(response.getHits().hits()[2].id(), equalTo("1")); assertThat(response.getHits().hits()[2].score(), equalTo(1.5f)); response = client() .prepareSearch("test") .setQuery( QueryBuilders.hasParentQuery( "parent", QueryBuilders.functionScoreQuery(matchQuery("p_field1", "p_value3"), fieldValueFactorFunction("p_field2")) .boostMode(CombineFunction.REPLACE)).scoreType("score")) .addSort(SortBuilders.fieldSort("c_field3")).addSort(SortBuilders.scoreSort()).get(); assertThat(response.getHits().totalHits(), equalTo(7l)); assertThat(response.getHits().hits()[0].id(), equalTo("13")); assertThat(response.getHits().hits()[0].score(), equalTo(5f)); assertThat(response.getHits().hits()[1].id(), equalTo("14")); assertThat(response.getHits().hits()[1].score(), equalTo(5f)); assertThat(response.getHits().hits()[2].id(), equalTo("15")); assertThat(response.getHits().hits()[2].score(), equalTo(5f)); assertThat(response.getHits().hits()[3].id(), equalTo("16")); assertThat(response.getHits().hits()[3].score(), equalTo(5f)); assertThat(response.getHits().hits()[4].id(), equalTo("17")); assertThat(response.getHits().hits()[4].score(), equalTo(5f)); assertThat(response.getHits().hits()[5].id(), equalTo("18")); assertThat(response.getHits().hits()[5].score(), equalTo(5f)); assertThat(response.getHits().hits()[6].id(), equalTo("1")); assertThat(response.getHits().hits()[6].score(), equalTo(5f)); } @Test // https://github.com/elasticsearch/elasticsearch/issues/2536 public void testParentChildQueriesCanHandleNoRelevantTypesInIndex() throws Exception { assertAcked(prepareCreate("test") .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); SearchResponse response = client().prepareSearch("test") .setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"))).get(); assertNoFailures(response); assertThat(response.getHits().totalHits(), equalTo(0l)); client().prepareIndex("test", "child1").setSource(jsonBuilder().startObject().field("text", "value").endObject()).setRefresh(true) .get(); response = client().prepareSearch("test").setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"))).get(); assertNoFailures(response); assertThat(response.getHits().totalHits(), equalTo(0l)); response = client().prepareSearch("test").setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value")).scoreType("max")) .get(); assertNoFailures(response); assertThat(response.getHits().totalHits(), equalTo(0l)); response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("parent", matchQuery("text", "value"))).get(); assertNoFailures(response); assertThat(response.getHits().totalHits(), equalTo(0l)); response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("parent", matchQuery("text", "value")).scoreType("score")) .get(); assertNoFailures(response); assertThat(response.getHits().totalHits(), equalTo(0l)); } @Test public void testHasChildAndHasParentFilter_withFilter() throws Exception { assertAcked(prepareCreate("test") .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(filteredQuery(matchAllQuery(), hasChildQuery("child", termQuery("c_field", 1)))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits()[0].id(), equalTo("1")); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), hasParentQuery("parent", termQuery("p_field", 1)))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().hits()[0].id(), equalTo("2")); } @Test public void testHasChildAndHasParentWrappedInAQueryFilter() throws Exception { assertAcked(prepareCreate("test") .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(filteredQuery(matchAllQuery(), hasChildQuery("child", matchQuery("c_field", 1)))).get(); assertSearchHit(searchResponse, 1, hasId("1")); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), hasParentQuery("parent", matchQuery("p_field", 1)))).get(); assertSearchHit(searchResponse, 1, hasId("2")); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), boolQuery().must(hasChildQuery("child", matchQuery("c_field", 1))))).get(); assertSearchHit(searchResponse, 1, hasId("1")); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), boolQuery().must(hasParentQuery("parent", matchQuery("p_field", 1))))).get(); assertSearchHit(searchResponse, 1, hasId("2")); } @Test public void testSimpleQueryRewrite() throws Exception { assertAcked(prepareCreate("test") .addMapping("parent", "p_field", "type=string") .addMapping("child", "_parent", "type=parent", "c_field", "type=string")); 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")).scoreType("max")).addSort("p_field", SortOrder.ASC) .setSize(5).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(10L)); assertThat(searchResponse.getHits().hits()[0].id(), equalTo("p000")); assertThat(searchResponse.getHits().hits()[1].id(), equalTo("p001")); assertThat(searchResponse.getHits().hits()[2].id(), equalTo("p002")); assertThat(searchResponse.getHits().hits()[3].id(), equalTo("p003")); assertThat(searchResponse.getHits().hits()[4].id(), equalTo("p004")); searchResponse = client().prepareSearch("test").setSearchType(searchType) .setQuery(hasParentQuery("parent", prefixQuery("p_field", "p")).scoreType("score")).addSort("c_field", SortOrder.ASC) .setSize(5).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(500L)); assertThat(searchResponse.getHits().hits()[0].id(), equalTo("c000")); assertThat(searchResponse.getHits().hits()[1].id(), equalTo("c001")); assertThat(searchResponse.getHits().hits()[2].id(), equalTo("c002")); assertThat(searchResponse.getHits().hits()[3].id(), equalTo("c003")); assertThat(searchResponse.getHits().hits()[4].id(), equalTo("c004")); } } @Test // See also issue: // https://github.com/elasticsearch/elasticsearch/issues/3144 public void testReIndexingParentAndChildDocuments() throws Exception { assertAcked(prepareCreate("test") .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")).scoreType("sum")).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).sourceAsString(), containsString("\"p_value1\"")); searchResponse = client() .prepareSearch("test") .setQuery( boolQuery().must(matchQuery("c_field", "x")).must( hasParentQuery("parent", termQuery("p_field", "p_value2")).scoreType("score"))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("c3")); assertThat(searchResponse.getHits().getAt(1).id(), 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")).scoreType("sum")) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p1")); assertThat(searchResponse.getHits().getAt(0).sourceAsString(), containsString("\"p_value1\"")); searchResponse = client() .prepareSearch("test") .setQuery( boolQuery().must(matchQuery("c_field", "x")).must( hasParentQuery("parent", termQuery("p_field", "p_value2")).scoreType("score"))).get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); assertThat(searchResponse.getHits().getAt(0).id(), Matchers.anyOf(equalTo("c3"), equalTo("c4"))); assertThat(searchResponse.getHits().getAt(1).id(), Matchers.anyOf(equalTo("c3"), equalTo("c4"))); } @Test // See also issue: // https://github.com/elasticsearch/elasticsearch/issues/3203 public void testHasChildQueryWithMinimumScore() throws Exception { assertAcked(prepareCreate("test") .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()).scoreType("sum")) .setMinScore(3) // Score needs to be 3 or above! .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("p2")); assertThat(searchResponse.getHits().getAt(0).score(), equalTo(3.0f)); } @Test public void testParentFieldFilter() throws Exception { assertAcked(prepareCreate("test") .setSettings(settingsBuilder().put(indexSettings()) .put("index.refresh_interval", -1)) .addMapping("parent") .addMapping("child", "_parent", "type=parent") .addMapping("child2", "_parent", "type=parent")); ensureGreen(); // test term filter SearchResponse response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termQuery("_parent", "p1"))) .get(); assertHitCount(response, 0l); client().prepareIndex("test", "some_type", "1").setSource("field", "value").get(); client().prepareIndex("test", "parent", "p1").setSource("p_field", "value").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "value").setParent("p1").get(); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termQuery("_parent", "p1"))).execute() .actionGet(); assertHitCount(response, 0l); refresh(); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termQuery("_parent", "p1"))).execute() .actionGet(); assertHitCount(response, 1l); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termQuery("_parent", "parent#p1"))).execute() .actionGet(); assertHitCount(response, 1l); client().prepareIndex("test", "parent2", "p1").setSource("p_field", "value").setRefresh(true).get(); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termQuery("_parent", "p1"))).execute() .actionGet(); assertHitCount(response, 1l); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termQuery("_parent", "parent#p1"))).execute() .actionGet(); assertHitCount(response, 1l); // test terms filter client().prepareIndex("test", "child2", "c1").setSource("c_field", "value").setParent("p1").get(); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termsQuery("_parent", "p1"))).execute() .actionGet(); assertHitCount(response, 1l); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termsQuery("_parent", "parent#p1"))).execute() .actionGet(); assertHitCount(response, 1l); refresh(); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termsQuery("_parent", "p1"))).execute() .actionGet(); assertHitCount(response, 2l); refresh(); response = client().prepareSearch("test").setQuery(filteredQuery(matchAllQuery(), termsQuery("_parent", "p1", "p1"))).execute() .actionGet(); assertHitCount(response, 2l); response = client().prepareSearch("test") .setQuery(filteredQuery(matchAllQuery(), termsQuery("_parent", "parent#p1", "parent2#p1"))).get(); assertHitCount(response, 2l); } @Test public void testHasChildNotBeingCached() throws IOException { assertAcked(prepareCreate("test") .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")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), 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")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); } private QueryBuilder randomHasChild(String type, String field, String value) { if (randomBoolean()) { if (randomBoolean()) { return constantScoreQuery(hasChildQuery(type, termQuery(field, value))); } else { return filteredQuery(matchAllQuery(), hasChildQuery(type, termQuery(field, value))); } } else { return hasChildQuery(type, termQuery(field, value)); } } private QueryBuilder randomHasParent(String type, String field, String value) { if (randomBoolean()) { if (randomBoolean()) { return constantScoreQuery(hasParentQuery(type, termQuery(field, value))); } else { return filteredQuery(matchAllQuery(), hasParentQuery(type, termQuery(field, value))); } } else { return hasParentQuery(type, termQuery(field, value)); } } @Test // Relates to bug: https://github.com/elasticsearch/elasticsearch/issues/3818 public void testHasChildQueryOnlyReturnsSingleChildType() { assertAcked(prepareCreate("grandissue") .addMapping("grandparent", "name", "type=string") .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*").analyzeWildcard(true) ) ) ) ) ) ).get(); assertHitCount(searchResponse, 1l); searchResponse = client().prepareSearch("grandissue").setQuery( boolQuery().must( hasChildQuery( "parent", boolQuery().must( hasChildQuery( "child_type_two", boolQuery().must( queryStringQuery("name:William*").analyzeWildcard(true) ) ) ) ) ) ).get(); assertHitCount(searchResponse, 0l); } @Test public void indexChildDocWithNoParentMapping() throws IOException { assertAcked(prepareCreate("test") .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(); } @Test 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]")); } } @Test public void testHasChildQueryWithNestedInnerObjects() throws Exception { assertAcked(prepareCreate("test") .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(); String scoreMode = ScoreType.values()[getRandom().nextInt(ScoreType.values().length)].name().toLowerCase(Locale.ROOT); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(QueryBuilders.hasChildQuery("child", termQuery("c_field", "blue")).scoreType(scoreMode), notQuery(termQuery("p_field", "3")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); searchResponse = client().prepareSearch("test") .setQuery(filteredQuery(QueryBuilders.hasChildQuery("child", termQuery("c_field", "red")).scoreType(scoreMode), notQuery(termQuery("p_field", "3")))) .get(); assertNoFailures(searchResponse); assertThat(searchResponse.getHits().totalHits(), equalTo(2l)); } @Test public void testNamedFilters() throws Exception { assertAcked(prepareCreate("test") .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")).scoreType("max").queryName("test")) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("test")); searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score").queryName("test")) .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")).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")).queryName("test"))) .get(); assertHitCount(searchResponse, 1l); assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1)); assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("test")); } @Test public void testParentChildQueriesNoParentType() throws Exception { assertAcked(prepareCreate("test") .setSettings(settingsBuilder() .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"))) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setQuery(hasChildQuery("child", termQuery("c_field", "1")).scoreType("max")) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setPostFilter(hasChildQuery("child", termQuery("c_field", "1"))) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setQuery(hasParentQuery("parent", termQuery("p_field", "1")).scoreType("score")) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } try { client().prepareSearch("test") .setPostFilter(hasParentQuery("parent", termQuery("p_field", "1"))) .get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); } } public void testParentChildCaching() throws Exception { assertAcked(prepareCreate("test") .setSettings( settingsBuilder() .put(indexSettings()) .put("index.refresh_interval", -1) ) .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(filteredQuery(matchAllQuery(), boolQuery() .must(QueryBuilders.hasChildQuery("child", matchQuery("c_field", "red"))) .must(matchAllQuery()))) .get(); assertThat(searchResponse.getHits().totalHits(), 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(filteredQuery(matchAllQuery(), boolQuery() .must(QueryBuilders.hasChildQuery("child", matchQuery("c_field", "red"))) .must(matchAllQuery()))) .get(); assertThat(searchResponse.getHits().totalHits(), equalTo(1l)); } @Test public void testParentChildQueriesViaScrollApi() throws Exception { assertAcked(prepareCreate("test") .addMapping("parent") .addMapping("child", "_parent", "type=parent")); ensureGreen(); for (int i = 0; i < 10; i++) { client().prepareIndex("test", "parent", "p" + i).setSource("{}").get(); client().prepareIndex("test", "child", "c" + i).setSource("{}").setParent("p" + i).get(); } refresh(); QueryBuilder[] queries = new QueryBuilder[]{ hasChildQuery("child", matchAllQuery()), filteredQuery(matchAllQuery(), hasChildQuery("child", matchAllQuery())), hasParentQuery("parent", matchAllQuery()), filteredQuery(matchAllQuery(), hasParentQuery("parent", matchAllQuery())) }; for (QueryBuilder query : queries) { SearchResponse scrollResponse = client().prepareSearch("test") .setScroll(TimeValue.timeValueSeconds(30)) .setSize(1) .addField("_id") .setQuery(query) .setSearchType("scan") .execute() .actionGet(); assertNoFailures(scrollResponse); assertThat(scrollResponse.getHits().totalHits(), equalTo(10l)); int scannedDocs = 0; do { scrollResponse = client() .prepareSearchScroll(scrollResponse.getScrollId()) .setScroll(TimeValue.timeValueSeconds(30)).get(); assertThat(scrollResponse.getHits().totalHits(), equalTo(10l)); scannedDocs += scrollResponse.getHits().getHits().length; } while (scrollResponse.getHits().getHits().length > 0); assertThat(scannedDocs, equalTo(10)); } } // https://github.com/elasticsearch/elasticsearch/issues/5783 @Test public void testQueryBeforeChildType() throws Exception { assertAcked(prepareCreate("test") .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("{\"query\": {\"has_child\": {\"type\": \"posts\", \"query\": {\"match\": {\"field\": \"bar\"}}}}}").get(); assertHitCount(resp, 1L); // Now reverse the order for the type after the query resp = client().prepareSearch("test") .setSource("{\"query\": {\"has_child\": {\"query\": {\"match\": {\"field\": \"bar\"}}, \"type\": \"posts\"}}}").get(); assertHitCount(resp, 1L); } @Test // https://github.com/elasticsearch/elasticsearch/issues/6256 public void testParentFieldInMultiMatchField() throws Exception { assertAcked(prepareCreate("test") .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")) .get(); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().getAt(0).id(), equalTo("1")); } @Test public void testTypeIsAppliedInHasParentInnerQuery() throws Exception { assertAcked(prepareCreate("test") .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("{}")); indexRequests.add(client().prepareIndex("test", "child", "2").setParent("1").setSource("{}")); indexRandom(true, indexRequests); SearchResponse searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasParentQuery("parent", notQuery(termQuery("field1", "a"))))) .get(); assertHitCount(searchResponse, 0l); searchResponse = client().prepareSearch("test") .setQuery(hasParentQuery("parent", constantScoreQuery(notQuery(termQuery("field1", "a"))))) .get(); assertHitCount(searchResponse, 0l); searchResponse = client().prepareSearch("test") .setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("field1", "a")))) .get(); assertHitCount(searchResponse, 2l); searchResponse = client().prepareSearch("test") .setQuery(hasParentQuery("parent", constantScoreQuery(termQuery("field1", "a")))) .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(String scoreType, int minChildren, int maxChildren, int cutoff) throws SearchPhaseExecutionException { return client() .prepareSearch("test") .setQuery( QueryBuilders .hasChildQuery( "child", QueryBuilders.functionScoreQuery(constantScoreQuery(QueryBuilders.termQuery("foo", "two"))).boostMode("replace").scoreMode("sum") .add(QueryBuilders.matchAllQuery(), weightFactorFunction(1)) .add(QueryBuilders.termQuery("foo", "three"), weightFactorFunction(1)) .add(QueryBuilders.termQuery("foo", "four"), weightFactorFunction(1))).scoreType(scoreType) .minChildren(minChildren).maxChildren(maxChildren).setShortCircuitCutoff(cutoff)) .addSort("_score", SortOrder.DESC).addSort("id", SortOrder.ASC).get(); } private SearchResponse minMaxFilter(int minChildren, int maxChildren, int cutoff) throws SearchPhaseExecutionException { return client() .prepareSearch("test") .setQuery( QueryBuilders.constantScoreQuery(QueryBuilders.hasChildQuery("child", termQuery("foo", "two")) .minChildren(minChildren).maxChildren(maxChildren).setShortCircuitCutoff(cutoff))) .addSort("id", SortOrder.ASC).setTrackScores(true).get(); } @Test public void testMinMaxChildren() throws Exception { assertAcked(prepareCreate("test") .addMapping("parent", "id", "type=long") .addMapping("child", "_parent", "type=parent")); ensureGreen(); indexRandom(true, createMinMaxDocBuilders().toArray(new IndexRequestBuilder[0])); SearchResponse response; int cutoff = getRandom().nextInt(4); // Score mode = NONE response = minMaxQuery("none", 0, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("none", 1, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("none", 2, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("4")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); response = minMaxQuery("none", 3, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); response = minMaxQuery("none", 4, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(0l)); response = minMaxQuery("none", 0, 4, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("none", 0, 3, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("none", 0, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); response = minMaxQuery("none", 2, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); try { response = minMaxQuery("none", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // Score mode = SUM response = minMaxQuery("sum", 0, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(6f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(3f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("sum", 1, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(6f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(3f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("sum", 2, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(6f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(3f)); response = minMaxQuery("sum", 3, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(6f)); response = minMaxQuery("sum", 4, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(0l)); response = minMaxQuery("sum", 0, 4, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(6f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(3f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("sum", 0, 3, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(6f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(3f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("sum", 0, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); assertThat(response.getHits().hits()[1].id(), equalTo("2")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); response = minMaxQuery("sum", 2, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); try { response = minMaxQuery("sum", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // Score mode = MAX response = minMaxQuery("max", 0, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(2f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("max", 1, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(2f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("max", 2, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(2f)); response = minMaxQuery("max", 3, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); response = minMaxQuery("max", 4, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(0l)); response = minMaxQuery("max", 0, 4, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(2f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("max", 0, 3, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(3f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(2f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("max", 0, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); assertThat(response.getHits().hits()[1].id(), equalTo("2")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); response = minMaxQuery("max", 2, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); try { response = minMaxQuery("max", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // Score mode = AVG response = minMaxQuery("avg", 0, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1.5f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("avg", 1, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1.5f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("avg", 2, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1.5f)); response = minMaxQuery("avg", 3, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); response = minMaxQuery("avg", 4, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(0l)); response = minMaxQuery("avg", 0, 4, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1.5f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("avg", 0, 3, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(2f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1.5f)); assertThat(response.getHits().hits()[2].id(), equalTo("2")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxQuery("avg", 0, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(1.5f)); assertThat(response.getHits().hits()[1].id(), equalTo("2")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); response = minMaxQuery("avg", 2, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(1.5f)); try { response = minMaxQuery("avg", 3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } // HasChildFilter response = minMaxFilter(0, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxFilter(1, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxFilter(2, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("4")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); response = minMaxFilter(3, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("4")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); response = minMaxFilter(4, 0, cutoff); assertThat(response.getHits().totalHits(), equalTo(0l)); response = minMaxFilter(0, 4, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxFilter(0, 3, cutoff); assertThat(response.getHits().totalHits(), equalTo(3l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); assertThat(response.getHits().hits()[2].id(), equalTo("4")); assertThat(response.getHits().hits()[2].score(), equalTo(1f)); response = minMaxFilter(0, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(2l)); assertThat(response.getHits().hits()[0].id(), equalTo("2")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); assertThat(response.getHits().hits()[1].id(), equalTo("3")); assertThat(response.getHits().hits()[1].score(), equalTo(1f)); response = minMaxFilter(2, 2, cutoff); assertThat(response.getHits().totalHits(), equalTo(1l)); assertThat(response.getHits().hits()[0].id(), equalTo("3")); assertThat(response.getHits().hits()[0].score(), equalTo(1f)); try { response = minMaxFilter(3, 2, cutoff); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.toString(), containsString("[has_child] 'max_children' is less than 'min_children'")); } } @Test public void testParentFieldToNonExistingType() { assertAcked(prepareCreate("test").addMapping("parent").addMapping("child", "_parent", "type=parent2")); client().prepareIndex("test", "parent", "1").setSource("{}").get(); client().prepareIndex("test", "child", "1").setParent("1").setSource("{}").get(); refresh(); try { client().prepareSearch("test") .setQuery(QueryBuilders.hasChildQuery("child", matchAllQuery())) .get(); fail(); } catch (SearchPhaseExecutionException e) { } } public void testHasParentInnerQueryType() { assertAcked(prepareCreate("test").addMapping("parent-type").addMapping("child-type", "_parent", "type=parent-type")); client().prepareIndex("test", "child-type", "child-id").setParent("parent-id").setSource("{}").get(); client().prepareIndex("test", "parent-type", "parent-id").setSource("{}").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( QueryBuilders.hasParentQuery("parent-type", new IdsQueryBuilder().addIds("parent-id"))).get(); assertSearchHits(searchResponse, "child-id"); } public void testHasChildInnerQueryType() { assertAcked(prepareCreate("test").addMapping("parent-type").addMapping("child-type", "_parent", "type=parent-type")); client().prepareIndex("test", "child-type", "child-id").setParent("parent-id").setSource("{}").get(); client().prepareIndex("test", "parent-type", "parent-id").setSource("{}").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( QueryBuilders.hasChildQuery("child-type", new IdsQueryBuilder().addIds("child-id"))).get(); assertSearchHits(searchResponse, "parent-id"); } // Tests #16550 public void testHasChildWithNonDefaultGlobalSimilarity() { assertAcked(prepareCreate("test").setSettings(settingsBuilder().put(indexSettings()) .put("index.similarity.default.type", "BM25")) .addMapping("parent") .addMapping("child", "_parent", "type=parent", "c_field", "type=string")); ensureGreen(); verifyNonDefaultSimilarity(); } // Tests #16550 public void testHasChildWithNonDefaultFieldSimilarity() { assertAcked(prepareCreate("test") .addMapping("parent") .addMapping("child", "_parent", "type=parent", "c_field", "type=string,similarity=BM25")); ensureGreen(); verifyNonDefaultSimilarity(); } // Tests #16550 private void verifyNonDefaultSimilarity() { client().prepareIndex("test", "parent", "p1").setSource("p_field", "p_value1").get(); client().prepareIndex("test", "child", "c1").setSource("c_field", "c_value").setParent("p1").get(); client().prepareIndex("test", "child", "c2").setSource("c_field", "c_value").setParent("p1").get(); refresh(); // baseline: sum of scores of matching child docs outside of has_child query SearchResponse searchResponse = client().prepareSearch("test") .setTypes("child") .setQuery(matchQuery("c_field", "c_value")) .get(); assertSearchHits(searchResponse, "c1", "c2"); float childSum = 0f; for (SearchHit hit : searchResponse.getHits()) { childSum += hit.getScore(); } // compare baseline to has_child with 'total' score_mode searchResponse = client().prepareSearch("test") .setQuery(hasChildQuery("child", matchQuery("c_field", "c_value")).scoreMode("total")) .get(); assertSearchHits(searchResponse, "p1"); assertThat(searchResponse.getHits().hits()[0].score(), equalTo(childSum)); } static HasChildQueryBuilder hasChildQuery(String type, QueryBuilder queryBuilder) { HasChildQueryBuilder hasChildQueryBuilder = QueryBuilders.hasChildQuery(type, queryBuilder); hasChildQueryBuilder.setShortCircuitCutoff(randomInt(10)); return hasChildQueryBuilder; } public void testParentWithoutChildTypes() { assertAcked(prepareCreate("test").addMapping("parent").addMapping("child", "_parent", "type=parent")); ensureGreen(); try { client().prepareSearch("test").setQuery(hasParentQuery("child", matchAllQuery())).get(); fail(); } catch (SearchPhaseExecutionException e) { assertThat(e.status(), equalTo(RestStatus.BAD_REQUEST)); assertThat(e.toString(), containsString("[has_parent] no child types found for type [child]")); } } public void testHighlightersIgnoreParentChild() { assertAcked(prepareCreate("test") .addMapping("parent-type", "searchText", "type=string,term_vector=with_positions_offsets,index_options=offsets") .addMapping("child-type", "_parent", "type=parent-type", "searchText", "type=string,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(QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("searchText", "fox")) .must(QueryBuilders.hasChildQuery("child-type", QueryBuilders.matchAllQuery())) ) .addHighlightedField(new HighlightBuilder.Field("searchText").highlighterType(highlightType)) .get(); assertHitCount(searchResponse, 1); assertThat(searchResponse.getHits().getAt(0).id(), 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(QueryBuilders.boolQuery() .must(QueryBuilders.matchQuery("searchText", "fox")) .must(QueryBuilders.hasParentQuery("parent-type", QueryBuilders.matchAllQuery())) ) .addHighlightedField(new HighlightBuilder.Field("searchText").highlighterType(highlightType)) .get(); assertHitCount(searchResponse, 1); assertThat(searchResponse.getHits().getAt(0).id(), equalTo("child-id")); highlightField = searchResponse.getHits().getAt(0).getHighlightFields().get("searchText"); assertThat(highlightField.getFragments()[0].string(), equalTo("quick brown <em>fox</em>")); } } }