Add parent-join module (#24638)

* Add parent-join module

This change adds a new module named `parent-join`.
The goal of this module is to provide a replacement for the `_parent` field but as a first step this change only moves the `has_child`, `has_parent` queries and the `children` aggregation to this module.
These queries and aggregations are no longer in core but they are deployed by default as a module.

Relates #20257
This commit is contained in:
Jim Ferenczi 2017-05-12 15:58:06 +02:00 committed by GitHub
parent be2a6ce80b
commit 279a18a527
66 changed files with 1469 additions and 1106 deletions

View File

@ -138,6 +138,7 @@ subprojects {
"org.elasticsearch.plugin:transport-netty4-client:${version}": ':modules:transport-netty4',
"org.elasticsearch.plugin:reindex-client:${version}": ':modules:reindex',
"org.elasticsearch.plugin:lang-mustache-client:${version}": ':modules:lang-mustache',
"org.elasticsearch.plugin:parent-join-client:${version}": ':modules:parent-join',
"org.elasticsearch.plugin:percolator-client:${version}": ':modules:percolator',
]
project.afterEvaluate {

View File

@ -620,7 +620,6 @@
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]BoolQueryBuilderTests.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]BoostingQueryBuilderTests.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]GeoDistanceQueryBuilderTests.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]HasChildQueryBuilderTests.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]MoreLikeThisQueryBuilderTests.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]MultiMatchQueryBuilderTests.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]index[/\\]query[/\\]SpanMultiTermQueryBuilderTests.java" checks="LineLength" />
@ -689,7 +688,6 @@
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]MultiValueModeTests.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]SearchWithRejectionsIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]aggregations[/\\]MissingValueIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]aggregations[/\\]bucket[/\\]ChildrenIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]aggregations[/\\]bucket[/\\]DateHistogramIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]aggregations[/\\]bucket[/\\]DateHistogramOffsetIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]aggregations[/\\]bucket[/\\]GeoDistanceIT.java" checks="LineLength" />
@ -716,7 +714,6 @@
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]basic[/\\]SearchWithRandomExceptionsIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]basic[/\\]SearchWithRandomIOExceptionsIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]basic[/\\]TransportTwoNodesSearchIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]child[/\\]ChildQuerySearchIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]child[/\\]ParentFieldLoadingIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]geo[/\\]GeoBoundingBoxIT.java" checks="LineLength" />
<suppress files="core[/\\]src[/\\]test[/\\]java[/\\]org[/\\]elasticsearch[/\\]search[/\\]geo[/\\]GeoFilterIT.java" checks="LineLength" />

View File

@ -51,8 +51,6 @@ import static org.elasticsearch.index.query.QueryBuilders.geoBoundingBoxQuery;
import static org.elasticsearch.index.query.QueryBuilders.geoDistanceQuery;
import static org.elasticsearch.index.query.QueryBuilders.geoPolygonQuery;
import static org.elasticsearch.index.query.QueryBuilders.geoShapeQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery;
import static org.elasticsearch.index.query.QueryBuilders.idsQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
@ -216,24 +214,6 @@ public class QueryDSLDocumentationTests extends ESTestCase {
}
}
public void testHasChild() {
// tag::has_child
hasChildQuery(
"blog_tag", // <1>
termQuery("tag","something"), // <2>
ScoreMode.None); // <3>
// end::has_child
}
public void testHasParent() {
// tag::has_parent
hasParentQuery(
"blog", // <1>
termQuery("tag","something"), // <2>
false); // <3>
// end::has_parent
}
public void testIds() {
// tag::ids
idsQuery("my_type", "type2")

View File

@ -31,6 +31,7 @@ dependencies {
compile "org.elasticsearch.plugin:reindex-client:${version}"
compile "org.elasticsearch.plugin:lang-mustache-client:${version}"
compile "org.elasticsearch.plugin:percolator-client:${version}"
compile "org.elasticsearch.plugin:parent-join-client:${version}"
testCompile "com.carrotsearch.randomizedtesting:randomizedtesting-runner:${versions.randomizedrunner}"
testCompile "junit:junit:${versions.junit}"
testCompile "org.hamcrest:hamcrest-all:${versions.hamcrest}"

View File

@ -195,7 +195,8 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
}
}
InnerHitBuilder(InnerHitBuilder other, QueryBuilder query, String parentChildType, boolean ignoreUnmapped) {
// NORELEASE Do not use this ctr, it is public for hasChild and hasParent query but this is temporary
public InnerHitBuilder(InnerHitBuilder other, QueryBuilder query, String parentChildType, boolean ignoreUnmapped) {
this(other);
this.query = query;
this.parentChildType = parentChildType;
@ -751,7 +752,8 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
}
}
static InnerHitBuilder rewrite(InnerHitBuilder original, QueryBuilder rewrittenQuery) {
// TODO public for hasParent and hasChild query
public static InnerHitBuilder rewrite(InnerHitBuilder original, QueryBuilder rewrittenQuery) {
if (original == null) {
return null;
}

View File

@ -23,7 +23,6 @@ import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.join.BitSetProducer;
import org.apache.lucene.search.join.ScoreMode;
import org.apache.lucene.search.join.ToParentBlockJoinQuery;
import org.elasticsearch.common.ParseField;
import org.elasticsearch.common.ParsingException;
import org.elasticsearch.common.io.stream.StreamInput;
@ -36,6 +35,7 @@ import org.elasticsearch.index.search.ESToParentBlockJoinQuery;
import org.elasticsearch.index.search.NestedHelper;
import java.io.IOException;
import java.util.Locale;
import java.util.Map;
import java.util.Objects;
@ -144,7 +144,7 @@ public class NestedQueryBuilder extends AbstractQueryBuilder<NestedQueryBuilder>
builder.field(PATH_FIELD.getPreferredName(), path);
builder.field(IGNORE_UNMAPPED_FIELD.getPreferredName(), ignoreUnmapped);
if (scoreMode != null) {
builder.field(SCORE_MODE_FIELD.getPreferredName(), HasChildQueryBuilder.scoreModeAsString(scoreMode));
builder.field(SCORE_MODE_FIELD.getPreferredName(), scoreModeAsString(scoreMode));
}
printBoostAndQueryName(builder);
if (innerHitBuilder != null) {
@ -183,7 +183,7 @@ public class NestedQueryBuilder extends AbstractQueryBuilder<NestedQueryBuilder>
} else if (IGNORE_UNMAPPED_FIELD.match(currentFieldName)) {
ignoreUnmapped = parser.booleanValue();
} else if (SCORE_MODE_FIELD.match(currentFieldName)) {
scoreMode = HasChildQueryBuilder.parseScoreMode(parser.text());
scoreMode = parseScoreMode(parser.text());
} else if (AbstractQueryBuilder.NAME_FIELD.match(currentFieldName)) {
queryName = parser.text();
} else {
@ -201,6 +201,30 @@ public class NestedQueryBuilder extends AbstractQueryBuilder<NestedQueryBuilder>
return queryBuilder;
}
public static ScoreMode parseScoreMode(String scoreModeString) {
if ("none".equals(scoreModeString)) {
return ScoreMode.None;
} else if ("min".equals(scoreModeString)) {
return ScoreMode.Min;
} else if ("max".equals(scoreModeString)) {
return ScoreMode.Max;
} else if ("avg".equals(scoreModeString)) {
return ScoreMode.Avg;
} else if ("sum".equals(scoreModeString)) {
return ScoreMode.Total;
}
throw new IllegalArgumentException("No score mode for child query [" + scoreModeString + "] found");
}
public static String scoreModeAsString(ScoreMode scoreMode) {
if (scoreMode == ScoreMode.Total) {
// Lucene uses 'total' but 'sum' is more consistent with other elasticsearch APIs
return "sum";
} else {
return scoreMode.name().toLowerCase(Locale.ROOT);
}
}
@Override
public final String getWriteableName() {
return NAME;

View File

@ -471,30 +471,6 @@ public abstract class QueryBuilders {
return moreLikeThisQuery(null, null, likeItems);
}
/**
* Constructs a new has_child query, with the child type and the query to run on the child documents. The
* results of this query are the parent docs that those child docs matched.
*
* @param type The child type.
* @param query The query.
* @param scoreMode How the scores from the children hits should be aggregated into the parent hit.
*/
public static HasChildQueryBuilder hasChildQuery(String type, QueryBuilder query, ScoreMode scoreMode) {
return new HasChildQueryBuilder(type, query, scoreMode);
}
/**
* Constructs a new parent query, with the parent type and the query to run on the parent documents. The
* results of this query are the children docs that those parent docs matched.
*
* @param type The parent type.
* @param query The query.
* @param score Whether the score from the parent hit should propagate to the child hit
*/
public static HasParentQueryBuilder hasParentQuery(String type, QueryBuilder query, boolean score) {
return new HasParentQueryBuilder(type, query, score);
}
/**
* Constructs a new parent id query that returns all child documents of the specified type that
* point to the specified id.

View File

@ -20,8 +20,6 @@
package org.elasticsearch.search;
import org.apache.lucene.search.BooleanQuery;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.NamedRegistry;
import org.elasticsearch.common.geo.ShapesAvailability;
import org.elasticsearch.common.geo.builders.ShapeBuilders;
@ -45,8 +43,6 @@ import org.elasticsearch.index.query.GeoBoundingBoxQueryBuilder;
import org.elasticsearch.index.query.GeoDistanceQueryBuilder;
import org.elasticsearch.index.query.GeoPolygonQueryBuilder;
import org.elasticsearch.index.query.GeoShapeQueryBuilder;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import org.elasticsearch.index.query.HasParentQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.MatchNoneQueryBuilder;
@ -103,8 +99,6 @@ import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.PipelineAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrixAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.adjacency.InternalAdjacencyMatrix;
import org.elasticsearch.search.aggregations.bucket.children.ChildrenAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.children.InternalChildren;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.InternalFilter;
import org.elasticsearch.search.aggregations.bucket.filters.FiltersAggregationBuilder;
@ -256,7 +250,6 @@ import org.elasticsearch.search.suggest.term.TermSuggestionBuilder;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
@ -410,9 +403,6 @@ public class SearchModule {
GeoCentroidAggregationBuilder::parse).addResultReader(InternalGeoCentroid::new));
registerAggregation(new AggregationSpec(ScriptedMetricAggregationBuilder.NAME, ScriptedMetricAggregationBuilder::new,
ScriptedMetricAggregationBuilder::parse).addResultReader(InternalScriptedMetric::new));
registerAggregation(new AggregationSpec(ChildrenAggregationBuilder.NAME, ChildrenAggregationBuilder::new,
ChildrenAggregationBuilder::parse).addResultReader(InternalChildren::new));
registerFromPlugin(plugins, SearchPlugin::getAggregations, this::registerAggregation);
}
@ -706,8 +696,6 @@ public class SearchModule {
MatchPhrasePrefixQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(MultiMatchQueryBuilder.NAME, MultiMatchQueryBuilder::new, MultiMatchQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(NestedQueryBuilder.NAME, NestedQueryBuilder::new, NestedQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(HasChildQueryBuilder.NAME, HasChildQueryBuilder::new, HasChildQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(HasParentQueryBuilder.NAME, HasParentQueryBuilder::new, HasParentQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(DisMaxQueryBuilder.NAME, DisMaxQueryBuilder::new, DisMaxQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(IdsQueryBuilder.NAME, IdsQueryBuilder::new, IdsQueryBuilder::fromXContent));
registerQuery(new QuerySpec<>(MatchAllQueryBuilder.NAME, MatchAllQueryBuilder::new, MatchAllQueryBuilder::fromXContent));

View File

@ -23,8 +23,6 @@ import org.elasticsearch.common.geo.GeoPoint;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrix;
import org.elasticsearch.search.aggregations.bucket.adjacency.AdjacencyMatrixAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.children.Children;
import org.elasticsearch.search.aggregations.bucket.children.ChildrenAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filter.Filter;
import org.elasticsearch.search.aggregations.bucket.filter.FilterAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.filters.Filters;
@ -163,20 +161,20 @@ public class AggregationBuilders {
public static FiltersAggregationBuilder filters(String name, QueryBuilder... filters) {
return new FiltersAggregationBuilder(name, filters);
}
/**
* Create a new {@link AdjacencyMatrix} aggregation with the given name.
*/
public static AdjacencyMatrixAggregationBuilder adjacencyMatrix(String name, Map<String, QueryBuilder> filters) {
return new AdjacencyMatrixAggregationBuilder(name, filters);
}
}
/**
* Create a new {@link AdjacencyMatrix} aggregation with the given name and separator
*/
public static AdjacencyMatrixAggregationBuilder adjacencyMatrix(String name, String separator, Map<String, QueryBuilder> filters) {
return new AdjacencyMatrixAggregationBuilder(name, separator, filters);
}
}
/**
* Create a new {@link Sampler} aggregation with the given name.
@ -220,13 +218,6 @@ public class AggregationBuilders {
return new ReverseNestedAggregationBuilder(name);
}
/**
* Create a new {@link Children} aggregation with the given name.
*/
public static ChildrenAggregationBuilder children(String name, String childType) {
return new ChildrenAggregationBuilder(name, childType);
}
/**
* Create a new {@link GeoDistance} aggregation with the given name.
*/

View File

@ -26,7 +26,6 @@ import org.apache.lucene.search.highlight.WeightedSpanTerm;
import org.apache.lucene.search.highlight.WeightedSpanTermExtractor;
import org.elasticsearch.common.lucene.search.function.FiltersFunctionScoreQuery;
import org.elasticsearch.common.lucene.search.function.FunctionScoreQuery;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import java.io.IOException;
import java.util.Map;
@ -83,7 +82,7 @@ public final class CustomQueryScorer extends QueryScorer {
}
protected void extract(Query query, float boost, Map<String, WeightedSpanTerm> terms) throws IOException {
if (query instanceof HasChildQueryBuilder.LateParsingQuery) {
if (isChildOrParentQuery(query.getClass())) {
// skip has_child or has_parent queries, see: https://github.com/elastic/elasticsearch/issues/14999
return;
} else if (query instanceof FunctionScoreQuery) {
@ -94,5 +93,13 @@ public final class CustomQueryScorer extends QueryScorer {
super.extract(query, boost, terms);
}
}
/**
* Workaround to detect parent/child query
*/
private static final String PARENT_CHILD_QUERY_NAME = "HasChildQueryBuilder$LateParsingQuery";
private static boolean isChildOrParentQuery(Class<?> clazz) {
return clazz.getName().endsWith(PARENT_CHILD_QUERY_NAME);
}
}
}

View File

@ -450,156 +450,7 @@ public class BulkWithUpdatesIT extends ESIntegTestCase {
assertHitCount(countResponse, numDocs);
}
/*
Test for https://github.com/elastic/elasticsearch/issues/3444
*/
public void testBulkUpdateDocAsUpsertWithParent() throws Exception {
client().admin().indices().prepareCreate("test")
.setSettings("index.mapping.single_type", false)
.addMapping("parent", "{\"parent\":{}}", XContentType.JSON)
.addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON)
.execute().actionGet();
ensureGreen();
BulkRequestBuilder builder = client().prepareBulk();
// It's important to use JSON parsing here and request objects: issue 3444 is related to incomplete option parsing
byte[] addParent = new BytesArray(
"{" +
" \"index\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"parent\"," +
" \"_id\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"field1\" : \"value1\"" +
"}" +
"\n").array();
byte[] addChild = new BytesArray(
"{" +
" \"update\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"child\"," +
" \"_id\" : \"child1\"," +
" \"parent\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"doc\" : {" +
" \"field1\" : \"value1\"" +
" }," +
" \"doc_as_upsert\" : \"true\"" +
"}" +
"\n").array();
builder.add(addParent, 0, addParent.length, XContentType.JSON);
builder.add(addChild, 0, addChild.length, XContentType.JSON);
BulkResponse bulkResponse = builder.get();
assertThat(bulkResponse.getItems().length, equalTo(2));
assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false));
assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false));
client().admin().indices().prepareRefresh("test").get();
//we check that the _parent field was set on the child document by using the has parent query
SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(QueryBuilders.hasParentQuery("parent", QueryBuilders.matchAllQuery(), false))
.get();
assertNoFailures(searchResponse);
assertSearchHits(searchResponse, "child1");
}
/*
Test for https://github.com/elastic/elasticsearch/issues/3444
*/
public void testBulkUpdateUpsertWithParent() throws Exception {
assertAcked(prepareCreate("test")
.setSettings("index.mapping.single_type", false)
.addMapping("parent", "{\"parent\":{}}", XContentType.JSON)
.addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON));
ensureGreen();
BulkRequestBuilder builder = client().prepareBulk();
byte[] addParent = new BytesArray(
"{" +
" \"index\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"parent\"," +
" \"_id\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"field1\" : \"value1\"" +
"}" +
"\n").array();
byte[] addChild1 = new BytesArray(
"{" +
" \"update\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"child\"," +
" \"_id\" : \"child1\"," +
" \"parent\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"script\" : {" +
" \"inline\" : \"ctx._source.field2 = 'value2'\"" +
" }," +
" \"lang\" : \"" + CustomScriptPlugin.NAME + "\"," +
" \"upsert\" : {" +
" \"field1\" : \"value1'\"" +
" }" +
"}" +
"\n").array();
byte[] addChild2 = new BytesArray(
"{" +
" \"update\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"child\"," +
" \"_id\" : \"child1\"," +
" \"parent\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"script\" : \"ctx._source.field2 = 'value2'\"," +
" \"upsert\" : {" +
" \"field1\" : \"value1'\"" +
" }" +
"}" +
"\n").array();
builder.add(addParent, 0, addParent.length, XContentType.JSON);
builder.add(addChild1, 0, addChild1.length, XContentType.JSON);
builder.add(addChild2, 0, addChild2.length, XContentType.JSON);
BulkResponse bulkResponse = builder.get();
assertThat(bulkResponse.getItems().length, equalTo(3));
assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false));
assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false));
assertThat(bulkResponse.getItems()[2].isFailed(), equalTo(true));
assertThat(bulkResponse.getItems()[2].getFailure().getCause().getCause().getMessage(),
equalTo("script_lang not supported [painless]"));
client().admin().indices().prepareRefresh("test").get();
SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(QueryBuilders.hasParentQuery("parent", QueryBuilders.matchAllQuery(), false))
.get();
assertSearchHits(searchResponse, "child1");
}
/*
* Test for https://github.com/elastic/elasticsearch/issues/8365

View File

@ -63,8 +63,6 @@ import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_ME
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_READ;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_BLOCKS_WRITE;
import static org.elasticsearch.cluster.metadata.IndexMetaData.SETTING_READ_ONLY;
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.rangeQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
@ -824,27 +822,6 @@ public class IndexAliasesIT extends ESIntegTestCase {
}
}
public void testAliasesFilterWithHasChildQuery() throws Exception {
assertAcked(prepareCreate("my-index")
.setSettings("index.mapping.single_type", false)
.addMapping("parent")
.addMapping("child", "_parent", "type=parent")
);
client().prepareIndex("my-index", "parent", "1").setSource("{}", XContentType.JSON).get();
client().prepareIndex("my-index", "child", "2").setSource("{}", XContentType.JSON).setParent("1").get();
refresh();
assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter1", hasChildQuery("child", matchAllQuery(), ScoreMode.None)));
assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter2", hasParentQuery("parent", matchAllQuery(), false)));
SearchResponse response = client().prepareSearch("filter1").get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
response = client().prepareSearch("filter2").get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("2"));
}
public void testAliasesWithBlocks() {
createIndex("test");
ensureGreen();

View File

@ -153,24 +153,6 @@ public class InnerHitBuilderTests extends ESTestCase {
assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue());
}
public void testInlineLeafInnerHitsHasChildQuery() throws Exception {
InnerHitBuilder leafInnerHits = randomInnerHits();
HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None)
.innerHit(leafInnerHits, false);
Map<String, InnerHitBuilder> innerHitBuilders = new HashMap<>();
hasChildQueryBuilder.extractInnerHitBuilders(innerHitBuilders);
assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue());
}
public void testInlineLeafInnerHitsHasParentQuery() throws Exception {
InnerHitBuilder leafInnerHits = randomInnerHits();
HasParentQueryBuilder hasParentQueryBuilder = new HasParentQueryBuilder("type", new MatchAllQueryBuilder(), false)
.innerHit(leafInnerHits, false);
Map<String, InnerHitBuilder> innerHitBuilders = new HashMap<>();
hasParentQueryBuilder.extractInnerHitBuilders(innerHitBuilders);
assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue());
}
public void testInlineLeafInnerHitsNestedQueryViaBoolQuery() {
InnerHitBuilder leafInnerHits = randomInnerHits();
NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("path", new MatchAllQueryBuilder(), ScoreMode.None)
@ -181,25 +163,6 @@ public class InnerHitBuilderTests extends ESTestCase {
assertThat(innerHitBuilders.get(leafInnerHits.getName()), notNullValue());
}
public void testInlineLeafInnerHitsNestedQueryViaDisMaxQuery() {
InnerHitBuilder leafInnerHits1 = randomInnerHits();
NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("path", new MatchAllQueryBuilder(), ScoreMode.None)
.innerHit(leafInnerHits1, false);
InnerHitBuilder leafInnerHits2 = randomInnerHits();
HasChildQueryBuilder hasChildQueryBuilder = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None)
.innerHit(leafInnerHits2, false);
DisMaxQueryBuilder disMaxQueryBuilder = new DisMaxQueryBuilder();
disMaxQueryBuilder.add(nestedQueryBuilder);
disMaxQueryBuilder.add(hasChildQueryBuilder);
Map<String, InnerHitBuilder> innerHitBuilders = new HashMap<>();
disMaxQueryBuilder.extractInnerHitBuilders(innerHitBuilders);
assertThat(innerHitBuilders.size(), equalTo(2));
assertThat(innerHitBuilders.get(leafInnerHits1.getName()), notNullValue());
assertThat(innerHitBuilders.get(leafInnerHits2.getName()), notNullValue());
}
public void testInlineLeafInnerHitsNestedQueryViaConstantScoreQuery() {
InnerHitBuilder leafInnerHits = randomInnerHits();
NestedQueryBuilder nestedQueryBuilder = new NestedQueryBuilder("path", new MatchAllQueryBuilder(), ScoreMode.None)
@ -252,43 +215,6 @@ public class InnerHitBuilderTests extends ESTestCase {
assertThat(innerHitsContext.getInnerHits().size(), equalTo(0));
}
public void testBuild_ignoreUnmappedHasChildQuery() throws Exception {
QueryShardContext queryShardContext = mock(QueryShardContext.class);
when(queryShardContext.documentMapper("type")).thenReturn(null);
SearchContext searchContext = mock(SearchContext.class);
when(searchContext.getQueryShardContext()).thenReturn(queryShardContext);
InnerHitBuilder leafInnerHits = randomInnerHits();
HasChildQueryBuilder query1 = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None)
.innerHit(leafInnerHits, false);
expectThrows(IllegalStateException.class, () -> query1.innerHit().build(searchContext, new InnerHitsContext()));
HasChildQueryBuilder query2 = new HasChildQueryBuilder("type", new MatchAllQueryBuilder(), ScoreMode.None)
.innerHit(leafInnerHits, true);
InnerHitsContext innerHitsContext = new InnerHitsContext();
query2.innerHit().build(searchContext, innerHitsContext);
assertThat(innerHitsContext.getInnerHits().size(), equalTo(0));
}
public void testBuild_ingoreUnmappedHasParentQuery() throws Exception {
QueryShardContext queryShardContext = mock(QueryShardContext.class);
when(queryShardContext.documentMapper("type")).thenReturn(null);
SearchContext searchContext = mock(SearchContext.class);
when(searchContext.getQueryShardContext()).thenReturn(queryShardContext);
InnerHitBuilder leafInnerHits = randomInnerHits();
HasParentQueryBuilder query1 = new HasParentQueryBuilder("type", new MatchAllQueryBuilder(), false)
.innerHit(leafInnerHits, false);
expectThrows(IllegalStateException.class, () -> query1.innerHit().build(searchContext, new InnerHitsContext()));
HasParentQueryBuilder query2 = new HasParentQueryBuilder("type", new MatchAllQueryBuilder(), false)
.innerHit(leafInnerHits, true);
InnerHitsContext innerHitsContext = new InnerHitsContext();
query2.innerHit().build(searchContext, innerHitsContext);
assertThat(innerHitsContext.getInnerHits().size(), equalTo(0));
}
public static InnerHitBuilder randomInnerHits() {
return randomInnerHits(true, true);
}

View File

@ -61,7 +61,7 @@ public class NestedQueryBuilderTests extends AbstractQueryTestCase<NestedQueryBu
}
/**
* @return a {@link HasChildQueryBuilder} with random values all over the place
* @return a {@link NestedQueryBuilder} with random values all over the place
*/
@Override
protected NestedQueryBuilder doCreateTestQueryBuilder() {
@ -203,4 +203,46 @@ public class NestedQueryBuilderTests extends AbstractQueryTestCase<NestedQueryBu
assertThat(query, notNullValue());
assertThat(query, instanceOf(MatchNoDocsQuery.class));
}
public void testMinFromString() {
assertThat("fromString(min) != MIN", ScoreMode.Min, equalTo(NestedQueryBuilder.parseScoreMode("min")));
assertThat("min", equalTo(NestedQueryBuilder.scoreModeAsString(ScoreMode.Min)));
}
public void testMaxFromString() {
assertThat("fromString(max) != MAX", ScoreMode.Max, equalTo(NestedQueryBuilder.parseScoreMode("max")));
assertThat("max", equalTo(NestedQueryBuilder.scoreModeAsString(ScoreMode.Max)));
}
public void testAvgFromString() {
assertThat("fromString(avg) != AVG", ScoreMode.Avg, equalTo(NestedQueryBuilder.parseScoreMode("avg")));
assertThat("avg", equalTo(NestedQueryBuilder.scoreModeAsString(ScoreMode.Avg)));
}
public void testSumFromString() {
assertThat("fromString(total) != SUM", ScoreMode.Total, equalTo(NestedQueryBuilder.parseScoreMode("sum")));
assertThat("sum", equalTo(NestedQueryBuilder.scoreModeAsString(ScoreMode.Total)));
}
public void testNoneFromString() {
assertThat("fromString(none) != NONE", ScoreMode.None, equalTo(NestedQueryBuilder.parseScoreMode("none")));
assertThat("none", equalTo(NestedQueryBuilder.scoreModeAsString(ScoreMode.None)));
}
/**
* Should throw {@link IllegalArgumentException} instead of NPE.
*/
public void testThatNullFromStringThrowsException() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> NestedQueryBuilder.parseScoreMode(null));
assertEquals("No score mode for child query [null] found", e.getMessage());
}
/**
* Failure should not change (and the value should never match anything...).
*/
public void testThatUnrecognizedFromStringThrowsException() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> NestedQueryBuilder.parseScoreMode("unrecognized value"));
assertEquals("No score mode for child query [unrecognized value] found", e.getMessage());
}
}

View File

@ -270,8 +270,6 @@ public class SearchModuleTests extends ModuleTestCase {
"geo_distance",
"geo_polygon",
"geo_shape",
"has_child",
"has_parent",
"ids",
"match",
"match_all",

View File

@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.filter;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.List;

View File

@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.global;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.List;

View File

@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.missing;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.List;

View File

@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.nested;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.List;

View File

@ -21,7 +21,7 @@ package org.elasticsearch.search.aggregations.bucket.nested;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.List;

View File

@ -20,7 +20,7 @@ package org.elasticsearch.search.aggregations.bucket.sampler;
import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.List;
@ -42,4 +42,4 @@ public class InternalSamplerTests extends InternalSingleBucketAggregationTestCas
protected Writeable.Reader<InternalSampler> instanceReader() {
return InternalSampler::new;
}
}
}

View File

@ -55,8 +55,6 @@ import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.common.xcontent.support.XContentMapValues.extractValue;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
@ -246,268 +244,6 @@ public class InnerHitsIT extends ESIntegTestCase {
}
}
public void testSimpleParentChild() throws Exception {
assertAcked(prepareCreate("articles")
.setSettings("index.mapping.single_type", false)
.addMapping("article", "title", "type=text")
.addMapping("comment", "_parent", "type=article", "message", "type=text,fielddata=true")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox"));
requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick"));
requests.add(client().prepareIndex("articles", "comment", "2").setParent("1").setSource("message", "fox ate rabbit x y z"));
requests.add(client().prepareIndex("articles", "comment", "3").setParent("1").setSource("message", "rabbit got away"));
requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant"));
requests.add(client().prepareIndex("articles", "comment", "4").setParent("2").setSource("message", "elephant captured"));
requests.add(client().prepareIndex("articles", "comment", "5").setParent("2").setSource("message", "mice squashed by elephant x"));
requests.add(client().prepareIndex("articles", "comment", "6").setParent("2").setSource("message", "elephant scared by mice x y"));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("1"));
assertThat(response.getHits().getAt(0).getShard(), notNullValue());
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(2L));
assertThat(innerHits.getAt(0).getId(), equalTo("1"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
assertThat(innerHits.getAt(1).getId(), equalTo("2"));
assertThat(innerHits.getAt(1).getType(), equalTo("comment"));
response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment", matchQuery("message", "elephant"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("2"));
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(3L));
assertThat(innerHits.getAt(0).getId(), equalTo("4"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
assertThat(innerHits.getAt(1).getId(), equalTo("5"));
assertThat(innerHits.getAt(1).getType(), equalTo("comment"));
assertThat(innerHits.getAt(2).getId(), equalTo("6"));
assertThat(innerHits.getAt(2).getType(), equalTo("comment"));
response = client().prepareSearch("articles")
.setQuery(
hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None).innerHit(
new InnerHitBuilder()
.addDocValueField("message")
.setHighlightBuilder(new HighlightBuilder().field("message"))
.setExplain(true).setSize(1)
.addScriptField("script", new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5",
Collections.emptyMap())),
false)
).get();
assertNoFailures(response);
innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getHits().length, equalTo(1));
assertThat(innerHits.getAt(0).getHighlightFields().get("message").getFragments()[0].string(), equalTo("<em>fox</em> eat quick"));
assertThat(innerHits.getAt(0).getExplanation().toString(), containsString("weight(message:fox"));
assertThat(innerHits.getAt(0).getFields().get("message").getValue().toString(), equalTo("eat"));
assertThat(innerHits.getAt(0).getFields().get("script").getValue().toString(), equalTo("5"));
}
public void testRandomParentChild() throws Exception {
assertAcked(prepareCreate("idx")
.setSettings("index.mapping.single_type", false)
.addMapping("parent")
.addMapping("child1", "_parent", "type=parent")
.addMapping("child2", "_parent", "type=parent")
);
int numDocs = scaledRandomIntBetween(5, 50);
List<IndexRequestBuilder> requestBuilders = new ArrayList<>();
int child1 = 0;
int child2 = 0;
int[] child1InnerObjects = new int[numDocs];
int[] child2InnerObjects = new int[numDocs];
for (int parent = 0; parent < numDocs; parent++) {
String parentId = String.format(Locale.ENGLISH, "%03d", parent);
requestBuilders.add(client().prepareIndex("idx", "parent", parentId).setSource("{}", XContentType.JSON));
int numChildDocs = child1InnerObjects[parent] = scaledRandomIntBetween(1, numDocs);
int limit = child1 + numChildDocs;
for (; child1 < limit; child1++) {
requestBuilders.add(client().prepareIndex("idx", "child1",
String.format(Locale.ENGLISH, "%04d", child1)).setParent(parentId).setSource("{}", XContentType.JSON));
}
numChildDocs = child2InnerObjects[parent] = scaledRandomIntBetween(1, numDocs);
limit = child2 + numChildDocs;
for (; child2 < limit; child2++) {
requestBuilders.add(client().prepareIndex("idx", "child2",
String.format(Locale.ENGLISH, "%04d", child2)).setParent(parentId).setSource("{}", XContentType.JSON));
}
}
indexRandom(true, requestBuilders);
int size = randomIntBetween(0, numDocs);
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
boolQuery.should(constantScoreQuery(hasChildQuery("child1", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder().setName("a")
.addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false)));
boolQuery.should(constantScoreQuery(hasChildQuery("child2", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder().setName("b")
.addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false)));
SearchResponse searchResponse = client().prepareSearch("idx")
.setSize(numDocs)
.setTypes("parent")
.addSort("_uid", SortOrder.ASC)
.setQuery(boolQuery)
.get();
assertNoFailures(searchResponse);
assertHitCount(searchResponse, numDocs);
assertThat(searchResponse.getHits().getHits().length, equalTo(numDocs));
int offset1 = 0;
int offset2 = 0;
for (int parent = 0; parent < numDocs; parent++) {
SearchHit searchHit = searchResponse.getHits().getAt(parent);
assertThat(searchHit.getType(), equalTo("parent"));
assertThat(searchHit.getId(), equalTo(String.format(Locale.ENGLISH, "%03d", parent)));
assertThat(searchHit.getShard(), notNullValue());
SearchHits inner = searchHit.getInnerHits().get("a");
assertThat(inner.getTotalHits(), equalTo((long) child1InnerObjects[parent]));
for (int child = 0; child < child1InnerObjects[parent] && child < size; child++) {
SearchHit innerHit = inner.getAt(child);
assertThat(innerHit.getType(), equalTo("child1"));
String childId = String.format(Locale.ENGLISH, "%04d", offset1 + child);
assertThat(innerHit.getId(), equalTo(childId));
assertThat(innerHit.getNestedIdentity(), nullValue());
}
offset1 += child1InnerObjects[parent];
inner = searchHit.getInnerHits().get("b");
assertThat(inner.getTotalHits(), equalTo((long) child2InnerObjects[parent]));
for (int child = 0; child < child2InnerObjects[parent] && child < size; child++) {
SearchHit innerHit = inner.getAt(child);
assertThat(innerHit.getType(), equalTo("child2"));
String childId = String.format(Locale.ENGLISH, "%04d", offset2 + child);
assertThat(innerHit.getId(), equalTo(childId));
assertThat(innerHit.getNestedIdentity(), nullValue());
}
offset2 += child2InnerObjects[parent];
}
}
public void testInnerHitsOnHasParent() throws Exception {
assertAcked(prepareCreate("stack")
.setSettings("index.mapping.single_type", false)
.addMapping("question", "body", "type=text")
.addMapping("answer", "_parent", "type=question", "body", "type=text")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("stack", "question", "1").setSource("body", "I'm using HTTPS + Basic authentication "
+ "to protect a resource. How can I throttle authentication attempts to protect against brute force attacks?"));
requests.add(client().prepareIndex("stack", "answer", "1").setParent("1").setSource("body",
"install fail2ban and enable rules for apache"));
requests.add(client().prepareIndex("stack", "question", "2").setSource("body",
"I have firewall rules set up and also denyhosts installed.\\ndo I also need to install fail2ban?"));
requests.add(client().prepareIndex("stack", "answer", "2").setParent("2").setSource("body",
"Denyhosts protects only ssh; Fail2Ban protects all daemons."));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("stack")
.setTypes("answer")
.addSort("_uid", SortOrder.ASC)
.setQuery(
boolQuery()
.must(matchQuery("body", "fail2ban"))
.must(hasParentQuery("question", matchAllQuery(), false).innerHit(new InnerHitBuilder(), false))
).get();
assertNoFailures(response);
assertHitCount(response, 2);
SearchHit searchHit = response.getHits().getAt(0);
assertThat(searchHit.getId(), equalTo("1"));
assertThat(searchHit.getType(), equalTo("answer"));
assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question"));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("1"));
searchHit = response.getHits().getAt(1);
assertThat(searchHit.getId(), equalTo("2"));
assertThat(searchHit.getType(), equalTo("answer"));
assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question"));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("2"));
}
public void testParentChildMultipleLayers() throws Exception {
assertAcked(prepareCreate("articles")
.setSettings("index.mapping.single_type", false)
.addMapping("article", "title", "type=text")
.addMapping("comment", "_parent", "type=article", "message", "type=text")
.addMapping("remark", "_parent", "type=comment", "message", "type=text")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox"));
requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick"));
requests.add(client().prepareIndex("articles", "remark", "1").setParent("1").setRouting("1").setSource("message", "good"));
requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant"));
requests.add(client().prepareIndex("articles", "comment", "2").setParent("2").setSource("message", "elephant captured"));
requests.add(client().prepareIndex("articles", "remark", "2").setParent("2").setRouting("2").setSource("message", "bad"));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment",
hasChildQuery("remark", matchQuery("message", "good"), ScoreMode.None).innerHit(new InnerHitBuilder(), false),
ScoreMode.None).innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("1"));
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("1"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
innerHits = innerHits.getAt(0).getInnerHits().get("remark");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("1"));
assertThat(innerHits.getAt(0).getType(), equalTo("remark"));
response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment",
hasChildQuery("remark", matchQuery("message", "bad"), ScoreMode.None).innerHit(new InnerHitBuilder(), false),
ScoreMode.None).innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("2"));
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("2"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
innerHits = innerHits.getAt(0).getInnerHits().get("remark");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("2"));
assertThat(innerHits.getAt(0).getType(), equalTo("remark"));
}
public void testNestedMultipleLayers() throws Exception {
assertAcked(prepareCreate("articles").addMapping("article", jsonBuilder().startObject()
.startObject("article").startObject("properties")
@ -724,92 +460,6 @@ public class InnerHitsIT extends ESIntegTestCase {
assertThat(messages.getAt(0).getNestedIdentity().getChild(), nullValue());
}
public void testRoyals() throws Exception {
assertAcked(
prepareCreate("royals")
.setSettings("index.mapping.single_type", false)
.addMapping("king")
.addMapping("prince", "_parent", "type=king")
.addMapping("duke", "_parent", "type=prince")
.addMapping("earl", "_parent", "type=duke")
.addMapping("baron", "_parent", "type=earl")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("royals", "king", "king").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "prince", "prince").setParent("king").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "duke", "duke").setParent("prince").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl1").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl2").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl3").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl4").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron1").setParent("earl1").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron2").setParent("earl2").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron3").setParent("earl3").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron4").setParent("earl4").setRouting("king")
.setSource("{}", XContentType.JSON));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("royals")
.setTypes("duke")
.setQuery(boolQuery()
.filter(hasParentQuery("prince",
hasParentQuery("king", matchAllQuery(), false).innerHit(new InnerHitBuilder().setName("kings"), false),
false).innerHit(new InnerHitBuilder().setName("princes"), false)
)
.filter(hasChildQuery("earl",
hasChildQuery("baron", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder().setName("barons"), false),
ScoreMode.None).innerHit(new InnerHitBuilder()
.addSort(SortBuilders.fieldSort("_uid").order(SortOrder.ASC))
.setName("earls")
.setSize(4), false)
)
)
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("duke"));
SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("earls");
assertThat(innerHits.getTotalHits(), equalTo(4L));
assertThat(innerHits.getAt(0).getId(), equalTo("earl1"));
assertThat(innerHits.getAt(1).getId(), equalTo("earl2"));
assertThat(innerHits.getAt(2).getId(), equalTo("earl3"));
assertThat(innerHits.getAt(3).getId(), equalTo("earl4"));
SearchHits innerInnerHits = innerHits.getAt(0).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron1"));
innerInnerHits = innerHits.getAt(1).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron2"));
innerInnerHits = innerHits.getAt(2).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron3"));
innerInnerHits = innerHits.getAt(3).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron4"));
innerHits = response.getHits().getAt(0).getInnerHits().get("princes");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("prince"));
innerInnerHits = innerHits.getAt(0).getInnerHits().get("kings");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("king"));
}
public void testMatchesQueriesNestedInnerHits() throws Exception {
XContentBuilder builder = jsonBuilder().startObject()
.startObject("type1")
@ -914,84 +564,6 @@ public class InnerHitsIT extends ESIntegTestCase {
}
}
public void testMatchesQueriesParentChildInnerHits() throws Exception {
assertAcked(prepareCreate("index")
.setSettings("index.mapping.single_type", false)
.addMapping("child", "_parent", "type=parent"));
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("index", "parent", "1").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("index", "child", "1").setParent("1").setSource("field", "value1"));
requests.add(client().prepareIndex("index", "child", "2").setParent("1").setSource("field", "value2"));
requests.add(client().prepareIndex("index", "parent", "2").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("index", "child", "3").setParent("2").setSource("field", "value1"));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("index")
.setQuery(hasChildQuery("child", matchQuery("field", "value1").queryName("_name1"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false))
.addSort("_uid", SortOrder.ASC)
.get();
assertHitCount(response, 2);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1"));
assertThat(response.getHits().getAt(1).getId(), equalTo("2"));
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getTotalHits(), equalTo(1L));
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1"));
QueryBuilder query = hasChildQuery("child", matchQuery("field", "value2").queryName("_name2"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false);
response = client().prepareSearch("index")
.setQuery(query)
.addSort("_uid", SortOrder.ASC)
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name2"));
}
public void testDontExplode() throws Exception {
assertAcked(prepareCreate("index1")
.setSettings("index.mapping.single_type", false)
.addMapping("child", "_parent", "type=parent"));
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("index1", "parent", "1").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("index1", "child", "1").setParent("1").setSource("field", "value1"));
indexRandom(true, requests);
QueryBuilder query = hasChildQuery("child", matchQuery("field", "value1"), ScoreMode.None)
.innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false);
SearchResponse response = client().prepareSearch("index1")
.setQuery(query)
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertAcked(prepareCreate("index2").addMapping("type", "nested", "type=nested"));
client().prepareIndex("index2", "type", "1").setSource(jsonBuilder().startObject()
.startArray("nested")
.startObject()
.field("field", "value1")
.endObject()
.endArray()
.endObject())
.setRefreshPolicy(IMMEDIATE)
.get();
query = nestedQuery("nested", matchQuery("nested.field", "value1"), ScoreMode.Avg)
.innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false);
response = client().prepareSearch("index2")
.setQuery(query)
.get();
assertNoFailures(response);
assertHitCount(response, 1);
}
public void testNestedSourceFiltering() throws Exception {
assertAcked(prepareCreate("index1").addMapping("message", "comments", "type=nested"));
client().prepareIndex("index1", "message", "1").setSource(jsonBuilder().startObject()
@ -1021,25 +593,6 @@ public class InnerHitsIT extends ESIntegTestCase {
equalTo("fox ate rabbit x y z"));
}
public void testNestedInnerHitWrappedInParentChildInnerhit() throws Exception {
assertAcked(prepareCreate("test")
.setSettings("index.mapping.single_type", false)
.addMapping("child_type", "_parent", "type=parent_type", "nested_type", "type=nested"));
client().prepareIndex("test", "parent_type", "1").setSource("key", "value").get();
client().prepareIndex("test", "child_type", "2").setParent("1").setSource("nested_type", Collections.singletonMap("key", "value"))
.get();
refresh();
SearchResponse response = client().prepareSearch("test")
.setQuery(boolQuery().must(matchQuery("key", "value"))
.should(hasChildQuery("child_type", nestedQuery("nested_type", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false), ScoreMode.None).innerHit(new InnerHitBuilder(), false)))
.get();
assertHitCount(response, 1);
SearchHit hit = response.getHits().getAt(0);
assertThat(hit.getInnerHits().get("child_type").getAt(0).field("_parent").getValue(), equalTo("1"));
assertThat(hit.getInnerHits().get("child_type").getAt(0).getInnerHits().get("nested_type").getAt(0).field("_parent"), nullValue());
}
public void testInnerHitsWithIgnoreUnmapped() throws Exception {
assertAcked(prepareCreate("index1")
.setSettings("index.mapping.single_type", false)
@ -1062,17 +615,6 @@ public class InnerHitsIT extends ESIntegTestCase {
assertNoFailures(response);
assertHitCount(response, 2);
assertSearchHits(response, "1", "3");
response = client().prepareSearch("index1", "index2")
.setQuery(boolQuery()
.should(hasChildQuery("child_type", matchAllQuery(), ScoreMode.None).ignoreUnmapped(true)
.innerHit(new InnerHitBuilder(), true))
.should(termQuery("key", "value"))
)
.get();
assertNoFailures(response);
assertHitCount(response, 2);
assertSearchHits(response, "1", "3");
}
}

View File

@ -24,7 +24,7 @@ Import Aggregation definition classes:
[source,java]
--------------------------------------------------
import org.elasticsearch.search.aggregations.bucket.children.Children;
import org.elasticsearch.join.aggregations.Children;
--------------------------------------------------
[source,java]

View File

@ -0,0 +1,24 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
esplugin {
description 'This module adds the support parent-child queries and aggregations'
classname 'org.elasticsearch.join.ParentJoinPlugin'
hasClientJar = true
}

View File

@ -0,0 +1,54 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.join;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.join.aggregations.ChildrenAggregationBuilder;
import org.elasticsearch.join.aggregations.InternalChildren;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.SearchPlugin;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
public class ParentJoinPlugin extends Plugin implements SearchPlugin {
public ParentJoinPlugin(Settings settings) {}
@Override
public List<QuerySpec<?>> getQueries() {
return Arrays.asList(
new QuerySpec<>(HasChildQueryBuilder.NAME, HasChildQueryBuilder::new, HasChildQueryBuilder::fromXContent),
new QuerySpec<>(HasParentQueryBuilder.NAME, HasParentQueryBuilder::new, HasParentQueryBuilder::fromXContent)
);
}
@Override
public List<AggregationSpec> getAggregations() {
return Collections.singletonList(
new AggregationSpec(ChildrenAggregationBuilder.NAME, ChildrenAggregationBuilder::new, ChildrenAggregationBuilder::parse)
.addResultReader(InternalChildren::new)
);
}
}

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.children;
package org.elasticsearch.join.aggregations;
import org.elasticsearch.search.aggregations.bucket.SingleBucketAggregation;

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.children;
package org.elasticsearch.join.aggregations;
import org.apache.lucene.search.Query;
import org.elasticsearch.common.ParsingException;

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.children;
package org.elasticsearch.join.aggregations;
import org.apache.lucene.search.Query;
import org.elasticsearch.search.aggregations.Aggregator;

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.children;
package org.elasticsearch.join.aggregations;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.search.aggregations.InternalAggregations;

View File

@ -0,0 +1,29 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.join.aggregations;
public abstract class JoinAggregationBuilders {
/**
* Create a new {@link Children} aggregation with the given name.
*/
public static ChildrenAggregationBuilder children(String name, String childType) {
return new ChildrenAggregationBuilder(name, childType);
}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.children;
package org.elasticsearch.join.aggregations;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.LeafReaderContext;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.query;
package org.elasticsearch.join.query;
import org.apache.lucene.index.DirectoryReader;
import org.apache.lucene.index.IndexReader;
@ -38,6 +38,14 @@ import org.elasticsearch.index.fielddata.IndexParentChildFieldData;
import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.ParentFieldMapper;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryRewriteContext;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import java.io.IOException;
import java.util.Locale;
@ -210,7 +218,7 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil
builder.field(QUERY_FIELD.getPreferredName());
query.toXContent(builder, params);
builder.field(TYPE_FIELD.getPreferredName(), type);
builder.field(SCORE_MODE_FIELD.getPreferredName(), scoreModeAsString(scoreMode));
builder.field(SCORE_MODE_FIELD.getPreferredName(), NestedQueryBuilder.scoreModeAsString(scoreMode));
builder.field(MIN_CHILDREN_FIELD.getPreferredName(), minChildren);
builder.field(MAX_CHILDREN_FIELD.getPreferredName(), maxChildren);
builder.field(IGNORE_UNMAPPED_FIELD.getPreferredName(), ignoreUnmapped);
@ -251,7 +259,7 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil
if (TYPE_FIELD.match(currentFieldName)) {
childType = parser.text();
} else if (SCORE_MODE_FIELD.match(currentFieldName)) {
scoreMode = parseScoreMode(parser.text());
scoreMode = NestedQueryBuilder.parseScoreMode(parser.text());
} else if (AbstractQueryBuilder.BOOST_FIELD.match(currentFieldName)) {
boost = parser.floatValue();
} else if (MIN_CHILDREN_FIELD.match(currentFieldName)) {
@ -278,30 +286,6 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil
return hasChildQueryBuilder;
}
public static ScoreMode parseScoreMode(String scoreModeString) {
if ("none".equals(scoreModeString)) {
return ScoreMode.None;
} else if ("min".equals(scoreModeString)) {
return ScoreMode.Min;
} else if ("max".equals(scoreModeString)) {
return ScoreMode.Max;
} else if ("avg".equals(scoreModeString)) {
return ScoreMode.Avg;
} else if ("sum".equals(scoreModeString)) {
return ScoreMode.Total;
}
throw new IllegalArgumentException("No score mode for child query [" + scoreModeString + "] found");
}
public static String scoreModeAsString(ScoreMode scoreMode) {
if (scoreMode == ScoreMode.Total) {
// Lucene uses 'total' but 'sum' is more consistent with other elasticsearch APIs
return "sum";
} else {
return scoreMode.name().toLowerCase(Locale.ROOT);
}
}
@Override
public String getWriteableName() {
return NAME;

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.index.query;
package org.elasticsearch.join.query;
import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
@ -33,6 +33,13 @@ import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.fielddata.plain.ParentChildIndexFieldData;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.ParentFieldMapper;
import org.elasticsearch.index.query.AbstractQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryRewriteContext;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import java.io.IOException;
import java.util.HashSet;

View File

@ -0,0 +1,50 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.join.query;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.index.query.QueryBuilder;
public abstract class JoinQueryBuilders {
/**
* Constructs a new has_child query, with the child type and the query to run on the child documents. The
* results of this query are the parent docs that those child docs matched.
*
* @param type The child type.
* @param query The query.
* @param scoreMode How the scores from the children hits should be aggregated into the parent hit.
*/
public static HasChildQueryBuilder hasChildQuery(String type, QueryBuilder query, ScoreMode scoreMode) {
return new HasChildQueryBuilder(type, query, scoreMode);
}
/**
* Constructs a new parent query, with the parent type and the query to run on the parent documents. The
* results of this query are the children docs that those parent docs matched.
*
* @param type The parent type.
* @param query The query.
* @param score Whether the score from the parent hit should propagate to the child hit
*/
public static HasParentQueryBuilder hasParentQuery(String type, QueryBuilder query, boolean score) {
return new HasParentQueryBuilder(type, query, score);
}
}

View File

@ -0,0 +1,37 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.join;
import com.carrotsearch.randomizedtesting.annotations.Name;
import com.carrotsearch.randomizedtesting.annotations.ParametersFactory;
import org.elasticsearch.test.rest.yaml.ClientYamlTestCandidate;
import org.elasticsearch.test.rest.yaml.ESClientYamlSuiteTestCase;
public class ParentChildClientYamlTestSuiteIT extends ESClientYamlSuiteTestCase {
public ParentChildClientYamlTestSuiteIT(@Name("yaml") ClientYamlTestCandidate testCandidate) {
super(testCandidate);
}
@ParametersFactory
public static Iterable<Object[]> parameters() throws Exception {
return createParameters();
}
}

View File

@ -16,7 +16,7 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket;
package org.elasticsearch.join.aggregations;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.index.IndexRequestBuilder;
@ -26,27 +26,33 @@ import org.elasticsearch.client.Requests;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.bucket.children.Children;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.elasticsearch.search.aggregations.metrics.sum.Sum;
import org.elasticsearch.search.aggregations.metrics.tophits.TopHits;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import org.junit.Before;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.search.aggregations.AggregationBuilders.children;
import static org.elasticsearch.join.aggregations.JoinAggregationBuilders.children;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery;
import static org.elasticsearch.search.aggregations.AggregationBuilders.sum;
import static org.elasticsearch.search.aggregations.AggregationBuilders.terms;
import static org.elasticsearch.search.aggregations.AggregationBuilders.topHits;
@ -59,13 +65,28 @@ import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.sameInstance;
@ESIntegTestCase.SuiteScopeTestCase
@ClusterScope(scope = Scope.SUITE)
public class ChildrenIT extends ESIntegTestCase {
private static final Map<String, Control> categoryToControl = new HashMap<>();
@Override
public void setupSuiteScopeCluster() throws Exception {
protected boolean ignoreExternalCluster() {
return true;
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singleton(ParentJoinPlugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return nodePlugins();
}
@Before
public void setupCluster() throws Exception {
categoryToControl.clear();
assertAcked(
prepareCreate("test")
.setSettings("index.mapping.single_type", false)
@ -95,7 +116,8 @@ public class ChildrenIT extends ESIntegTestCase {
control.articleIds.add(id);
}
requests.add(client().prepareIndex("test", "article", id).setCreate(true).setSource("category", categories, "randomized", true));
requests.add(client()
.prepareIndex("test", "article", id).setCreate(true).setSource("category", categories, "randomized", true));
}
String[] commenters = new String[randomIntBetween(5, 50)];
@ -116,17 +138,24 @@ public class ChildrenIT extends ESIntegTestCase {
control.commenterToCommentId.put(commenter, ids = new HashSet<>());
}
ids.add(idValue);
requests.add(client().prepareIndex("test", "comment", idValue).setCreate(true).setParent(articleId).setSource("commenter", commenter));
requests.add(client().prepareIndex("test", "comment", idValue)
.setCreate(true).setParent(articleId).setSource("commenter", commenter));
}
}
}
requests.add(client().prepareIndex("test", "article", "a").setSource("category", new String[]{"a"}, "randomized", false));
requests.add(client().prepareIndex("test", "article", "b").setSource("category", new String[]{"a", "b"}, "randomized", false));
requests.add(client().prepareIndex("test", "article", "c").setSource("category", new String[]{"a", "b", "c"}, "randomized", false));
requests.add(client().prepareIndex("test", "article", "d").setSource("category", new String[]{"c"}, "randomized", false));
requests.add(client().prepareIndex("test", "comment", "a").setParent("a").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("test", "comment", "c").setParent("c").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("test", "article", "a")
.setSource("category", new String[]{"a"}, "randomized", false));
requests.add(client().prepareIndex("test", "article", "b")
.setSource("category", new String[]{"a", "b"}, "randomized", false));
requests.add(client().prepareIndex("test", "article", "c")
.setSource("category", new String[]{"a", "b", "c"}, "randomized", false));
requests.add(client().prepareIndex("test", "article", "d")
.setSource("category", new String[]{"c"}, "randomized", false));
requests.add(client().prepareIndex("test", "comment", "a")
.setParent("a").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("test", "comment", "c")
.setParent("c").setSource("{}", XContentType.JSON));
indexRandom(true, requests);
ensureSearchable("test");
@ -155,7 +184,8 @@ public class ChildrenIT extends ESIntegTestCase {
Children childrenBucket = categoryBucket.getAggregations().get("to_comment");
assertThat(childrenBucket.getName(), equalTo("to_comment"));
assertThat(childrenBucket.getDocCount(), equalTo((long) entry1.getValue().commentIds.size()));
assertThat((long) ((InternalAggregation)childrenBucket).getProperty("_count"), equalTo((long) entry1.getValue().commentIds.size()));
assertThat((long) ((InternalAggregation)childrenBucket).getProperty("_count"),
equalTo((long) entry1.getValue().commentIds.size()));
Terms commentersTerms = childrenBucket.getAggregations().get("commenters");
assertThat((Terms) ((InternalAggregation)childrenBucket).getProperty("commenters"), sameInstance(commentersTerms));
@ -283,7 +313,7 @@ public class ChildrenIT extends ESIntegTestCase {
public void testNonExistingChildType() throws Exception {
SearchResponse searchResponse = client().prepareSearch("test")
.addAggregation(
children("non-existing", "xyz")
children("non-existing", "xyz")
).get();
assertSearchResponse(searchResponse);
@ -304,7 +334,8 @@ children("non-existing", "xyz")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex(indexName, masterType, "1").setSource("brand", "Levis", "name", "Style 501", "material", "Denim"));
requests.add(client().prepareIndex(indexName, masterType, "1")
.setSource("brand", "Levis", "name", "Style 501", "material", "Denim"));
requests.add(client().prepareIndex(indexName, childType, "0").setParent("1").setSource("color", "blue", "size", "32"));
requests.add(client().prepareIndex(indexName, childType, "1").setParent("1").setSource("color", "blue", "size", "34"));
requests.add(client().prepareIndex(indexName, childType, "2").setParent("1").setSource("color", "blue", "size", "36"));
@ -312,7 +343,8 @@ children("non-existing", "xyz")
requests.add(client().prepareIndex(indexName, childType, "4").setParent("1").setSource("color", "black", "size", "40"));
requests.add(client().prepareIndex(indexName, childType, "5").setParent("1").setSource("color", "gray", "size", "36"));
requests.add(client().prepareIndex(indexName, masterType, "2").setSource("brand", "Wrangler", "name", "Regular Cut", "material", "Leather"));
requests.add(client().prepareIndex(indexName, masterType, "2")
.setSource("brand", "Wrangler", "name", "Regular Cut", "material", "Leather"));
requests.add(client().prepareIndex(indexName, childType, "6").setParent("2").setSource("color", "blue", "size", "32"));
requests.add(client().prepareIndex(indexName, childType, "7").setParent("2").setSource("color", "blue", "size", "34"));
requests.add(client().prepareIndex(indexName, childType, "8").setParent("2").setSource("color", "black", "size", "36"));
@ -425,7 +457,7 @@ children("non-existing", "xyz")
.setSize(0)
.addAggregation(AggregationBuilders.terms("towns").field("town")
.subAggregation(AggregationBuilders.terms("parent_names").field("name")
.subAggregation(AggregationBuilders.children("child_docs", "childType"))
.subAggregation(children("child_docs", "childType"))
)
)
.get();
@ -468,5 +500,4 @@ children("non-existing", "xyz")
this.category = category;
}
}
}

View File

@ -17,13 +17,22 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket;
package org.elasticsearch.join.aggregations;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.aggregations.BaseAggregationTestCase;
import org.elasticsearch.search.aggregations.bucket.children.ChildrenAggregationBuilder;
import java.util.Collection;
import java.util.Collections;
public class ChildrenTests extends BaseAggregationTestCase<ChildrenAggregationBuilder> {
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return Collections.singleton(ParentJoinPlugin.class);
}
@Override
protected ChildrenAggregationBuilder createTestAggregatorBuilder() {
String name = randomAlphaOfLengthBetween(3, 20);

View File

@ -17,11 +17,11 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.children;
package org.elasticsearch.join.aggregations;
import org.elasticsearch.common.io.stream.Writeable.Reader;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.InternalSingleBucketAggregationTestCase;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;
import java.util.List;

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket.children;
package org.elasticsearch.join.aggregations;
import org.apache.lucene.document.Field;
import org.apache.lucene.document.SortedDocValuesField;

View File

@ -16,17 +16,20 @@
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.search.child;
package org.elasticsearch.join.query;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.explain.ExplainResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchPhaseExecutionException;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.action.support.WriteRequest.RefreshPolicy;
import org.elasticsearch.common.bytes.BytesArray;
import org.elasticsearch.common.lucene.search.function.CombineFunction;
import org.elasticsearch.common.lucene.search.function.FiltersFunctionScoreQuery;
import org.elasticsearch.common.settings.Settings;
@ -34,8 +37,6 @@ import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.IndexModule;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import org.elasticsearch.index.query.HasParentQueryBuilder;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
@ -43,6 +44,8 @@ import org.elasticsearch.index.query.MatchQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.AggregationBuilders;
@ -62,6 +65,8 @@ import org.hamcrest.Matchers;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
@ -72,8 +77,6 @@ import java.util.Set;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasChildQuery;
import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery;
import static org.elasticsearch.index.query.QueryBuilders.idsQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
@ -83,6 +86,8 @@ import static org.elasticsearch.index.query.QueryBuilders.prefixQuery;
import static org.elasticsearch.index.query.QueryBuilders.queryStringQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.index.query.QueryBuilders.termsQuery;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery;
import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.fieldValueFactorFunction;
import static org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders.weightFactorFunction;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
@ -100,6 +105,21 @@ import static org.hamcrest.Matchers.notNullValue;
@ClusterScope(scope = Scope.SUITE)
public class ChildQuerySearchIT extends ESIntegTestCase {
@Override
protected boolean ignoreExternalCluster() {
return true;
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Collections.singleton(ParentJoinPlugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return nodePlugins();
}
@Override
public Settings indexSettings() {
@ -145,26 +165,30 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("p1"));
searchResponse = client().prepareSearch("test")
.setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("parent", termQuery("p_field", "p_value1"), false))).execute()
.setQuery(boolQuery().must(matchAllQuery())
.filter(hasParentQuery("parent", termQuery("p_field", "p_value1"), false))).execute()
.actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c1"));
searchResponse = client().prepareSearch("test")
.setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("child", termQuery("c_field", "c_value1"), false))).execute()
.setQuery(boolQuery().must(matchAllQuery())
.filter(hasParentQuery("child", termQuery("c_field", "c_value1"), false))).execute()
.actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("gc1"));
searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", termQuery("p_field", "p_value1"), false)).execute()
searchResponse = client().prepareSearch("test")
.setQuery(hasParentQuery("parent", termQuery("p_field", "p_value1"), false)).execute()
.actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
assertThat(searchResponse.getHits().getAt(0).getId(), equalTo("c1"));
searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("child", termQuery("c_field", "c_value1"), false)).execute()
searchResponse = client().prepareSearch("test")
.setQuery(hasParentQuery("child", termQuery("c_field", "c_value1"), false)).execute()
.actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
@ -209,7 +233,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
refresh();
// TEST FETCHING _parent from child
SearchResponse searchResponse = client().prepareSearch("test").setQuery(idsQuery("child").addIds("c1")).storedFields("_parent").execute()
SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(idsQuery("child").addIds("c1")).storedFields("_parent").execute()
.actionGet();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
@ -284,7 +309,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
builders.add(client().prepareIndex("test", "child", Integer.toString(i)).setSource("c_field", i).setParent("" + 0));
}
for (int i = 0; i < 10; i++) {
builders.add(client().prepareIndex("test", "child", Integer.toString(i + 10)).setSource("c_field", i + 10).setParent(Integer.toString(i)));
builders.add(client().prepareIndex("test", "child", Integer.toString(i + 10))
.setSource("c_field", i + 10).setParent(Integer.toString(i)));
}
if (randomBoolean()) {
@ -445,9 +471,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
SearchResponse searchResponse = client()
.prepareSearch("test")
.setQuery(hasChildQuery("child", boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow")), ScoreMode.None))
.setQuery(hasChildQuery("child",
boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow")), ScoreMode.None))
.addAggregation(AggregationBuilders.global("global").subAggregation(
AggregationBuilders.filter("filter", boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow"))).subAggregation(
AggregationBuilders.filter("filter",
boolQuery().should(termQuery("c_field", "red")).should(termQuery("c_field", "yellow"))).subAggregation(
AggregationBuilders.terms("facet1").field("c_field")))).get();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L));
@ -523,7 +551,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
assertNoFailures(searchResponse);
searchResponse = client().prepareSearch("test").setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
.setQuery(boolQuery().mustNot(hasParentQuery("parent", boolQuery().should(queryStringQuery("p_field:*")), false))).execute()
.setQuery(boolQuery().mustNot(hasParentQuery("parent",
boolQuery().should(queryStringQuery("p_field:*")), false))).execute()
.actionGet();
assertNoFailures(searchResponse);
}
@ -570,7 +599,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
.get();
assertHitCount(countResponse, 1L);
countResponse = client().prepareSearch("test").setSize(0).setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true))
countResponse = client().prepareSearch("test").setSize(0)
.setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true))
.get();
assertHitCount(countResponse, 1L);
@ -579,7 +609,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
.get();
assertHitCount(countResponse, 1L);
countResponse = client().prepareSearch("test").setSize(0).setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1"), false)))
countResponse = client().prepareSearch("test").setSize(0)
.setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1"), false)))
.get();
assertHitCount(countResponse, 1L);
}
@ -685,11 +716,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
SearchResponse response = client()
.prepareSearch("test")
.setQuery(
QueryBuilders.hasChildQuery(
"child",
QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
fieldValueFactorFunction("c_field1"))
.boostMode(CombineFunction.REPLACE), ScoreMode.Total)).get();
hasChildQuery(
"child",
QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
fieldValueFactorFunction("c_field1"))
.boostMode(CombineFunction.REPLACE), ScoreMode.Total)).get();
assertThat(response.getHits().getTotalHits(), equalTo(3L));
assertThat(response.getHits().getHits()[0].getId(), equalTo("1"));
@ -702,11 +733,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
response = client()
.prepareSearch("test")
.setQuery(
QueryBuilders.hasChildQuery(
"child",
QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
fieldValueFactorFunction("c_field1"))
.boostMode(CombineFunction.REPLACE), ScoreMode.Max)).get();
hasChildQuery(
"child",
QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
fieldValueFactorFunction("c_field1"))
.boostMode(CombineFunction.REPLACE), ScoreMode.Max)).get();
assertThat(response.getHits().getTotalHits(), equalTo(3L));
assertThat(response.getHits().getHits()[0].getId(), equalTo("3"));
@ -719,11 +750,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
response = client()
.prepareSearch("test")
.setQuery(
QueryBuilders.hasChildQuery(
"child",
QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
fieldValueFactorFunction("c_field1"))
.boostMode(CombineFunction.REPLACE), ScoreMode.Avg)).get();
hasChildQuery(
"child",
QueryBuilders.functionScoreQuery(matchQuery("c_field2", 0),
fieldValueFactorFunction("c_field1"))
.boostMode(CombineFunction.REPLACE), ScoreMode.Avg)).get();
assertThat(response.getHits().getTotalHits(), equalTo(3L));
assertThat(response.getHits().getHits()[0].getId(), equalTo("3"));
@ -736,11 +767,11 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
response = client()
.prepareSearch("test")
.setQuery(
QueryBuilders.hasParentQuery(
"parent",
QueryBuilders.functionScoreQuery(matchQuery("p_field1", "p_value3"),
fieldValueFactorFunction("p_field2"))
.boostMode(CombineFunction.REPLACE), true))
hasParentQuery(
"parent",
QueryBuilders.functionScoreQuery(matchQuery("p_field1", "p_value3"),
fieldValueFactorFunction("p_field2"))
.boostMode(CombineFunction.REPLACE), true))
.addSort(SortBuilders.fieldSort("c_field3")).addSort(SortBuilders.scoreSort()).get();
assertThat(response.getHits().getTotalHits(), equalTo(7L));
@ -769,7 +800,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
ensureGreen();
SearchResponse response = client().prepareSearch("test")
.setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get();
.setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get();
assertNoFailures(response);
assertThat(response.getHits().getTotalHits(), equalTo(0L));
@ -777,20 +808,21 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
.setRefreshPolicy(RefreshPolicy.IMMEDIATE).get();
response = client().prepareSearch("test")
.setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get();
.setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.None)).get();
assertNoFailures(response);
assertThat(response.getHits().getTotalHits(), equalTo(0L));
response = client().prepareSearch("test").setQuery(QueryBuilders.hasChildQuery("child", matchQuery("text", "value"), ScoreMode.Max))
response = client().prepareSearch("test").setQuery(hasChildQuery("child", matchQuery("text", "value"), ScoreMode.Max))
.get();
assertNoFailures(response);
assertThat(response.getHits().getTotalHits(), equalTo(0L));
response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("parent", matchQuery("text", "value"), false)).get();
response = client().prepareSearch("test")
.setQuery(hasParentQuery("parent", matchQuery("text", "value"), false)).get();
assertNoFailures(response);
assertThat(response.getHits().getTotalHits(), equalTo(0L));
response = client().prepareSearch("test").setQuery(QueryBuilders.hasParentQuery("parent", matchQuery("text", "value"), true))
response = client().prepareSearch("test").setQuery(hasParentQuery("parent", matchQuery("text", "value"), true))
.get();
assertNoFailures(response);
assertThat(response.getHits().getTotalHits(), equalTo(0L));
@ -818,7 +850,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("1"));
searchResponse = client().prepareSearch("test")
.setQuery(boolQuery().must(matchAllQuery()).filter(hasParentQuery("parent", termQuery("p_field", 1), false))).get();
.setQuery(boolQuery().must(matchAllQuery())
.filter(hasParentQuery("parent", termQuery("p_field", 1), false))).get();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
assertThat(searchResponse.getHits().getHits()[0].getId(), equalTo("2"));
@ -873,12 +906,14 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
assertSearchHit(searchResponse, 1, hasId("2"));
searchResponse = client().prepareSearch("test")
.setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery().must(hasChildQuery("child", matchQuery("c_field", 1), ScoreMode.None))))
.setQuery(boolQuery().must(matchAllQuery())
.filter(boolQuery().must(hasChildQuery("child", matchQuery("c_field", 1), ScoreMode.None))))
.get();
assertSearchHit(searchResponse, 1, hasId("1"));
searchResponse = client().prepareSearch("test")
.setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery().must(hasParentQuery("parent", matchQuery("p_field", 1), false)))).get();
.setQuery(boolQuery().must(matchAllQuery())
.filter(boolQuery().must(hasParentQuery("parent", matchQuery("p_field", 1), false)))).get();
assertSearchHit(searchResponse, 1, hasId("2"));
}
@ -974,7 +1009,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
client().admin().indices().prepareRefresh("test").get();
}
searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.Total))
searchResponse = client().prepareSearch("test")
.setQuery(hasChildQuery("child", termQuery("c_field", "yellow"), ScoreMode.Total))
.get();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
@ -1009,7 +1045,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
client().prepareIndex("test", "child", "c5").setSource("c_field", "x").setParent("p2").get();
refresh();
SearchResponse searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.Total))
SearchResponse searchResponse = client()
.prepareSearch("test").setQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.Total))
.setMinScore(3) // Score needs to be 3 or above!
.get();
assertNoFailures(searchResponse);
@ -1219,7 +1256,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
createIndex("test");
ensureGreen();
PutMappingResponse putMappingResponse = client().admin().indices().preparePutMapping("test").setType("child").setSource("number", "type=integer")
PutMappingResponse putMappingResponse = client().admin().indices()
.preparePutMapping("test").setType("child").setSource("number", "type=integer")
.get();
assertThat(putMappingResponse.isAcknowledged(), equalTo(true));
@ -1269,13 +1307,15 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
ScoreMode scoreMode = randomFrom(ScoreMode.values());
SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "blue"), scoreMode)).filter(boolQuery().mustNot(termQuery("p_field", "3"))))
.setQuery(boolQuery().must(hasChildQuery("child", termQuery("c_field", "blue"), scoreMode))
.filter(boolQuery().mustNot(termQuery("p_field", "3"))))
.get();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(1L));
searchResponse = client().prepareSearch("test")
.setQuery(boolQuery().must(QueryBuilders.hasChildQuery("child", termQuery("c_field", "red"), scoreMode)).filter(boolQuery().mustNot(termQuery("p_field", "3"))))
.setQuery(boolQuery().must(hasChildQuery("child", termQuery("c_field", "red"), scoreMode))
.filter(boolQuery().mustNot(termQuery("p_field", "3"))))
.get();
assertNoFailures(searchResponse);
assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L));
@ -1293,25 +1333,29 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
client().prepareIndex("test", "child", "c1").setSource("c_field", "1").setParent(parentId).get();
refresh();
SearchResponse searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.Max).queryName("test"))
SearchResponse searchResponse = client().prepareSearch("test").setQuery(hasChildQuery("child",
termQuery("c_field", "1"), ScoreMode.Max).queryName("test"))
.get();
assertHitCount(searchResponse, 1L);
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("test"));
searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent", termQuery("p_field", "1"), true).queryName("test"))
searchResponse = client().prepareSearch("test").setQuery(hasParentQuery("parent",
termQuery("p_field", "1"), true).queryName("test"))
.get();
assertHitCount(searchResponse, 1L);
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("test"));
searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasChildQuery("child", termQuery("c_field", "1"), ScoreMode.None).queryName("test")))
searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasChildQuery("child",
termQuery("c_field", "1"), ScoreMode.None).queryName("test")))
.get();
assertHitCount(searchResponse, 1L);
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries()[0], equalTo("test"));
searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasParentQuery("parent", termQuery("p_field", "1"), false).queryName("test")))
searchResponse = client().prepareSearch("test").setQuery(constantScoreQuery(hasParentQuery("parent",
termQuery("p_field", "1"), false).queryName("test")))
.get();
assertHitCount(searchResponse, 1L);
assertThat(searchResponse.getHits().getAt(0).getMatchedQueries().length, equalTo(1));
@ -1400,7 +1444,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
for (int i = 0; i < 2; i++) {
SearchResponse searchResponse = client().prepareSearch()
.setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery()
.must(QueryBuilders.hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None))
.must(hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None))
.must(matchAllQuery())))
.get();
assertThat(searchResponse.getHits().getTotalHits(), equalTo(2L));
@ -1412,7 +1456,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
SearchResponse searchResponse = client().prepareSearch()
.setQuery(boolQuery().must(matchAllQuery()).filter(boolQuery()
.must(QueryBuilders.hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None))
.must(hasChildQuery("child", matchQuery("c_field", "red"), ScoreMode.None))
.must(matchAllQuery())))
.get();
@ -1478,7 +1522,8 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
SearchResponse resp;
resp = client().prepareSearch("test")
.setSource(new SearchSourceBuilder().query(QueryBuilders.hasChildQuery("posts", QueryBuilders.matchQuery("field", "bar"), ScoreMode.None)))
.setSource(new SearchSourceBuilder().query(hasChildQuery("posts",
QueryBuilders.matchQuery("field", "bar"), ScoreMode.None)))
.get();
assertHitCount(resp, 1L);
}
@ -1580,8 +1625,10 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
QueryBuilders.functionScoreQuery(constantScoreQuery(QueryBuilders.termQuery("foo", "two")),
new FunctionScoreQueryBuilder.FilterFunctionBuilder[]{
new FunctionScoreQueryBuilder.FilterFunctionBuilder(weightFactorFunction(1)),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "three"), weightFactorFunction(1)),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "four"), weightFactorFunction(1))
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "three"),
weightFactorFunction(1)),
new FunctionScoreQueryBuilder.FilterFunctionBuilder(QueryBuilders.termQuery("foo", "four"),
weightFactorFunction(1))
}).boostMode(CombineFunction.REPLACE).scoreMode(FiltersFunctionScoreQuery.ScoreMode.SUM), scoreMode)
.minMaxChildren(minChildren, maxChildren != null ? maxChildren : HasChildQueryBuilder.DEFAULT_MAX_CHILDREN);
@ -1916,7 +1963,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
try {
client().prepareSearch("test")
.setQuery(QueryBuilders.hasChildQuery("child", matchAllQuery(), ScoreMode.None))
.setQuery(hasChildQuery("child", matchAllQuery(), ScoreMode.None))
.get();
fail();
} catch (SearchPhaseExecutionException e) {
@ -1932,7 +1979,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
refresh();
//make sure that when we explicitly set a type, the inner query is executed in the context of the parent type instead
SearchResponse searchResponse = client().prepareSearch("test").setTypes("child-type").setQuery(
QueryBuilders.hasParentQuery("parent-type", new IdsQueryBuilder().addIds("parent-id"), false)).get();
hasParentQuery("parent-type", new IdsQueryBuilder().addIds("parent-id"), false)).get();
assertSearchHits(searchResponse, "child-id");
}
@ -1945,7 +1992,7 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
refresh();
//make sure that when we explicitly set a type, the inner query is executed in the context of the child type instead
SearchResponse searchResponse = client().prepareSearch("test").setTypes("parent-type").setQuery(
QueryBuilders.hasChildQuery("child-type", new IdsQueryBuilder().addIds("child-id"), ScoreMode.None)).get();
hasChildQuery("child-type", new IdsQueryBuilder().addIds("child-id"), ScoreMode.None)).get();
assertSearchHits(searchResponse, "parent-id");
}
@ -1955,8 +2002,10 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
.addMapping("parent-type", "searchText", "type=text,term_vector=with_positions_offsets,index_options=offsets")
.addMapping("child-type", "_parent", "type=parent-type", "searchText",
"type=text,term_vector=with_positions_offsets,index_options=offsets"));
client().prepareIndex("test", "parent-type", "parent-id").setSource("searchText", "quick brown fox").get();
client().prepareIndex("test", "child-type", "child-id").setParent("parent-id").setSource("searchText", "quick brown fox").get();
client().prepareIndex("test", "parent-type", "parent-id")
.setSource("searchText", "quick brown fox").get();
client().prepareIndex("test", "child-type", "child-id")
.setParent("parent-id").setSource("searchText", "quick brown fox").get();
refresh();
String[] highlightTypes = new String[] {"plain", "fvh", "postings"};
@ -1988,4 +2037,177 @@ public class ChildQuerySearchIT extends ESIntegTestCase {
}
}
public void testAliasesFilterWithHasChildQuery() throws Exception {
assertAcked(prepareCreate("my-index")
.setSettings("index.mapping.single_type", false)
.addMapping("parent")
.addMapping("child", "_parent", "type=parent")
);
client().prepareIndex("my-index", "parent", "1").setSource("{}", XContentType.JSON).get();
client().prepareIndex("my-index", "child", "2").setSource("{}", XContentType.JSON).setParent("1").get();
refresh();
assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter1",
hasChildQuery("child", matchAllQuery(), ScoreMode.None)));
assertAcked(admin().indices().prepareAliases().addAlias("my-index", "filter2",
hasParentQuery("parent", matchAllQuery(), false)));
SearchResponse response = client().prepareSearch("filter1").get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
response = client().prepareSearch("filter2").get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("2"));
}
/*
Test for https://github.com/elastic/elasticsearch/issues/3444
*/
public void testBulkUpdateDocAsUpsertWithParent() throws Exception {
client().admin().indices().prepareCreate("test")
.setSettings("index.mapping.single_type", false)
.addMapping("parent", "{\"parent\":{}}", XContentType.JSON)
.addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON)
.execute().actionGet();
ensureGreen();
BulkRequestBuilder builder = client().prepareBulk();
// It's important to use JSON parsing here and request objects: issue 3444 is related to incomplete option parsing
byte[] addParent = new BytesArray(
"{" +
" \"index\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"parent\"," +
" \"_id\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"field1\" : \"value1\"" +
"}" +
"\n").array();
byte[] addChild = new BytesArray(
"{" +
" \"update\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"child\"," +
" \"_id\" : \"child1\"," +
" \"parent\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"doc\" : {" +
" \"field1\" : \"value1\"" +
" }," +
" \"doc_as_upsert\" : \"true\"" +
"}" +
"\n").array();
builder.add(addParent, 0, addParent.length, XContentType.JSON);
builder.add(addChild, 0, addChild.length, XContentType.JSON);
BulkResponse bulkResponse = builder.get();
assertThat(bulkResponse.getItems().length, equalTo(2));
assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false));
assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false));
client().admin().indices().prepareRefresh("test").get();
//we check that the _parent field was set on the child document by using the has parent query
SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(hasParentQuery("parent", QueryBuilders.matchAllQuery(), false))
.get();
assertNoFailures(searchResponse);
assertSearchHits(searchResponse, "child1");
}
/*
Test for https://github.com/elastic/elasticsearch/issues/3444
*/
public void testBulkUpdateUpsertWithParent() throws Exception {
assertAcked(prepareCreate("test")
.setSettings("index.mapping.single_type", false)
.addMapping("parent", "{\"parent\":{}}", XContentType.JSON)
.addMapping("child", "{\"child\": {\"_parent\": {\"type\": \"parent\"}}}", XContentType.JSON));
ensureGreen();
BulkRequestBuilder builder = client().prepareBulk();
byte[] addParent = new BytesArray(
"{" +
" \"index\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"parent\"," +
" \"_id\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"field1\" : \"value1\"" +
"}" +
"\n").array();
byte[] addChild1 = new BytesArray(
"{" +
" \"update\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"child\"," +
" \"_id\" : \"child1\"," +
" \"parent\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"script\" : {" +
" \"inline\" : \"ctx._source.field2 = 'value2'\"" +
" }," +
" \"lang\" : \"" + InnerHitsIT.CustomScriptPlugin.NAME + "\"," +
" \"upsert\" : {" +
" \"field1\" : \"value1'\"" +
" }" +
"}" +
"\n").array();
byte[] addChild2 = new BytesArray(
"{" +
" \"update\" : {" +
" \"_index\" : \"test\"," +
" \"_type\" : \"child\"," +
" \"_id\" : \"child1\"," +
" \"parent\" : \"parent1\"" +
" }" +
"}" +
"\n" +
"{" +
" \"script\" : \"ctx._source.field2 = 'value2'\"," +
" \"upsert\" : {" +
" \"field1\" : \"value1'\"" +
" }" +
"}" +
"\n").array();
builder.add(addParent, 0, addParent.length, XContentType.JSON);
builder.add(addChild1, 0, addChild1.length, XContentType.JSON);
builder.add(addChild2, 0, addChild2.length, XContentType.JSON);
BulkResponse bulkResponse = builder.get();
assertThat(bulkResponse.getItems().length, equalTo(3));
assertThat(bulkResponse.getItems()[0].isFailed(), equalTo(false));
assertThat(bulkResponse.getItems()[1].isFailed(), equalTo(false));
assertThat(bulkResponse.getItems()[2].isFailed(), equalTo(true));
assertThat(bulkResponse.getItems()[2].getFailure().getCause().getCause().getMessage(),
equalTo("script_lang not supported [painless]"));
client().admin().indices().prepareRefresh("test").get();
SearchResponse searchResponse = client().prepareSearch("test")
.setQuery(hasParentQuery("parent", QueryBuilders.matchAllQuery(), false))
.get();
assertSearchHits(searchResponse, "child1");
}
}

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.index.query;
package org.elasticsearch.join.query;
import com.carrotsearch.randomizedtesting.generators.RandomPicks;
import org.apache.lucene.search.TermInSetQuery;
@ -40,7 +40,17 @@ import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.TypeFieldMapper;
import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.mapper.UidFieldMapper;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.WrapperQueryBuilder;
import org.elasticsearch.index.similarity.SimilarityService;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.fetch.subphase.InnerHitsContext;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.search.sort.FieldSortBuilder;
@ -48,10 +58,12 @@ import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.test.AbstractQueryTestCase;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
@ -65,6 +77,11 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
boolean requiresRewrite = false;
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return Collections.singletonList(ParentJoinPlugin.class);
}
@Override
protected void initializeAdditionalMappings(MapperService mapperService) throws IOException {
similarity = randomFrom("classic", "BM25");
@ -97,7 +114,7 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
int min = randomIntBetween(0, Integer.MAX_VALUE / 2);
int max = randomIntBetween(min, Integer.MAX_VALUE);
QueryBuilder innerQueryBuilder = RandomQueryBuilder.createQuery(random());
QueryBuilder innerQueryBuilder = new MatchAllQueryBuilder();
if (randomBoolean()) {
requiresRewrite = true;
innerQueryBuilder = new WrapperQueryBuilder(innerQueryBuilder.toString());
@ -144,19 +161,19 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
}
public void testIllegalValues() {
QueryBuilder query = RandomQueryBuilder.createQuery(random());
QueryBuilder query = new MatchAllQueryBuilder();
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> QueryBuilders.hasChildQuery(null, query, ScoreMode.None));
() -> hasChildQuery(null, query, ScoreMode.None));
assertEquals("[has_child] requires 'type' field", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> QueryBuilders.hasChildQuery("foo", null, ScoreMode.None));
e = expectThrows(IllegalArgumentException.class, () -> hasChildQuery("foo", null, ScoreMode.None));
assertEquals("[has_child] requires 'query' field", e.getMessage());
e = expectThrows(IllegalArgumentException.class, () -> QueryBuilders.hasChildQuery("foo", query, null));
e = expectThrows(IllegalArgumentException.class, () -> hasChildQuery("foo", query, null));
assertEquals("[has_child] requires 'score_mode' field", e.getMessage());
int positiveValue = randomIntBetween(0, Integer.MAX_VALUE);
HasChildQueryBuilder foo = QueryBuilders.hasChildQuery("foo", query, ScoreMode.None); // all good
HasChildQueryBuilder foo = hasChildQuery("foo", query, ScoreMode.None); // all good
e = expectThrows(IllegalArgumentException.class, () -> foo.minMaxChildren(randomIntBetween(Integer.MIN_VALUE, -1), positiveValue));
assertEquals("[has_child] requires non-negative 'min_children' field", e.getMessage());
@ -225,7 +242,7 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
String[] searchTypes = new String[]{PARENT_TYPE};
QueryShardContext shardContext = createShardContext();
shardContext.setTypes(searchTypes);
HasChildQueryBuilder hasChildQueryBuilder = QueryBuilders.hasChildQuery(CHILD_TYPE, new IdsQueryBuilder().addIds("id"), ScoreMode.None);
HasChildQueryBuilder hasChildQueryBuilder = hasChildQuery(CHILD_TYPE, new IdsQueryBuilder().addIds("id"), ScoreMode.None);
Query query = hasChildQueryBuilder.toQuery(shardContext);
//verify that the context types are still the same as the ones we previously set
assertThat(shardContext.getTypes(), equalTo(searchTypes));
@ -252,7 +269,8 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
assertThat(booleanTermsQuery.clauses().get(0).getQuery(), instanceOf(TermQuery.class));
TermQuery termQuery = (TermQuery) booleanTermsQuery.clauses().get(0).getQuery();
assertThat(termQuery.getTerm().field(), equalTo(UidFieldMapper.NAME));
//we want to make sure that the inner ids query gets executed against the child type rather than the main type we initially set to the context
//we want to make sure that the inner ids query gets executed against the child type rather
// than the main type we initially set to the context
BytesRef[] ids = Uid.createUidsForTypesAndIds(Collections.singletonList(type), Collections.singletonList(id));
assertThat(termQuery.getTerm().bytes(), equalTo(ids[0]));
//check the type filter
@ -273,7 +291,8 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
public void testNonDefaultSimilarity() throws Exception {
QueryShardContext shardContext = createShardContext();
HasChildQueryBuilder hasChildQueryBuilder = QueryBuilders.hasChildQuery(CHILD_TYPE, new TermQueryBuilder("custom_string", "value"), ScoreMode.None);
HasChildQueryBuilder hasChildQueryBuilder =
hasChildQuery(CHILD_TYPE, new TermQueryBuilder("custom_string", "value"), ScoreMode.None);
HasChildQueryBuilder.LateParsingQuery query = (HasChildQueryBuilder.LateParsingQuery) hasChildQueryBuilder.toQuery(shardContext);
Similarity expected = SimilarityService.BUILT_IN.get(similarity)
.apply(similarity, Settings.EMPTY, Settings.builder().put(IndexMetaData.SETTING_VERSION_CREATED, Version.CURRENT).build())
@ -281,48 +300,6 @@ public class HasChildQueryBuilderTests extends AbstractQueryTestCase<HasChildQue
assertThat(((PerFieldSimilarityWrapper) query.getSimilarity()).get("custom_string"), instanceOf(expected.getClass()));
}
public void testMinFromString() {
assertThat("fromString(min) != MIN", ScoreMode.Min, equalTo(HasChildQueryBuilder.parseScoreMode("min")));
assertThat("min", equalTo(HasChildQueryBuilder.scoreModeAsString(ScoreMode.Min)));
}
public void testMaxFromString() {
assertThat("fromString(max) != MAX", ScoreMode.Max, equalTo(HasChildQueryBuilder.parseScoreMode("max")));
assertThat("max", equalTo(HasChildQueryBuilder.scoreModeAsString(ScoreMode.Max)));
}
public void testAvgFromString() {
assertThat("fromString(avg) != AVG", ScoreMode.Avg, equalTo(HasChildQueryBuilder.parseScoreMode("avg")));
assertThat("avg", equalTo(HasChildQueryBuilder.scoreModeAsString(ScoreMode.Avg)));
}
public void testSumFromString() {
assertThat("fromString(total) != SUM", ScoreMode.Total, equalTo(HasChildQueryBuilder.parseScoreMode("sum")));
assertThat("sum", equalTo(HasChildQueryBuilder.scoreModeAsString(ScoreMode.Total)));
}
public void testNoneFromString() {
assertThat("fromString(none) != NONE", ScoreMode.None, equalTo(HasChildQueryBuilder.parseScoreMode("none")));
assertThat("none", equalTo(HasChildQueryBuilder.scoreModeAsString(ScoreMode.None)));
}
/**
* Should throw {@link IllegalArgumentException} instead of NPE.
*/
public void testThatNullFromStringThrowsException() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> HasChildQueryBuilder.parseScoreMode(null));
assertEquals("No score mode for child query [null] found", e.getMessage());
}
/**
* Failure should not change (and the value should never match anything...).
*/
public void testThatUnrecognizedFromStringThrowsException() {
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> HasChildQueryBuilder.parseScoreMode("unrecognized value"));
assertEquals("No score mode for child query [unrecognized value] found", e.getMessage());
}
public void testIgnoreUnmapped() throws IOException {
final HasChildQueryBuilder queryBuilder = new HasChildQueryBuilder("unmapped", new MatchAllQueryBuilder(), ScoreMode.None);
queryBuilder.ignoreUnmapped(true);

View File

@ -17,7 +17,7 @@
* under the License.
*/
package org.elasticsearch.index.query;
package org.elasticsearch.join.query;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
@ -28,6 +28,16 @@ import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.query.IdsQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryShardContext;
import org.elasticsearch.index.query.QueryShardException;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.WrapperQueryBuilder;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.search.fetch.subphase.InnerHitsContext;
import org.elasticsearch.search.internal.SearchContext;
import org.elasticsearch.search.sort.FieldSortBuilder;
@ -35,9 +45,12 @@ import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.test.AbstractQueryTestCase;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.instanceOf;
@ -49,6 +62,11 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase<HasParentQ
boolean requiresRewrite = false;
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return Collections.singletonList(ParentJoinPlugin.class);
}
@Override
protected void initializeAdditionalMappings(MapperService mapperService) throws IOException {
mapperService.merge(PARENT_TYPE, new CompressedXContent(PutMappingRequest.buildFromSimplifiedDef(PARENT_TYPE,
@ -79,7 +97,7 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase<HasParentQ
*/
@Override
protected HasParentQueryBuilder doCreateTestQueryBuilder() {
QueryBuilder innerQueryBuilder = RandomQueryBuilder.createQuery(random());
QueryBuilder innerQueryBuilder = new MatchAllQueryBuilder();
if (randomBoolean()) {
requiresRewrite = true;
innerQueryBuilder = new WrapperQueryBuilder(innerQueryBuilder.toString());
@ -124,17 +142,17 @@ public class HasParentQueryBuilderTests extends AbstractQueryTestCase<HasParentQ
}
public void testIllegalValues() throws IOException {
QueryBuilder query = RandomQueryBuilder.createQuery(random());
QueryBuilder query = new MatchAllQueryBuilder();
IllegalArgumentException e = expectThrows(IllegalArgumentException.class,
() -> QueryBuilders.hasParentQuery(null, query, false));
() -> hasParentQuery(null, query, false));
assertThat(e.getMessage(), equalTo("[has_parent] requires 'type' field"));
e = expectThrows(IllegalArgumentException.class,
() -> QueryBuilders.hasParentQuery("foo", null, false));
() -> hasParentQuery("foo", null, false));
assertThat(e.getMessage(), equalTo("[has_parent] requires 'query' field"));
QueryShardContext context = createShardContext();
HasParentQueryBuilder qb = QueryBuilders.hasParentQuery("just_a_type", new MatchAllQueryBuilder(), false);
HasParentQueryBuilder qb = hasParentQuery("just_a_type", new MatchAllQueryBuilder(), false);
QueryShardException qse = expectThrows(QueryShardException.class, () -> qb.doToQuery(context));
assertThat(qse.getMessage(), equalTo("[has_parent] no child types found for type [just_a_type]"));
}

View File

@ -0,0 +1,568 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.join.query;
import org.apache.lucene.search.join.ScoreMode;
import org.apache.lucene.util.ArrayUtil;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.InnerHitBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockScriptEngine;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
import org.elasticsearch.script.ScriptType;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ClusterScope;
import org.elasticsearch.test.ESIntegTestCase.Scope;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.function.Function;
import static org.elasticsearch.action.support.WriteRequest.RefreshPolicy.IMMEDIATE;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.query.QueryBuilders.boolQuery;
import static org.elasticsearch.index.query.QueryBuilders.constantScoreQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchQuery;
import static org.elasticsearch.index.query.QueryBuilders.nestedQuery;
import static org.elasticsearch.index.query.QueryBuilders.termQuery;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasChildQuery;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertHitCount;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertNoFailures;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHit;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.hasId;
import static org.hamcrest.Matchers.containsString;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.notNullValue;
import static org.hamcrest.Matchers.nullValue;
@ClusterScope(scope = Scope.SUITE)
public class InnerHitsIT extends ESIntegTestCase {
@Override
protected boolean ignoreExternalCluster() {
return true;
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
return Arrays.asList(ParentJoinPlugin.class, CustomScriptPlugin.class);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return nodePlugins();
}
public static class CustomScriptPlugin extends MockScriptPlugin {
@Override
protected Map<String, Function<Map<String, Object>, Object>> pluginScripts() {
return Collections.singletonMap("5", script -> "5");
}
}
public void testSimpleParentChild() throws Exception {
assertAcked(prepareCreate("articles")
.setSettings("index.mapping.single_type", false)
.addMapping("article", "title", "type=text")
.addMapping("comment", "_parent", "type=article", "message", "type=text,fielddata=true")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox"));
requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick"));
requests.add(client().prepareIndex("articles", "comment", "2").setParent("1").setSource("message", "fox ate rabbit x y z"));
requests.add(client().prepareIndex("articles", "comment", "3").setParent("1").setSource("message", "rabbit got away"));
requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant"));
requests.add(client().prepareIndex("articles", "comment", "4").setParent("2").setSource("message", "elephant captured"));
requests.add(client().prepareIndex("articles", "comment", "5").setParent("2").setSource("message", "mice squashed by elephant x"));
requests.add(client().prepareIndex("articles", "comment", "6").setParent("2").setSource("message", "elephant scared by mice x y"));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("1"));
assertThat(response.getHits().getAt(0).getShard(), notNullValue());
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(2L));
assertThat(innerHits.getAt(0).getId(), equalTo("1"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
assertThat(innerHits.getAt(1).getId(), equalTo("2"));
assertThat(innerHits.getAt(1).getType(), equalTo("comment"));
response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment", matchQuery("message", "elephant"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("2"));
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(3L));
assertThat(innerHits.getAt(0).getId(), equalTo("4"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
assertThat(innerHits.getAt(1).getId(), equalTo("5"));
assertThat(innerHits.getAt(1).getType(), equalTo("comment"));
assertThat(innerHits.getAt(2).getId(), equalTo("6"));
assertThat(innerHits.getAt(2).getType(), equalTo("comment"));
response = client().prepareSearch("articles")
.setQuery(
hasChildQuery("comment", matchQuery("message", "fox"), ScoreMode.None).innerHit(
new InnerHitBuilder()
.addDocValueField("message")
.setHighlightBuilder(new HighlightBuilder().field("message"))
.setExplain(true).setSize(1)
.addScriptField("script", new Script(ScriptType.INLINE, MockScriptEngine.NAME, "5",
Collections.emptyMap())),
false)
).get();
assertNoFailures(response);
innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getHits().length, equalTo(1));
assertThat(innerHits.getAt(0).getHighlightFields().get("message").getFragments()[0].string(), equalTo("<em>fox</em> eat quick"));
assertThat(innerHits.getAt(0).getExplanation().toString(), containsString("weight(message:fox"));
assertThat(innerHits.getAt(0).getFields().get("message").getValue().toString(), equalTo("eat"));
assertThat(innerHits.getAt(0).getFields().get("script").getValue().toString(), equalTo("5"));
}
public void testRandomParentChild() throws Exception {
assertAcked(prepareCreate("idx")
.setSettings("index.mapping.single_type", false)
.addMapping("parent")
.addMapping("child1", "_parent", "type=parent")
.addMapping("child2", "_parent", "type=parent")
);
int numDocs = scaledRandomIntBetween(5, 50);
List<IndexRequestBuilder> requestBuilders = new ArrayList<>();
int child1 = 0;
int child2 = 0;
int[] child1InnerObjects = new int[numDocs];
int[] child2InnerObjects = new int[numDocs];
for (int parent = 0; parent < numDocs; parent++) {
String parentId = String.format(Locale.ENGLISH, "%03d", parent);
requestBuilders.add(client().prepareIndex("idx", "parent", parentId).setSource("{}", XContentType.JSON));
int numChildDocs = child1InnerObjects[parent] = scaledRandomIntBetween(1, numDocs);
int limit = child1 + numChildDocs;
for (; child1 < limit; child1++) {
requestBuilders.add(client().prepareIndex("idx", "child1",
String.format(Locale.ENGLISH, "%04d", child1)).setParent(parentId).setSource("{}", XContentType.JSON));
}
numChildDocs = child2InnerObjects[parent] = scaledRandomIntBetween(1, numDocs);
limit = child2 + numChildDocs;
for (; child2 < limit; child2++) {
requestBuilders.add(client().prepareIndex("idx", "child2",
String.format(Locale.ENGLISH, "%04d", child2)).setParent(parentId).setSource("{}", XContentType.JSON));
}
}
indexRandom(true, requestBuilders);
int size = randomIntBetween(0, numDocs);
BoolQueryBuilder boolQuery = new BoolQueryBuilder();
boolQuery.should(constantScoreQuery(hasChildQuery("child1", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder().setName("a")
.addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false)));
boolQuery.should(constantScoreQuery(hasChildQuery("child2", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder().setName("b")
.addSort(new FieldSortBuilder("_uid").order(SortOrder.ASC)).setSize(size), false)));
SearchResponse searchResponse = client().prepareSearch("idx")
.setSize(numDocs)
.setTypes("parent")
.addSort("_uid", SortOrder.ASC)
.setQuery(boolQuery)
.get();
assertNoFailures(searchResponse);
assertHitCount(searchResponse, numDocs);
assertThat(searchResponse.getHits().getHits().length, equalTo(numDocs));
int offset1 = 0;
int offset2 = 0;
for (int parent = 0; parent < numDocs; parent++) {
SearchHit searchHit = searchResponse.getHits().getAt(parent);
assertThat(searchHit.getType(), equalTo("parent"));
assertThat(searchHit.getId(), equalTo(String.format(Locale.ENGLISH, "%03d", parent)));
assertThat(searchHit.getShard(), notNullValue());
SearchHits inner = searchHit.getInnerHits().get("a");
assertThat(inner.getTotalHits(), equalTo((long) child1InnerObjects[parent]));
for (int child = 0; child < child1InnerObjects[parent] && child < size; child++) {
SearchHit innerHit = inner.getAt(child);
assertThat(innerHit.getType(), equalTo("child1"));
String childId = String.format(Locale.ENGLISH, "%04d", offset1 + child);
assertThat(innerHit.getId(), equalTo(childId));
assertThat(innerHit.getNestedIdentity(), nullValue());
}
offset1 += child1InnerObjects[parent];
inner = searchHit.getInnerHits().get("b");
assertThat(inner.getTotalHits(), equalTo((long) child2InnerObjects[parent]));
for (int child = 0; child < child2InnerObjects[parent] && child < size; child++) {
SearchHit innerHit = inner.getAt(child);
assertThat(innerHit.getType(), equalTo("child2"));
String childId = String.format(Locale.ENGLISH, "%04d", offset2 + child);
assertThat(innerHit.getId(), equalTo(childId));
assertThat(innerHit.getNestedIdentity(), nullValue());
}
offset2 += child2InnerObjects[parent];
}
}
public void testInnerHitsOnHasParent() throws Exception {
assertAcked(prepareCreate("stack")
.setSettings("index.mapping.single_type", false)
.addMapping("question", "body", "type=text")
.addMapping("answer", "_parent", "type=question", "body", "type=text")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("stack", "question", "1").setSource("body", "I'm using HTTPS + Basic authentication "
+ "to protect a resource. How can I throttle authentication attempts to protect against brute force attacks?"));
requests.add(client().prepareIndex("stack", "answer", "1").setParent("1").setSource("body",
"install fail2ban and enable rules for apache"));
requests.add(client().prepareIndex("stack", "question", "2").setSource("body",
"I have firewall rules set up and also denyhosts installed.\\ndo I also need to install fail2ban?"));
requests.add(client().prepareIndex("stack", "answer", "2").setParent("2").setSource("body",
"Denyhosts protects only ssh; Fail2Ban protects all daemons."));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("stack")
.setTypes("answer")
.addSort("_uid", SortOrder.ASC)
.setQuery(
boolQuery()
.must(matchQuery("body", "fail2ban"))
.must(hasParentQuery("question", matchAllQuery(), false).innerHit(new InnerHitBuilder(), false))
).get();
assertNoFailures(response);
assertHitCount(response, 2);
SearchHit searchHit = response.getHits().getAt(0);
assertThat(searchHit.getId(), equalTo("1"));
assertThat(searchHit.getType(), equalTo("answer"));
assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question"));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("1"));
searchHit = response.getHits().getAt(1);
assertThat(searchHit.getId(), equalTo("2"));
assertThat(searchHit.getType(), equalTo("answer"));
assertThat(searchHit.getInnerHits().get("question").getTotalHits(), equalTo(1L));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getType(), equalTo("question"));
assertThat(searchHit.getInnerHits().get("question").getAt(0).getId(), equalTo("2"));
}
public void testParentChildMultipleLayers() throws Exception {
assertAcked(prepareCreate("articles")
.setSettings("index.mapping.single_type", false)
.addMapping("article", "title", "type=text")
.addMapping("comment", "_parent", "type=article", "message", "type=text")
.addMapping("remark", "_parent", "type=comment", "message", "type=text")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("articles", "article", "1").setSource("title", "quick brown fox"));
requests.add(client().prepareIndex("articles", "comment", "1").setParent("1").setSource("message", "fox eat quick"));
requests.add(client().prepareIndex("articles", "remark", "1").setParent("1").setRouting("1").setSource("message", "good"));
requests.add(client().prepareIndex("articles", "article", "2").setSource("title", "big gray elephant"));
requests.add(client().prepareIndex("articles", "comment", "2").setParent("2").setSource("message", "elephant captured"));
requests.add(client().prepareIndex("articles", "remark", "2").setParent("2").setRouting("2").setSource("message", "bad"));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment",
hasChildQuery("remark", matchQuery("message", "good"), ScoreMode.None).innerHit(new InnerHitBuilder(), false),
ScoreMode.None).innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("1"));
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("1"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
innerHits = innerHits.getAt(0).getInnerHits().get("remark");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("1"));
assertThat(innerHits.getAt(0).getType(), equalTo("remark"));
response = client().prepareSearch("articles")
.setQuery(hasChildQuery("comment",
hasChildQuery("remark", matchQuery("message", "bad"), ScoreMode.None).innerHit(new InnerHitBuilder(), false),
ScoreMode.None).innerHit(new InnerHitBuilder(), false))
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertSearchHit(response, 1, hasId("2"));
assertThat(response.getHits().getAt(0).getInnerHits().size(), equalTo(1));
innerHits = response.getHits().getAt(0).getInnerHits().get("comment");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("2"));
assertThat(innerHits.getAt(0).getType(), equalTo("comment"));
innerHits = innerHits.getAt(0).getInnerHits().get("remark");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("2"));
assertThat(innerHits.getAt(0).getType(), equalTo("remark"));
}
public void testRoyals() throws Exception {
assertAcked(
prepareCreate("royals")
.setSettings("index.mapping.single_type", false)
.addMapping("king")
.addMapping("prince", "_parent", "type=king")
.addMapping("duke", "_parent", "type=prince")
.addMapping("earl", "_parent", "type=duke")
.addMapping("baron", "_parent", "type=earl")
);
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("royals", "king", "king").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "prince", "prince").setParent("king").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "duke", "duke").setParent("prince").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl1").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl2").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl3").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "earl", "earl4").setParent("duke").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron1").setParent("earl1").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron2").setParent("earl2").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron3").setParent("earl3").setRouting("king")
.setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("royals", "baron", "baron4").setParent("earl4").setRouting("king")
.setSource("{}", XContentType.JSON));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("royals")
.setTypes("duke")
.setQuery(boolQuery()
.filter(hasParentQuery("prince",
hasParentQuery("king", matchAllQuery(), false).innerHit(new InnerHitBuilder().setName("kings"), false),
false).innerHit(new InnerHitBuilder().setName("princes"), false)
)
.filter(hasChildQuery("earl",
hasChildQuery("baron", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder().setName("barons"), false),
ScoreMode.None).innerHit(new InnerHitBuilder()
.addSort(SortBuilders.fieldSort("_uid").order(SortOrder.ASC))
.setName("earls")
.setSize(4), false)
)
)
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("duke"));
SearchHits innerHits = response.getHits().getAt(0).getInnerHits().get("earls");
assertThat(innerHits.getTotalHits(), equalTo(4L));
assertThat(innerHits.getAt(0).getId(), equalTo("earl1"));
assertThat(innerHits.getAt(1).getId(), equalTo("earl2"));
assertThat(innerHits.getAt(2).getId(), equalTo("earl3"));
assertThat(innerHits.getAt(3).getId(), equalTo("earl4"));
SearchHits innerInnerHits = innerHits.getAt(0).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron1"));
innerInnerHits = innerHits.getAt(1).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron2"));
innerInnerHits = innerHits.getAt(2).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron3"));
innerInnerHits = innerHits.getAt(3).getInnerHits().get("barons");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("baron4"));
innerHits = response.getHits().getAt(0).getInnerHits().get("princes");
assertThat(innerHits.getTotalHits(), equalTo(1L));
assertThat(innerHits.getAt(0).getId(), equalTo("prince"));
innerInnerHits = innerHits.getAt(0).getInnerHits().get("kings");
assertThat(innerInnerHits.getTotalHits(), equalTo(1L));
assertThat(innerInnerHits.getAt(0).getId(), equalTo("king"));
}
public void testMatchesQueriesParentChildInnerHits() throws Exception {
assertAcked(prepareCreate("index")
.setSettings("index.mapping.single_type", false)
.addMapping("child", "_parent", "type=parent"));
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("index", "parent", "1").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("index", "child", "1").setParent("1").setSource("field", "value1"));
requests.add(client().prepareIndex("index", "child", "2").setParent("1").setSource("field", "value2"));
requests.add(client().prepareIndex("index", "parent", "2").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("index", "child", "3").setParent("2").setSource("field", "value1"));
indexRandom(true, requests);
SearchResponse response = client().prepareSearch("index")
.setQuery(hasChildQuery("child", matchQuery("field", "value1").queryName("_name1"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false))
.addSort("_uid", SortOrder.ASC)
.get();
assertHitCount(response, 2);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1"));
assertThat(response.getHits().getAt(1).getId(), equalTo("2"));
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getTotalHits(), equalTo(1L));
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(response.getHits().getAt(1).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name1"));
QueryBuilder query = hasChildQuery("child", matchQuery("field", "value2").queryName("_name2"), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false);
response = client().prepareSearch("index")
.setQuery(query)
.addSort("_uid", SortOrder.ASC)
.get();
assertHitCount(response, 1);
assertThat(response.getHits().getAt(0).getId(), equalTo("1"));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getTotalHits(), equalTo(1L));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries().length, equalTo(1));
assertThat(response.getHits().getAt(0).getInnerHits().get("child").getAt(0).getMatchedQueries()[0], equalTo("_name2"));
}
public void testDontExplode() throws Exception {
assertAcked(prepareCreate("index1")
.setSettings("index.mapping.single_type", false)
.addMapping("child", "_parent", "type=parent"));
List<IndexRequestBuilder> requests = new ArrayList<>();
requests.add(client().prepareIndex("index1", "parent", "1").setSource("{}", XContentType.JSON));
requests.add(client().prepareIndex("index1", "child", "1").setParent("1").setSource("field", "value1"));
indexRandom(true, requests);
QueryBuilder query = hasChildQuery("child", matchQuery("field", "value1"), ScoreMode.None)
.innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false);
SearchResponse response = client().prepareSearch("index1")
.setQuery(query)
.get();
assertNoFailures(response);
assertHitCount(response, 1);
assertAcked(prepareCreate("index2").addMapping("type", "nested", "type=nested"));
client().prepareIndex("index2", "type", "1").setSource(jsonBuilder().startObject()
.startArray("nested")
.startObject()
.field("field", "value1")
.endObject()
.endArray()
.endObject())
.setRefreshPolicy(IMMEDIATE)
.get();
query = nestedQuery("nested", matchQuery("nested.field", "value1"), ScoreMode.Avg)
.innerHit(new InnerHitBuilder().setSize(ArrayUtil.MAX_ARRAY_LENGTH - 1), false);
response = client().prepareSearch("index2")
.setQuery(query)
.get();
assertNoFailures(response);
assertHitCount(response, 1);
}
public void testNestedInnerHitWrappedInParentChildInnerhit() throws Exception {
assertAcked(prepareCreate("test")
.setSettings("index.mapping.single_type", false)
.addMapping("child_type", "_parent", "type=parent_type", "nested_type", "type=nested"));
client().prepareIndex("test", "parent_type", "1").setSource("key", "value").get();
client().prepareIndex("test", "child_type", "2").setParent("1").setSource("nested_type", Collections.singletonMap("key", "value"))
.get();
refresh();
SearchResponse response = client().prepareSearch("test")
.setQuery(boolQuery().must(matchQuery("key", "value"))
.should(hasChildQuery("child_type", nestedQuery("nested_type", matchAllQuery(), ScoreMode.None)
.innerHit(new InnerHitBuilder(), false), ScoreMode.None).innerHit(new InnerHitBuilder(), false)))
.get();
assertHitCount(response, 1);
SearchHit hit = response.getHits().getAt(0);
assertThat(hit.getInnerHits().get("child_type").getAt(0).field("_parent").getValue(), equalTo("1"));
assertThat(hit.getInnerHits().get("child_type").getAt(0).getInnerHits().get("nested_type").getAt(0).field("_parent"), nullValue());
}
public void testInnerHitsWithIgnoreUnmapped() throws Exception {
assertAcked(prepareCreate("index1")
.setSettings("index.mapping.single_type", false)
.addMapping("parent_type", "nested_type", "type=nested")
.addMapping("child_type", "_parent", "type=parent_type")
);
createIndex("index2");
client().prepareIndex("index1", "parent_type", "1").setSource("nested_type", Collections.singletonMap("key", "value")).get();
client().prepareIndex("index1", "child_type", "2").setParent("1").setSource("{}", XContentType.JSON).get();
client().prepareIndex("index2", "type", "3").setSource("key", "value").get();
refresh();
SearchResponse response = client().prepareSearch("index1", "index2")
.setQuery(boolQuery()
.should(hasChildQuery("child_type", matchAllQuery(), ScoreMode.None).ignoreUnmapped(true)
.innerHit(new InnerHitBuilder(), true))
.should(termQuery("key", "value"))
)
.get();
assertNoFailures(response);
assertHitCount(response, 2);
assertSearchHits(response, "1", "3");
}
}

View File

@ -0,0 +1,48 @@
setup:
- do:
indices.create:
index: test
body:
settings:
mapping.single_type: false
mappings:
type_2: {}
type_3:
_parent:
type: type_2
---
"Parent/child inner hits":
- skip:
version: " - 5.99.99"
reason: mapping.single_type was added in 6.0
- do:
index:
index: test
type: type_2
id: 1
body: {"foo": "bar"}
- do:
index:
index: test
type: type_3
id: 1
parent: 1
body: {"bar": "baz"}
- do:
indices.refresh: {}
- do:
search:
body: { "query" : { "has_child" : { "type" : "type_3", "query" : { "match_all" : {} }, "inner_hits" : {} } } }
- match: { hits.total: 1 }
- match: { hits.hits.0._index: "test" }
- match: { hits.hits.0._type: "type_2" }
- match: { hits.hits.0._id: "1" }
- is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._index
- match: { hits.hits.0.inner_hits.type_3.hits.hits.0._type: "type_3" }
- match: { hits.hits.0.inner_hits.type_3.hits.hits.0._id: "1" }
- is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._nested

View File

@ -23,5 +23,9 @@ esplugin {
hasClientJar = true
}
dependencies {
// for testing hasChild and hasParent rejections
testCompile project(path: ':modules:parent-join', configuration: 'runtime')
}
compileJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes"
compileTestJava.options.compilerArgs << "-Xlint:-deprecation,-rawtypes"

View File

@ -57,8 +57,6 @@ import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostingQueryBuilder;
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
import org.elasticsearch.index.query.DisMaxQueryBuilder;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import org.elasticsearch.index.query.HasParentQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.query.QueryShardContext;
@ -372,15 +370,16 @@ public class PercolatorFieldMapper extends FieldMapper {
return CONTENT_TYPE;
}
/**
* Fails if a percolator contains an unsupported query. The following queries are not supported:
* 1) a has_child query
* 2) a has_parent query
*/
static void verifyQuery(QueryBuilder queryBuilder) {
if (queryBuilder instanceof HasChildQueryBuilder) {
if (queryBuilder.getName().equals("has_child")) {
throw new IllegalArgumentException("the [has_child] query is unsupported inside a percolator query");
} else if (queryBuilder instanceof HasParentQueryBuilder) {
} else if (queryBuilder.getName().equals("has_parent")) {
throw new IllegalArgumentException("the [has_parent] query is unsupported inside a percolator query");
} else if (queryBuilder instanceof BoolQueryBuilder) {
BoolQueryBuilder boolQueryBuilder = (BoolQueryBuilder) queryBuilder;

View File

@ -52,13 +52,10 @@ import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.ParseContext;
import org.elasticsearch.index.mapper.ParsedDocument;
import org.elasticsearch.index.mapper.SourceToParse;
import org.elasticsearch.index.mapper.MapperService.MergeReason;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostingQueryBuilder;
import org.elasticsearch.index.query.ConstantScoreQueryBuilder;
import org.elasticsearch.index.query.DisMaxQueryBuilder;
import org.elasticsearch.index.query.HasChildQueryBuilder;
import org.elasticsearch.index.query.HasParentQueryBuilder;
import org.elasticsearch.index.query.MatchAllQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryParseContext;
@ -67,6 +64,9 @@ import org.elasticsearch.index.query.RangeQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.RandomScoreFunctionBuilder;
import org.elasticsearch.indices.TermsLookup;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.join.query.HasChildQueryBuilder;
import org.elasticsearch.join.query.HasParentQueryBuilder;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.script.MockScriptPlugin;
import org.elasticsearch.script.Script;
@ -109,7 +109,7 @@ public class PercolatorFieldMapperTests extends ESSingleNodeTestCase {
@Override
protected Collection<Class<? extends Plugin>> getPlugins() {
return pluginList(InternalSettingsPlugin.class, PercolatorPlugin.class, FoolMeScriptPlugin.class);
return pluginList(InternalSettingsPlugin.class, PercolatorPlugin.class, FoolMeScriptPlugin.class, ParentJoinPlugin.class);
}
@Before

View File

@ -39,6 +39,8 @@ dependencies {
compile "org.elasticsearch.client:rest:${version}"
// for http - testing reindex from remote
testCompile project(path: ':modules:transport-netty4', configuration: 'runtime')
// for parent/child testing
testCompile project(path: ':modules:parent-join', configuration: 'runtime')
}
dependencyLicenses {

View File

@ -22,9 +22,16 @@ package org.elasticsearch.index.reindex;
import org.elasticsearch.action.admin.indices.create.CreateIndexRequestBuilder;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.join.ParentJoinPlugin;
import org.elasticsearch.plugins.Plugin;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.index.query.QueryBuilders.hasParentQuery;
import static org.elasticsearch.index.query.QueryBuilders.idsQuery;
import static org.elasticsearch.join.query.JoinQueryBuilders.hasParentQuery;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertAcked;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertSearchHits;
import static org.hamcrest.Matchers.containsString;
@ -40,6 +47,23 @@ public class ReindexParentChildTests extends ReindexTestCase {
QueryBuilder findsCity;
QueryBuilder findsNeighborhood;
@Override
protected boolean ignoreExternalCluster() {
return true;
}
@Override
protected Collection<Class<? extends Plugin>> nodePlugins() {
final List<Class<? extends Plugin>> plugins = new ArrayList<>(super.nodePlugins());
plugins.add(ParentJoinPlugin.class);
return Collections.unmodifiableList(plugins);
}
@Override
protected Collection<Class<? extends Plugin>> transportClientPlugins() {
return nodePlugins();
}
public void testParentChild() throws Exception {
createParentChildIndex("source");
createParentChildIndex("dest");

View File

@ -158,85 +158,6 @@
metric: search
- match: {indices.source.total.search.open_contexts: 0}
---
"Reindex from remote with parent/child":
- do:
indices.create:
index: source
body:
settings:
mapping.single_type: false
mappings:
foo: {}
bar:
_parent:
type: foo
- do:
indices.create:
index: dest
body:
settings:
mapping.single_type: false
mappings:
foo: {}
bar:
_parent:
type: foo
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
index:
index: source
type: bar
id: 1
parent: 1
body: { "text": "test2" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
index: source
dest:
index: dest
- match: {created: 2}
- do:
search:
index: dest
body:
query:
has_parent:
parent_type: foo
query:
match:
text: test
- match: {hits.total: 1}
# Make sure reindex closed all the scroll contexts
- do:
indices.stats:
index: source
metric: search
- match: {indices.source.total.search.open_contexts: 0}
---
"Reindex from remote with timeouts":

View File

@ -22,4 +22,6 @@ apply plugin: 'elasticsearch.rest-test'
integTestCluster {
setting 'script.max_compilations_per_minute', '1000'
}
// Whitelist reindexing from the local node so we can test it.
setting 'reindex.remote.whitelist', '127.0.0.1:*'
}

View File

@ -0,0 +1,79 @@
---
"Reindex from remote with parent/child":
- do:
indices.create:
index: source
body:
settings:
mapping.single_type: false
mappings:
foo: {}
bar:
_parent:
type: foo
- do:
indices.create:
index: dest
body:
settings:
mapping.single_type: false
mappings:
foo: {}
bar:
_parent:
type: foo
- do:
index:
index: source
type: foo
id: 1
body: { "text": "test" }
- do:
index:
index: source
type: bar
id: 1
parent: 1
body: { "text": "test2" }
- do:
indices.refresh: {}
# Fetch the http host. We use the host of the master because we know there will always be a master.
- do:
cluster.state: {}
- set: { master_node: master }
- do:
nodes.info:
metric: [ http ]
- is_true: nodes.$master.http.publish_address
- set: {nodes.$master.http.publish_address: host}
- do:
reindex:
refresh: true
body:
source:
remote:
host: http://${host}
index: source
dest:
index: dest
- match: {created: 2}
- do:
search:
index: dest
body:
query:
has_parent:
parent_type: foo
query:
match:
text: test
- match: {hits.total: 1}
# Make sure reindex closed all the scroll contexts
- do:
indices.stats:
index: source
metric: search
- match: {indices.source.total.search.open_contexts: 0}

View File

@ -11,10 +11,6 @@ setup:
properties:
nested_field:
type: nested
type_2: {}
type_3:
_parent:
type: type_2
---
"Nested inner hits":
@ -47,38 +43,3 @@ setup:
- match: { hits.hits.0.inner_hits.nested_field.hits.hits.0._nested.offset: 0 }
- is_false: hits.hits.0.inner_hits.nested_field.hits.hits.0._nested.child
---
"Parent/child inner hits":
- skip:
version: " - 5.99.99"
reason: mapping.single_type was added in 6.0
- do:
index:
index: test
type: type_2
id: 1
body: {"foo": "bar"}
- do:
index:
index: test
type: type_3
id: 1
parent: 1
body: {"bar": "baz"}
- do:
indices.refresh: {}
- do:
search:
body: { "query" : { "has_child" : { "type" : "type_3", "query" : { "match_all" : {} }, "inner_hits" : {} } } }
- match: { hits.total: 1 }
- match: { hits.hits.0._index: "test" }
- match: { hits.hits.0._type: "type_2" }
- match: { hits.hits.0._id: "1" }
- is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._index
- match: { hits.hits.0.inner_hits.type_3.hits.hits.0._type: "type_3" }
- match: { hits.hits.0.inner_hits.type_3.hits.hits.0._id: "1" }
- is_false: hits.hits.0.inner_hits.type_3.hits.hits.0._nested

View File

@ -34,6 +34,7 @@ List projects = [
'modules:lang-expression',
'modules:lang-mustache',
'modules:lang-painless',
'modules:parent-join',
'modules:percolator',
'modules:reindex',
'modules:repository-url',
@ -72,7 +73,7 @@ List projects = [
'qa:smoke-test-ingest-disabled',
'qa:smoke-test-multinode',
'qa:smoke-test-plugins',
'qa:smoke-test-reindex-with-painless',
'qa:smoke-test-reindex-with-all-modules',
'qa:smoke-test-tribe-node',
'qa:vagrant',
'qa:wildfly'

View File

@ -33,6 +33,9 @@ import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.env.Environment;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.indices.IndicesModule;
import org.elasticsearch.plugins.Plugin;
import org.elasticsearch.plugins.PluginsService;
import org.elasticsearch.plugins.SearchPlugin;
import org.elasticsearch.search.SearchModule;
import org.elasticsearch.search.aggregations.support.ValuesSourceAggregationBuilder;
import org.elasticsearch.test.AbstractQueryTestCase;
@ -40,6 +43,7 @@ import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@ -66,6 +70,10 @@ public abstract class BaseAggregationTestCase<AB extends AbstractAggregationBuil
private NamedXContentRegistry xContentRegistry;
protected abstract AB createTestAggregatorBuilder();
protected Collection<Class<? extends Plugin>> getPlugins() {
return Collections.emptyList();
}
/**
* Setup for the whole base test class.
*/
@ -77,7 +85,8 @@ public abstract class BaseAggregationTestCase<AB extends AbstractAggregationBuil
.put(Environment.PATH_HOME_SETTING.getKey(), createTempDir())
.build();
IndicesModule indicesModule = new IndicesModule(Collections.emptyList());
SearchModule searchModule = new SearchModule(settings, false, emptyList());
PluginsService pluginsService = new PluginsService(settings, null, null, getPlugins());
SearchModule searchModule = new SearchModule(settings, false, pluginsService.filterPlugins(SearchPlugin.class));
List<NamedWriteableRegistry.Entry> entries = new ArrayList<>();
entries.addAll(indicesModule.getNamedWriteables());
entries.addAll(searchModule.getNamedWriteables());
@ -145,7 +154,6 @@ public abstract class BaseAggregationTestCase<AB extends AbstractAggregationBuil
}
}
public void testEqualsAndHashcode() throws IOException {
// TODO we only change name and boost, we should extend by any sub-test supplying a "mutate" method that randomly changes one
// aspect of the object under test

View File

@ -17,10 +17,11 @@
* under the License.
*/
package org.elasticsearch.search.aggregations.bucket;
package org.elasticsearch.search.aggregations;
import org.elasticsearch.search.aggregations.InternalAggregation;
import org.elasticsearch.search.aggregations.InternalAggregations;
import org.elasticsearch.search.aggregations.bucket.InternalSingleBucketAggregation;
import org.elasticsearch.search.aggregations.metrics.max.InternalMax;
import org.elasticsearch.search.aggregations.metrics.min.InternalMin;
import org.elasticsearch.search.aggregations.pipeline.PipelineAggregator;