summaryrefslogtreecommitdiff
path: root/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java
diff options
context:
space:
mode:
Diffstat (limited to 'core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java')
-rw-r--r--core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java380
1 files changed, 100 insertions, 280 deletions
diff --git a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java
index d21d3d6670..4419d6a93a 100644
--- a/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java
+++ b/core/src/main/java/org/elasticsearch/index/query/InnerHitBuilder.java
@@ -28,31 +28,21 @@ import org.elasticsearch.common.io.stream.Writeable;
import org.elasticsearch.common.xcontent.ObjectParser;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
-import org.elasticsearch.index.mapper.DocumentMapper;
-import org.elasticsearch.index.mapper.ObjectMapper;
import org.elasticsearch.script.Script;
-import org.elasticsearch.script.ScriptContext;
-import org.elasticsearch.script.SearchScript;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.builder.SearchSourceBuilder.ScriptField;
import org.elasticsearch.search.fetch.StoredFieldsContext;
-import org.elasticsearch.search.fetch.subphase.DocValueFieldsContext;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
-import org.elasticsearch.search.fetch.subphase.InnerHitsContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
-import org.elasticsearch.search.internal.SearchContext;
-import org.elasticsearch.search.sort.SortAndFormats;
import org.elasticsearch.search.sort.SortBuilder;
import java.io.IOException;
import java.util.ArrayList;
-import java.util.HashMap;
+import java.util.Comparator;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
-import java.util.Map;
import java.util.Objects;
-import java.util.Optional;
import java.util.Set;
import static org.elasticsearch.common.xcontent.XContentParser.Token.END_OBJECT;
@@ -61,7 +51,6 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
public static final ParseField NAME_FIELD = new ParseField("name");
public static final ParseField IGNORE_UNMAPPED = new ParseField("ignore_unmapped");
- public static final ParseField INNER_HITS_FIELD = new ParseField("inner_hits");
public static final QueryBuilder DEFAULT_INNER_HIT_QUERY = new MatchAllQueryBuilder();
private static final ObjectParser<InnerHitBuilder, QueryParseContext> PARSER = new ObjectParser<>("inner_hits", InnerHitBuilder::new);
@@ -104,35 +93,9 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
}, SearchSourceBuilder._SOURCE_FIELD, ObjectParser.ValueType.OBJECT_ARRAY_BOOLEAN_OR_STRING);
PARSER.declareObject(InnerHitBuilder::setHighlightBuilder, (p, c) -> HighlightBuilder.fromXContent(c),
SearchSourceBuilder.HIGHLIGHT_FIELD);
- PARSER.declareObject(InnerHitBuilder::setChildInnerHits, (p, c) -> {
- try {
- Map<String, InnerHitBuilder> innerHitBuilders = new HashMap<>();
- String innerHitName = null;
- for (XContentParser.Token token = p.nextToken(); token != XContentParser.Token.END_OBJECT; token = p.nextToken()) {
- switch (token) {
- case START_OBJECT:
- InnerHitBuilder innerHitBuilder = InnerHitBuilder.fromXContent(c);
- innerHitBuilder.setName(innerHitName);
- innerHitBuilders.put(innerHitName, innerHitBuilder);
- break;
- case FIELD_NAME:
- innerHitName = p.currentName();
- break;
- default:
- throw new ParsingException(p.getTokenLocation(), "Expected [" + XContentParser.Token.START_OBJECT + "] in ["
- + p.currentName() + "] but found [" + token + "]", p.getTokenLocation());
- }
- }
- return innerHitBuilders;
- } catch (IOException e) {
- throw new ParsingException(p.getTokenLocation(), "Could not parse inner query definition", e);
- }
- }, INNER_HITS_FIELD);
}
private String name;
- private String nestedPath;
- private String parentChildType;
private boolean ignoreUnmapped;
private int from;
@@ -148,71 +111,25 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
private Set<ScriptField> scriptFields;
private HighlightBuilder highlightBuilder;
private FetchSourceContext fetchSourceContext;
- private Map<String, InnerHitBuilder> childInnerHits;
public InnerHitBuilder() {
+ this.name = null;
}
- private InnerHitBuilder(InnerHitBuilder other) {
- name = other.name;
- this.ignoreUnmapped = other.ignoreUnmapped;
- from = other.from;
- size = other.size;
- explain = other.explain;
- version = other.version;
- trackScores = other.trackScores;
- if (other.storedFieldsContext != null) {
- storedFieldsContext = new StoredFieldsContext(other.storedFieldsContext);
- }
- if (other.docValueFields != null) {
- docValueFields = new ArrayList<> (other.docValueFields);
- }
- if (other.scriptFields != null) {
- scriptFields = new HashSet<> (other.scriptFields);
- }
- if (other.fetchSourceContext != null) {
- fetchSourceContext = new FetchSourceContext(
- other.fetchSourceContext.fetchSource(), other.fetchSourceContext.includes(), other.fetchSourceContext.excludes()
- );
- }
- if (other.sorts != null) {
- sorts = new ArrayList<>(other.sorts);
- }
- highlightBuilder = other.highlightBuilder;
- if (other.childInnerHits != null) {
- childInnerHits = new HashMap<>(other.childInnerHits);
- }
- }
-
-
- InnerHitBuilder(InnerHitBuilder other, String nestedPath, QueryBuilder query, boolean ignoreUnmapped) {
- this(other);
- this.query = query;
- this.nestedPath = nestedPath;
- this.ignoreUnmapped = ignoreUnmapped;
- if (name == null) {
- this.name = nestedPath;
- }
+ public InnerHitBuilder(String name) {
+ this.name = name;
}
- // 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;
- this.ignoreUnmapped = ignoreUnmapped;
- if (name == null) {
- this.name = parentChildType;
- }
- }
/**
* Read from a stream.
*/
public InnerHitBuilder(StreamInput in) throws IOException {
name = in.readOptionalString();
- nestedPath = in.readOptionalString();
- parentChildType = in.readOptionalString();
+ if (in.getVersion().before(Version.V_6_0_0_alpha2_UNRELEASED)) {
+ in.readOptionalString();
+ in.readOptionalString();
+ }
if (in.getVersion().onOrAfter(Version.V_5_2_0)) {
ignoreUnmapped = in.readBoolean();
}
@@ -239,21 +156,94 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
}
}
highlightBuilder = in.readOptionalWriteable(HighlightBuilder::new);
- query = in.readNamedWriteable(QueryBuilder.class);
- if (in.readBoolean()) {
- int size = in.readVInt();
- childInnerHits = new HashMap<>(size);
- for (int i = 0; i < size; i++) {
- childInnerHits.put(in.readString(), new InnerHitBuilder(in));
- }
+ if (in.getVersion().before(Version.V_6_0_0_alpha2_UNRELEASED)) {
+ /**
+ * this is needed for BWC with nodes pre 5.5
+ */
+ in.readNamedWriteable(QueryBuilder.class);
+ boolean hasChildren = in.readBoolean();
+ assert hasChildren == false;
}
}
@Override
public void writeTo(StreamOutput out) throws IOException {
+ if (out.getVersion().before(Version.V_6_0_0_alpha2_UNRELEASED)) {
+ throw new IOException("Invalid output version, must >= " + Version.V_6_0_0_alpha2_UNRELEASED.toString());
+ }
out.writeOptionalString(name);
- out.writeOptionalString(nestedPath);
- out.writeOptionalString(parentChildType);
+ out.writeBoolean(ignoreUnmapped);
+ out.writeVInt(from);
+ out.writeVInt(size);
+ out.writeBoolean(explain);
+ out.writeBoolean(version);
+ out.writeBoolean(trackScores);
+ out.writeOptionalWriteable(storedFieldsContext);
+ out.writeGenericValue(docValueFields);
+ boolean hasScriptFields = scriptFields != null;
+ out.writeBoolean(hasScriptFields);
+ if (hasScriptFields) {
+ out.writeVInt(scriptFields.size());
+ Iterator<ScriptField> iterator = scriptFields.stream()
+ .sorted(Comparator.comparing(ScriptField::fieldName)).iterator();
+ while (iterator.hasNext()) {
+ iterator.next().writeTo(out);
+ }
+ }
+ out.writeOptionalWriteable(fetchSourceContext);
+ boolean hasSorts = sorts != null;
+ out.writeBoolean(hasSorts);
+ if (hasSorts) {
+ out.writeVInt(sorts.size());
+ for (SortBuilder<?> sort : sorts) {
+ out.writeNamedWriteable(sort);
+ }
+ }
+ out.writeOptionalWriteable(highlightBuilder);
+ }
+
+ /**
+ * BWC serialization for nested {@link InnerHitBuilder}.
+ * Should only be used to send nested inner hits to nodes pre 5.5.
+ */
+ protected void writeToNestedBWC(StreamOutput out, QueryBuilder query, String nestedPath) throws IOException {
+ assert out.getVersion().before(Version.V_6_0_0_alpha2_UNRELEASED) :
+ "invalid output version, must be < " + Version.V_6_0_0_alpha2_UNRELEASED.toString();
+ writeToBWC(out, query, nestedPath, null);
+ }
+
+ /**
+ * BWC serialization for collapsing {@link InnerHitBuilder}.
+ * Should only be used to send collapsing inner hits to nodes pre 5.5.
+ */
+ public void writeToCollapseBWC(StreamOutput out) throws IOException {
+ assert out.getVersion().before(Version.V_6_0_0_alpha2_UNRELEASED) :
+ "invalid output version, must be < " + Version.V_6_0_0_alpha2_UNRELEASED.toString();
+ writeToBWC(out, new MatchAllQueryBuilder(), null, null);
+ }
+
+ /**
+ * BWC serialization for parent/child {@link InnerHitBuilder}.
+ * Should only be used to send hasParent or hasChild inner hits to nodes pre 5.5.
+ */
+ public void writeToParentChildBWC(StreamOutput out, QueryBuilder query, String parentChildPath) throws IOException {
+ assert(out.getVersion().before(Version.V_6_0_0_alpha2_UNRELEASED)) :
+ "invalid output version, must be < " + Version.V_6_0_0_alpha2_UNRELEASED.toString();
+ writeToBWC(out, query, null, parentChildPath);
+ }
+
+ private void writeToBWC(StreamOutput out,
+ QueryBuilder query,
+ String nestedPath,
+ String parentChildPath) throws IOException {
+ out.writeOptionalString(name);
+ if (nestedPath != null) {
+ out.writeOptionalString(nestedPath);
+ out.writeOptionalString(null);
+ } else {
+ out.writeOptionalString(null);
+ out.writeOptionalString(parentChildPath);
+ }
if (out.getVersion().onOrAfter(Version.V_5_2_0)) {
out.writeBoolean(ignoreUnmapped);
}
@@ -269,7 +259,7 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
if (hasScriptFields) {
out.writeVInt(scriptFields.size());
Iterator<ScriptField> iterator = scriptFields.stream()
- .sorted((a, b) -> a.fieldName().compareTo(b.fieldName())).iterator();
+ .sorted(Comparator.comparing(ScriptField::fieldName)).iterator();
while (iterator.hasNext()) {
iterator.next().writeTo(out);
}
@@ -285,18 +275,7 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
}
out.writeOptionalWriteable(highlightBuilder);
out.writeNamedWriteable(query);
- boolean hasChildInnerHits = childInnerHits != null;
- out.writeBoolean(hasChildInnerHits);
- if (hasChildInnerHits) {
- out.writeVInt(childInnerHits.size());
- Iterator<Map.Entry<String, InnerHitBuilder>> iterator = childInnerHits.entrySet().stream()
- .sorted((a, b) -> a.getKey().compareTo(b.getKey())).iterator();
- while (iterator.hasNext()) {
- Map.Entry<String, InnerHitBuilder> entry = iterator.next();
- out.writeString(entry.getKey());
- entry.getValue().writeTo(out);
- }
- }
+ out.writeBoolean(false);
}
public String getName() {
@@ -308,6 +287,11 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
return this;
}
+ public InnerHitBuilder setIgnoreUnmapped(boolean value) {
+ this.ignoreUnmapped = value;
+ return this;
+ }
+
/**
* Whether to include inner hits in the search response hits if required mappings is missing
*/
@@ -525,136 +509,6 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
return query;
}
- void setChildInnerHits(Map<String, InnerHitBuilder> childInnerHits) {
- this.childInnerHits = childInnerHits;
- }
-
- String getParentChildType() {
- return parentChildType;
- }
-
- String getNestedPath() {
- return nestedPath;
- }
-
- void addChildInnerHit(InnerHitBuilder innerHitBuilder) {
- if (childInnerHits == null) {
- childInnerHits = new HashMap<>();
- }
- this.childInnerHits.put(innerHitBuilder.getName(), innerHitBuilder);
- }
-
- public InnerHitsContext.BaseInnerHits build(SearchContext parentSearchContext,
- InnerHitsContext innerHitsContext) throws IOException {
- QueryShardContext queryShardContext = parentSearchContext.getQueryShardContext();
- if (nestedPath != null) {
- ObjectMapper nestedObjectMapper = queryShardContext.getObjectMapper(nestedPath);
- if (nestedObjectMapper == null) {
- if (ignoreUnmapped == false) {
- throw new IllegalStateException("[" + query.getName() + "] no mapping found for type [" + nestedPath + "]");
- } else {
- return null;
- }
- }
-
- ObjectMapper parentObjectMapper = queryShardContext.nestedScope().nextLevel(nestedObjectMapper);
- InnerHitsContext.NestedInnerHits nestedInnerHits = new InnerHitsContext.NestedInnerHits(
- name, parentSearchContext, parentObjectMapper, nestedObjectMapper
- );
- setupInnerHitsContext(queryShardContext, nestedInnerHits);
- if (childInnerHits != null) {
- buildChildInnerHits(parentSearchContext, nestedInnerHits);
- }
- queryShardContext.nestedScope().previousLevel();
- innerHitsContext.addInnerHitDefinition(nestedInnerHits);
- return nestedInnerHits;
- } else if (parentChildType != null) {
- DocumentMapper documentMapper = queryShardContext.documentMapper(parentChildType);
- if (documentMapper == null) {
- if (ignoreUnmapped == false) {
- throw new IllegalStateException("[" + query.getName() + "] no mapping found for type [" + parentChildType + "]");
- } else {
- return null;
- }
- }
-
- InnerHitsContext.ParentChildInnerHits parentChildInnerHits = new InnerHitsContext.ParentChildInnerHits(
- name, parentSearchContext, queryShardContext.getMapperService(), documentMapper
- );
- setupInnerHitsContext(queryShardContext, parentChildInnerHits);
- if (childInnerHits != null) {
- buildChildInnerHits(parentSearchContext, parentChildInnerHits);
- }
- innerHitsContext.addInnerHitDefinition( parentChildInnerHits);
- return parentChildInnerHits;
- } else {
- throw new IllegalStateException("Neither a nested or parent/child inner hit");
- }
- }
-
- private void buildChildInnerHits(SearchContext parentSearchContext, InnerHitsContext.BaseInnerHits innerHits) throws IOException {
- Map<String, InnerHitsContext.BaseInnerHits> childInnerHits = new HashMap<>();
- for (Map.Entry<String, InnerHitBuilder> entry : this.childInnerHits.entrySet()) {
- InnerHitsContext.BaseInnerHits childInnerHit = entry.getValue().build(
- parentSearchContext, new InnerHitsContext()
- );
- if (childInnerHit != null) {
- childInnerHits.put(entry.getKey(), childInnerHit);
- }
- }
- innerHits.setChildInnerHits(childInnerHits);
- }
-
- private void setupInnerHitsContext(QueryShardContext context, InnerHitsContext.BaseInnerHits innerHitsContext) throws IOException {
- innerHitsContext.from(from);
- innerHitsContext.size(size);
- innerHitsContext.explain(explain);
- innerHitsContext.version(version);
- innerHitsContext.trackScores(trackScores);
- if (storedFieldsContext != null) {
- innerHitsContext.storedFieldsContext(storedFieldsContext);
- }
- if (docValueFields != null) {
- innerHitsContext.docValueFieldsContext(new DocValueFieldsContext(docValueFields));
- }
- if (scriptFields != null) {
- for (ScriptField field : scriptFields) {
- SearchScript searchScript = innerHitsContext.getQueryShardContext().getSearchScript(field.script(),
- ScriptContext.SEARCH);
- innerHitsContext.scriptFields().add(new org.elasticsearch.search.fetch.subphase.ScriptFieldsContext.ScriptField(
- field.fieldName(), searchScript, field.ignoreFailure()));
- }
- }
- if (fetchSourceContext != null) {
- innerHitsContext.fetchSourceContext(fetchSourceContext);
- }
- if (sorts != null) {
- Optional<SortAndFormats> optionalSort = SortBuilder.buildSort(sorts, context);
- if (optionalSort.isPresent()) {
- innerHitsContext.sort(optionalSort.get());
- }
- }
- if (highlightBuilder != null) {
- innerHitsContext.highlight(highlightBuilder.build(context));
- }
- ParsedQuery parsedQuery = new ParsedQuery(query.toQuery(context), context.copyNamedQueries());
- innerHitsContext.parsedQuery(parsedQuery);
- }
-
- public void inlineInnerHits(Map<String, InnerHitBuilder> innerHits) {
- InnerHitBuilder copy = new InnerHitBuilder(this);
- copy.parentChildType = this.parentChildType;
- copy.nestedPath = this.nestedPath;
- copy.query = this.query;
- innerHits.put(copy.getName(), copy);
-
- Map<String, InnerHitBuilder> childInnerHits = new HashMap<>();
- extractInnerHits(query, childInnerHits);
- if (childInnerHits.size() > 0) {
- copy.setChildInnerHits(childInnerHits);
- }
- }
-
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject();
@@ -697,13 +551,6 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
if (highlightBuilder != null) {
builder.field(SearchSourceBuilder.HIGHLIGHT_FIELD.getPreferredName(), highlightBuilder, params);
}
- if (childInnerHits != null) {
- builder.startObject(INNER_HITS_FIELD.getPreferredName());
- for (Map.Entry<String, InnerHitBuilder> entry : childInnerHits.entrySet()) {
- builder.field(entry.getKey(), entry.getValue(), params);
- }
- builder.endObject();
- }
builder.endObject();
return builder;
}
@@ -715,8 +562,6 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
InnerHitBuilder that = (InnerHitBuilder) o;
return Objects.equals(name, that.name) &&
- Objects.equals(nestedPath, that.nestedPath) &&
- Objects.equals(parentChildType, that.parentChildType) &&
Objects.equals(ignoreUnmapped, that.ignoreUnmapped) &&
Objects.equals(from, that.from) &&
Objects.equals(size, that.size) &&
@@ -728,41 +573,16 @@ public final class InnerHitBuilder extends ToXContentToBytes implements Writeabl
Objects.equals(scriptFields, that.scriptFields) &&
Objects.equals(fetchSourceContext, that.fetchSourceContext) &&
Objects.equals(sorts, that.sorts) &&
- Objects.equals(highlightBuilder, that.highlightBuilder) &&
- Objects.equals(query, that.query) &&
- Objects.equals(childInnerHits, that.childInnerHits);
+ Objects.equals(highlightBuilder, that.highlightBuilder);
}
@Override
public int hashCode() {
- return Objects.hash(name, nestedPath, parentChildType, ignoreUnmapped, from, size, explain, version, trackScores,
- storedFieldsContext, docValueFields, scriptFields, fetchSourceContext, sorts, highlightBuilder, query, childInnerHits);
+ return Objects.hash(name, ignoreUnmapped, from, size, explain, version, trackScores,
+ storedFieldsContext, docValueFields, scriptFields, fetchSourceContext, sorts, highlightBuilder);
}
public static InnerHitBuilder fromXContent(QueryParseContext context) throws IOException {
return PARSER.parse(context.parser(), new InnerHitBuilder(), context);
}
-
- public static void extractInnerHits(QueryBuilder query, Map<String, InnerHitBuilder> innerHitBuilders) {
- if (query instanceof AbstractQueryBuilder) {
- ((AbstractQueryBuilder) query).extractInnerHitBuilders(innerHitBuilders);
- } else {
- throw new IllegalStateException("provided query builder [" + query.getClass() +
- "] class should inherit from AbstractQueryBuilder, but it doesn't");
- }
- }
-
- // TODO public for hasParent and hasChild query
- public static InnerHitBuilder rewrite(InnerHitBuilder original, QueryBuilder rewrittenQuery) {
- if (original == null) {
- return null;
- }
-
- InnerHitBuilder copy = new InnerHitBuilder(original);
- copy.query = rewrittenQuery;
- copy.parentChildType = original.parentChildType;
- copy.nestedPath = original.nestedPath;
- return copy;
- }
-
}