Skip to content

Commit

Permalink
Adds ignore_unmapped option to nested and P/C queries
Browse files Browse the repository at this point in the history
The change adds a new option to the `nested`, `has_parent`, `has_children` and `parent_id` queries: `ignore_unmapped`. If this option is set to false, the `toQuery` method on the QueryBuilder will throw an exception if the type/path specified in the query is unmapped. If the option is set to true, the `toQuery` method on the QueryBuilder will return a MatchNoDocsQuery. The default value is `false`so the queries work how they do today (throwing an exception on unmapped paths/types)
  • Loading branch information
colings86 committed Apr 14, 2016
1 parent acec464 commit 686aff1
Show file tree
Hide file tree
Showing 12 changed files with 287 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil
* The default minimum number of children that are required to match for the parent to be considered a match.
*/
public static final int DEFAULT_MIN_CHILDREN = 0;

/**
* The default value for ignore_unmapped.
*/
public static final boolean DEFAULT_IGNORE_UNMAPPED = false;
/*
* The default score mode that is used to combine score coming from multiple parent documents.
*/
Expand All @@ -74,6 +79,7 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil
private static final ParseField MIN_CHILDREN_FIELD = new ParseField("min_children");
private static final ParseField SCORE_MODE_FIELD = new ParseField("score_mode");
private static final ParseField INNER_HITS_FIELD = new ParseField("inner_hits");
private static final ParseField IGNORE_UNMAPPED_FIELD = new ParseField("ignore_unmapped");

private final QueryBuilder<?> query;

Expand All @@ -87,6 +93,8 @@ public class HasChildQueryBuilder extends AbstractQueryBuilder<HasChildQueryBuil

private InnerHitBuilder innerHitBuilder;

private boolean ignoreUnmapped = false;


public HasChildQueryBuilder(String type, QueryBuilder<?> query, int maxChildren, int minChildren, ScoreMode scoreMode,
InnerHitBuilder innerHitBuilder) {
Expand Down Expand Up @@ -123,6 +131,7 @@ public HasChildQueryBuilder(StreamInput in) throws IOException {
scoreMode = ScoreMode.values()[in.readVInt()];
query = in.readQuery();
innerHitBuilder = in.readOptionalWriteable(InnerHitBuilder::new);
ignoreUnmapped = in.readBoolean();
}

@Override
Expand All @@ -133,6 +142,7 @@ protected void doWriteTo(StreamOutput out) throws IOException {
out.writeVInt(scoreMode.ordinal());
out.writeQuery(query);
out.writeOptionalWriteable(innerHitBuilder);
out.writeBoolean(ignoreUnmapped);
}

/**
Expand Down Expand Up @@ -220,6 +230,25 @@ public int minChildren() {
*/
public int maxChildren() { return maxChildren; }

/**
* Sets whether the query builder should ignore unmapped types (and run a
* {@link MatchNoDocsQuery} in place of this query) or throw an exception if
* the type is unmapped.
*/
public HasChildQueryBuilder ignoreUnmapped(boolean ignoreUnmapped) {
this.ignoreUnmapped = ignoreUnmapped;
return this;
}

/**
* Gets whether the query builder will ignore unmapped types (and run a
* {@link MatchNoDocsQuery} in place of this query) or throw an exception if
* the type is unmapped.
*/
public boolean ignoreUnmapped() {
return ignoreUnmapped;
}

@Override
protected void doXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(NAME);
Expand All @@ -229,6 +258,7 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
builder.field(SCORE_MODE_FIELD.getPreferredName(), scoreModeAsString(scoreMode));
builder.field(MIN_CHILDREN_FIELD.getPreferredName(), minChildren);
builder.field(MAX_CHILDREN_FIELD.getPreferredName(), maxChildren);
builder.field(IGNORE_UNMAPPED_FIELD.getPreferredName(), ignoreUnmapped);
printBoostAndQueryName(builder);
if (innerHitBuilder != null) {
builder.field(INNER_HITS_FIELD.getPreferredName(), innerHitBuilder, params);
Expand All @@ -243,6 +273,7 @@ public static HasChildQueryBuilder fromXContent(QueryParseContext parseContext)
ScoreMode scoreMode = HasChildQueryBuilder.DEFAULT_SCORE_MODE;
int minChildren = HasChildQueryBuilder.DEFAULT_MIN_CHILDREN;
int maxChildren = HasChildQueryBuilder.DEFAULT_MAX_CHILDREN;
boolean ignoreUnmapped = DEFAULT_IGNORE_UNMAPPED;
String queryName = null;
InnerHitBuilder innerHitBuilder = null;
String currentFieldName = null;
Expand Down Expand Up @@ -272,6 +303,8 @@ public static HasChildQueryBuilder fromXContent(QueryParseContext parseContext)
minChildren = parser.intValue(true);
} else if (parseContext.parseFieldMatcher().match(currentFieldName, MAX_CHILDREN_FIELD)) {
maxChildren = parser.intValue(true);
} else if (parseContext.parseFieldMatcher().match(currentFieldName, IGNORE_UNMAPPED_FIELD)) {
ignoreUnmapped = parser.booleanValue();
} else if (parseContext.parseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
queryName = parser.text();
} else {
Expand All @@ -283,6 +316,7 @@ public static HasChildQueryBuilder fromXContent(QueryParseContext parseContext)
scoreMode, innerHitBuilder);
hasChildQueryBuilder.queryName(queryName);
hasChildQueryBuilder.boost(boost);
hasChildQueryBuilder.ignoreUnmapped(ignoreUnmapped);
return hasChildQueryBuilder;
}

Expand Down Expand Up @@ -331,7 +365,11 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
}
DocumentMapper childDocMapper = context.getMapperService().documentMapper(type);
if (childDocMapper == null) {
throw new QueryShardException(context, "[" + NAME + "] no mapping found for type [" + type + "]");
if (ignoreUnmapped) {
return new MatchNoDocsQuery();
} else {
throw new QueryShardException(context, "[" + NAME + "] no mapping found for type [" + type + "]");
}
}
ParentFieldMapper parentFieldMapper = childDocMapper.parentFieldMapper();
if (parentFieldMapper.active() == false) {
Expand All @@ -344,8 +382,8 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
String parentType = parentFieldMapper.type();
DocumentMapper parentDocMapper = context.getMapperService().documentMapper(parentType);
if (parentDocMapper == null) {
throw new QueryShardException(context, "[" + NAME + "] Type [" + type + "] points to a non existent parent type ["
+ parentType + "]");
throw new QueryShardException(context,
"[" + NAME + "] Type [" + type + "] points to a non existent parent type [" + parentType + "]");
}

if (maxChildren > 0 && maxChildren < minChildren) {
Expand Down Expand Up @@ -464,12 +502,13 @@ protected boolean doEquals(HasChildQueryBuilder that) {
&& Objects.equals(scoreMode, that.scoreMode)
&& Objects.equals(minChildren, that.minChildren)
&& Objects.equals(maxChildren, that.maxChildren)
&& Objects.equals(innerHitBuilder, that.innerHitBuilder);
&& Objects.equals(innerHitBuilder, that.innerHitBuilder)
&& Objects.equals(ignoreUnmapped, that.ignoreUnmapped);
}

@Override
protected int doHashCode() {
return Objects.hash(query, type, scoreMode, minChildren, maxChildren, innerHitBuilder);
return Objects.hash(query, type, scoreMode, minChildren, maxChildren, innerHitBuilder, ignoreUnmapped);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import org.apache.lucene.search.BooleanClause;
import org.apache.lucene.search.BooleanQuery;
import org.apache.lucene.search.MatchNoDocsQuery;
import org.apache.lucene.search.Query;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.common.ParseField;
Expand Down Expand Up @@ -49,16 +50,23 @@ public class HasParentQueryBuilder extends AbstractQueryBuilder<HasParentQueryBu

public static final boolean DEFAULT_SCORE = false;

/**
* The default value for ignore_unmapped.
*/
public static final boolean DEFAULT_IGNORE_UNMAPPED = false;

private static final ParseField QUERY_FIELD = new ParseField("query", "filter");
private static final ParseField SCORE_MODE_FIELD = new ParseField("score_mode").withAllDeprecated("score");
private static final ParseField TYPE_FIELD = new ParseField("parent_type", "type");
private static final ParseField SCORE_FIELD = new ParseField("score");
private static final ParseField INNER_HITS_FIELD = new ParseField("inner_hits");
private static final ParseField IGNORE_UNMAPPED_FIELD = new ParseField("ignore_unmapped");

private final QueryBuilder<?> query;
private final String type;
private boolean score = DEFAULT_SCORE;
private InnerHitBuilder innerHit;
private boolean ignoreUnmapped = false;

/**
* @param type The parent type
Expand Down Expand Up @@ -94,6 +102,7 @@ public HasParentQueryBuilder(StreamInput in) throws IOException {
score = in.readBoolean();
query = in.readQuery();
innerHit = in.readOptionalWriteable(InnerHitBuilder::new);
ignoreUnmapped = in.readBoolean();
}

@Override
Expand All @@ -102,6 +111,7 @@ protected void doWriteTo(StreamOutput out) throws IOException {
out.writeBoolean(score);
out.writeQuery(query);
out.writeOptionalWriteable(innerHit);
out.writeBoolean(ignoreUnmapped);
}

/**
Expand Down Expand Up @@ -150,6 +160,25 @@ public InnerHitBuilder innerHit() {
return innerHit;
}

/**
* Sets whether the query builder should ignore unmapped types (and run a
* {@link MatchNoDocsQuery} in place of this query) or throw an exception if
* the type is unmapped.
*/
public HasParentQueryBuilder ignoreUnmapped(boolean ignoreUnmapped) {
this.ignoreUnmapped = ignoreUnmapped;
return this;
}

/**
* Gets whether the query builder will ignore unmapped types (and run a
* {@link MatchNoDocsQuery} in place of this query) or throw an exception if
* the type is unmapped.
*/
public boolean ignoreUnmapped() {
return ignoreUnmapped;
}

@Override
protected Query doToQuery(QueryShardContext context) throws IOException {
Query innerQuery;
Expand All @@ -166,8 +195,11 @@ protected Query doToQuery(QueryShardContext context) throws IOException {
}
DocumentMapper parentDocMapper = context.getMapperService().documentMapper(type);
if (parentDocMapper == null) {
throw new QueryShardException(context, "[" + NAME + "] query configured 'parent_type' [" + type
+ "] is not a valid type");
if (ignoreUnmapped) {
return new MatchNoDocsQuery();
} else {
throw new QueryShardException(context, "[" + NAME + "] query configured 'parent_type' [" + type + "] is not a valid type");
}
}

if (innerHit != null) {
Expand Down Expand Up @@ -220,6 +252,7 @@ protected void doXContent(XContentBuilder builder, Params params) throws IOExcep
query.toXContent(builder, params);
builder.field(TYPE_FIELD.getPreferredName(), type);
builder.field(SCORE_FIELD.getPreferredName(), score);
builder.field(IGNORE_UNMAPPED_FIELD.getPreferredName(), ignoreUnmapped);
printBoostAndQueryName(builder);
if (innerHit != null) {
builder.field(INNER_HITS_FIELD.getPreferredName(), innerHit, params);
Expand All @@ -234,6 +267,7 @@ public static HasParentQueryBuilder fromXContent(QueryParseContext parseContext)
boolean score = HasParentQueryBuilder.DEFAULT_SCORE;
String queryName = null;
InnerHitBuilder innerHits = null;
boolean ignoreUnmapped = DEFAULT_IGNORE_UNMAPPED;

String currentFieldName = null;
XContentParser.Token token;
Expand Down Expand Up @@ -264,6 +298,8 @@ public static HasParentQueryBuilder fromXContent(QueryParseContext parseContext)
}
} else if (parseContext.parseFieldMatcher().match(currentFieldName, SCORE_FIELD)) {
score = parser.booleanValue();
} else if (parseContext.parseFieldMatcher().match(currentFieldName, IGNORE_UNMAPPED_FIELD)) {
ignoreUnmapped = parser.booleanValue();
} else if (parseContext.parseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.BOOST_FIELD)) {
boost = parser.floatValue();
} else if (parseContext.parseFieldMatcher().match(currentFieldName, AbstractQueryBuilder.NAME_FIELD)) {
Expand All @@ -273,7 +309,8 @@ public static HasParentQueryBuilder fromXContent(QueryParseContext parseContext)
}
}
}
return new HasParentQueryBuilder(parentType, iqb, score, innerHits).queryName(queryName).boost(boost);
return new HasParentQueryBuilder(parentType, iqb, score, innerHits).ignoreUnmapped(ignoreUnmapped).queryName(queryName)
.boost(boost);
}

@Override
Expand All @@ -286,12 +323,13 @@ protected boolean doEquals(HasParentQueryBuilder that) {
return Objects.equals(query, that.query)
&& Objects.equals(type, that.type)
&& Objects.equals(score, that.score)
&& Objects.equals(innerHit, that.innerHit);
&& Objects.equals(innerHit, that.innerHit)
&& Objects.equals(ignoreUnmapped, that.ignoreUnmapped);
}

@Override
protected int doHashCode() {
return Objects.hash(query, type, score, innerHit);
return Objects.hash(query, type, score, innerHit, ignoreUnmapped);
}

@Override
Expand Down
Loading

0 comments on commit 686aff1

Please sign in to comment.