The `has_child` query's inner query now is wrapped in a filtered query with the child type as filter, this prevents other children from being returned as hit.
Extended the specialized simplified mapping source method to support metadata mapping fields. These fields can just specified as normal fields, but will automatically be placed as top level mapping field. Closes #3818
This commit is contained in:
parent
c093e90d51
commit
7286a015db
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
package org.elasticsearch.action.admin.indices.mapping.put;
|
package org.elasticsearch.action.admin.indices.mapping.put;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.ObjectOpenHashSet;
|
||||||
import org.elasticsearch.ElasticSearchGenerationException;
|
import org.elasticsearch.ElasticSearchGenerationException;
|
||||||
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||||
import org.elasticsearch.action.ActionRequestValidationException;
|
import org.elasticsearch.action.ActionRequestValidationException;
|
||||||
|
@ -52,6 +53,11 @@ import static org.elasticsearch.common.unit.TimeValue.readTimeValue;
|
||||||
*/
|
*/
|
||||||
public class PutMappingRequest extends MasterNodeOperationRequest<PutMappingRequest> {
|
public class PutMappingRequest extends MasterNodeOperationRequest<PutMappingRequest> {
|
||||||
|
|
||||||
|
private static ObjectOpenHashSet<String> RESERVED_FIELDS = ObjectOpenHashSet.from(
|
||||||
|
"_uid", "_id", "_type", "_source", "_all", "_analyzer", "_boost", "_parent", "_routing", "_index",
|
||||||
|
"_size", "_timestamp", "_ttl"
|
||||||
|
);
|
||||||
|
|
||||||
private String[] indices;
|
private String[] indices;
|
||||||
|
|
||||||
private String type;
|
private String type;
|
||||||
|
@ -125,6 +131,9 @@ public class PutMappingRequest extends MasterNodeOperationRequest<PutMappingRequ
|
||||||
/**
|
/**
|
||||||
* A specialized simplified mapping source method, takes the form of simple properties definition:
|
* A specialized simplified mapping source method, takes the form of simple properties definition:
|
||||||
* ("field1", "type=string,store=true").
|
* ("field1", "type=string,store=true").
|
||||||
|
*
|
||||||
|
* Also supports metadata mapping fields such as `_all` and `_parent` as property definition, these metadata
|
||||||
|
* mapping fields will automatically be put on the top level mapping object.
|
||||||
*/
|
*/
|
||||||
public PutMappingRequest source(Object... source) {
|
public PutMappingRequest source(Object... source) {
|
||||||
return source(buildFromSimplifiedDef(type, source));
|
return source(buildFromSimplifiedDef(type, source));
|
||||||
|
@ -137,9 +146,31 @@ public class PutMappingRequest extends MasterNodeOperationRequest<PutMappingRequ
|
||||||
if (type != null) {
|
if (type != null) {
|
||||||
builder.startObject(type);
|
builder.startObject(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < source.length; i++) {
|
||||||
|
String fieldName = source[i++].toString();
|
||||||
|
if (RESERVED_FIELDS.contains(fieldName)) {
|
||||||
|
builder.startObject(fieldName);
|
||||||
|
String[] s1 = Strings.splitStringByCommaToArray(source[i].toString());
|
||||||
|
for (String s : s1) {
|
||||||
|
String[] s2 = Strings.split(s, "=");
|
||||||
|
if (s2.length != 2) {
|
||||||
|
throw new ElasticSearchIllegalArgumentException("malformed " + s);
|
||||||
|
}
|
||||||
|
builder.field(s2[0], s2[1]);
|
||||||
|
}
|
||||||
|
builder.endObject();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
builder.startObject("properties");
|
builder.startObject("properties");
|
||||||
for (int i = 0; i < source.length; i++) {
|
for (int i = 0; i < source.length; i++) {
|
||||||
builder.startObject(source[i++].toString());
|
String fieldName = source[i++].toString();
|
||||||
|
if (RESERVED_FIELDS.contains(fieldName)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
builder.startObject(fieldName);
|
||||||
String[] s1 = Strings.splitStringByCommaToArray(source[i].toString());
|
String[] s1 = Strings.splitStringByCommaToArray(source[i].toString());
|
||||||
for (String s : s1) {
|
for (String s : s1) {
|
||||||
String[] s2 = Strings.split(s, "=");
|
String[] s2 = Strings.split(s, "=");
|
||||||
|
|
|
@ -24,6 +24,7 @@ import org.apache.lucene.search.Query;
|
||||||
import org.elasticsearch.common.Strings;
|
import org.elasticsearch.common.Strings;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.lucene.search.XConstantScoreQuery;
|
import org.elasticsearch.common.lucene.search.XConstantScoreQuery;
|
||||||
|
import org.elasticsearch.common.lucene.search.XFilteredQuery;
|
||||||
import org.elasticsearch.common.xcontent.XContentParser;
|
import org.elasticsearch.common.xcontent.XContentParser;
|
||||||
import org.elasticsearch.index.mapper.DocumentMapper;
|
import org.elasticsearch.index.mapper.DocumentMapper;
|
||||||
import org.elasticsearch.index.search.child.ChildrenConstantScoreQuery;
|
import org.elasticsearch.index.search.child.ChildrenConstantScoreQuery;
|
||||||
|
@ -132,6 +133,9 @@ public class HasChildQueryParser implements QueryParser {
|
||||||
throw new QueryParsingException(parseContext.index(), "[has_child] Type [" + childType + "] points to a non existent parent type [" + parentType + "]");
|
throw new QueryParsingException(parseContext.index(), "[has_child] Type [" + childType + "] points to a non existent parent type [" + parentType + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// wrap the query with type query
|
||||||
|
innerQuery = new XFilteredQuery(innerQuery, parseContext.cacheFilter(childDocMapper.typeFilter(), null));
|
||||||
|
|
||||||
boolean deleteByQuery = "delete_by_query".equals(SearchContext.current().source());
|
boolean deleteByQuery = "delete_by_query".equals(SearchContext.current().source());
|
||||||
Query query;
|
Query query;
|
||||||
Filter parentFilter = parseContext.cacheFilter(parentDocMapper.typeFilter(), null);
|
Filter parentFilter = parseContext.cacheFilter(parentDocMapper.typeFilter(), null);
|
||||||
|
|
|
@ -1772,4 +1772,64 @@ public class SimpleChildQuerySearchTests extends AbstractIntegrationTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
// Relates to bug: https://github.com/elasticsearch/elasticsearch/issues/3818
|
||||||
|
public void testHasChildQueryOnlyReturnsSingleChildType() {
|
||||||
|
client().admin().indices().prepareCreate("grandissue")
|
||||||
|
.setSettings(
|
||||||
|
ImmutableSettings.settingsBuilder()
|
||||||
|
.put("index.number_of_shards", 1)
|
||||||
|
.put("index.number_of_replicas", 0)
|
||||||
|
)
|
||||||
|
.addMapping("grandparent", "name", "type=string")
|
||||||
|
.addMapping("parent", "_parent", "type=grandparent")
|
||||||
|
.addMapping("child_type_one", "_parent", "type=parent")
|
||||||
|
.addMapping("child_type_two", "_parent", "type=parent")
|
||||||
|
.execute().actionGet();
|
||||||
|
|
||||||
|
client().prepareIndex("grandissue", "grandparent", "1").setSource("name", "Grandpa").execute().actionGet();
|
||||||
|
client().prepareIndex("grandissue", "parent", "2").setParent("1").setSource("name", "Dana").execute().actionGet();
|
||||||
|
client().prepareIndex("grandissue", "child_type_one", "3").setParent("2").setRouting("1")
|
||||||
|
.setSource("name", "William")
|
||||||
|
.execute().actionGet();
|
||||||
|
client().prepareIndex("grandissue", "child_type_two", "4").setParent("2").setRouting("1")
|
||||||
|
.setSource("name", "Kate")
|
||||||
|
.execute().actionGet();
|
||||||
|
client().admin().indices().prepareRefresh("grandissue").execute().actionGet();
|
||||||
|
|
||||||
|
SearchResponse searchResponse = client().prepareSearch("grandissue").setQuery(
|
||||||
|
boolQuery().must(
|
||||||
|
hasChildQuery(
|
||||||
|
"parent",
|
||||||
|
boolQuery().must(
|
||||||
|
hasChildQuery(
|
||||||
|
"child_type_one",
|
||||||
|
boolQuery().must(
|
||||||
|
queryString("name:William*").analyzeWildcard(true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).execute().actionGet();
|
||||||
|
assertHitCount(searchResponse, 1l);
|
||||||
|
|
||||||
|
searchResponse = client().prepareSearch("grandissue").setQuery(
|
||||||
|
boolQuery().must(
|
||||||
|
hasChildQuery(
|
||||||
|
"parent",
|
||||||
|
boolQuery().must(
|
||||||
|
hasChildQuery(
|
||||||
|
"child_type_two",
|
||||||
|
boolQuery().must(
|
||||||
|
queryString("name:William*").analyzeWildcard(true)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).execute().actionGet();
|
||||||
|
assertHitCount(searchResponse, 0l);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue