-
Notifications
You must be signed in to change notification settings - Fork 25.2k
Teach _search to read search time mappings #59316
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
1533428
dc70b42
1938a0e
9d8e4b3
5a44788
7346b8b
4891bda
77f35cb
2011791
2b9b34c
0546dc2
a86ffaa
87bf5bf
8aeab2f
3c12ed0
09aa1f4
65a5326
27628d9
acefc5d
394ba8f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -618,6 +618,65 @@ public Analyzer searchQuoteAnalyzer() { | |
return this.searchQuoteAnalyzer; | ||
} | ||
|
||
/** | ||
* Builds a {@linkplain Function} to lookup mappers for a request, adding | ||
* any {@code extraMapping} provided. | ||
nik9000 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @param runtimeMappings extra mappings parse and to add to the request | ||
* lookup or {@code null} if there aren't any extra mappings | ||
*/ | ||
public Function<String, MappedFieldType> newFieldTypeLookup(Map<String, Object> runtimeMappings) { | ||
if (runtimeMappings == null || runtimeMappings.size() == 0) { | ||
return this::fieldType; | ||
} | ||
Mapper.BuilderContext builderContext = new Mapper.BuilderContext(indexSettings.getSettings(), new ContentPath(0)); | ||
Collection<ObjectMapper> objectMappers = new ArrayList<>(); | ||
Collection<FieldMapper> fieldMappers = new ArrayList<>(); | ||
Collection<FieldAliasMapper> fieldAliasMappers = new ArrayList<>(); | ||
for (Map.Entry<String, Object> runtimeEntry : runtimeMappings.entrySet()) { | ||
@SuppressWarnings("unchecked") // Safe because that is how we deserialized it | ||
Map<String, Object> definition = (Map<String, Object>) runtimeEntry.getValue(); | ||
String type = (String) definition.remove("type"); | ||
if (type == null) { | ||
throw new IllegalArgumentException("[type] is required for runtime mapping [" + runtimeEntry.getKey() + "]"); | ||
} | ||
Mapper.TypeParser parser = documentMapperParser().parserContext().typeParser(type); | ||
if (parser == null) { | ||
throw new IllegalArgumentException("[" + type + "] is unknown type for runtime mapping [" + runtimeEntry.getKey() + "]"); | ||
} | ||
Mapper.Builder<?> builder = parser.parse(runtimeEntry.getKey(), definition, documentMapperParser().parserContext()); | ||
Mapper mapper = builder.build(builderContext); | ||
|
||
MapperUtils.collect(mapper, objectMappers, fieldMappers, fieldAliasMappers); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you expand on why we need this? I was expecting that alias or objects would be caught anyways by your checks below, that only runtime fields can be defined. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This should allow us to collect the sub-mappers under objects. I do need to make sure there is a test for though. |
||
|
||
} | ||
// We don't do anything with the collected ObjectMappers | ||
Map<String, MappedFieldType> extra = new HashMap<>(); | ||
for (FieldMapper fm : fieldMappers) { | ||
if (false == fm.isRuntimeField()) { | ||
throw new IllegalArgumentException( | ||
"[" + fm.typeName() + "] are not supported in runtime mappings" | ||
); | ||
} | ||
MappedFieldType fromIndexMapping = fieldType(fm.name()); | ||
if (fromIndexMapping != null) { | ||
throw new IllegalArgumentException( | ||
"[" + fm.name() + "] can't be defined in the search's runtime mappings and the index's mappings" | ||
); | ||
} | ||
extra.put(fm.name(), fm.fieldType()); | ||
} | ||
if (false == fieldAliasMappers.isEmpty()) { | ||
throw new IllegalArgumentException("aliases are not supported in runtime mappings"); | ||
} | ||
return fullName -> { | ||
MappedFieldType searchTime = extra.get(fullName); | ||
javanna marked this conversation as resolved.
Show resolved
Hide resolved
|
||
if (searchTime != null) { | ||
return searchTime; | ||
} | ||
return fieldType(fullName); | ||
}; | ||
} | ||
|
||
/** | ||
* Returns <code>true</code> if fielddata is enabled for the {@link IdFieldMapper} field, <code>false</code> otherwise. | ||
*/ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ | |
package org.elasticsearch.search.builder; | ||
|
||
import org.elasticsearch.ElasticsearchException; | ||
import org.elasticsearch.Version; | ||
import org.elasticsearch.common.Booleans; | ||
import org.elasticsearch.common.Nullable; | ||
import org.elasticsearch.common.ParseField; | ||
|
@@ -62,6 +63,7 @@ | |
import java.util.ArrayList; | ||
import java.util.Collections; | ||
import java.util.List; | ||
import java.util.Map; | ||
import java.util.Objects; | ||
|
||
import static org.elasticsearch.index.query.AbstractQueryBuilder.parseInnerQueryBuilder; | ||
|
@@ -107,6 +109,7 @@ public final class SearchSourceBuilder implements Writeable, ToXContentObject, R | |
public static final ParseField SEARCH_AFTER = new ParseField("search_after"); | ||
public static final ParseField COLLAPSE = new ParseField("collapse"); | ||
public static final ParseField SLICE = new ParseField("slice"); | ||
public static final ParseField RUNTIME_MAPPINGS = new ParseField("runtime_mappings"); | ||
|
||
public static SearchSourceBuilder fromXContent(XContentParser parser) throws IOException { | ||
return fromXContent(parser, true); | ||
|
@@ -185,6 +188,8 @@ public static HighlightBuilder highlight() { | |
|
||
private CollapseBuilder collapse = null; | ||
|
||
private Map<String, Object> runtimeMappings; | ||
|
||
/** | ||
* Constructs a new search source builder. | ||
*/ | ||
|
@@ -239,6 +244,10 @@ public SearchSourceBuilder(StreamInput in) throws IOException { | |
sliceBuilder = in.readOptionalWriteable(SliceBuilder::new); | ||
collapse = in.readOptionalWriteable(CollapseBuilder::new); | ||
trackTotalHitsUpTo = in.readOptionalInt(); | ||
if (in.getVersion().onOrAfter(Version.V_8_0_0)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. add a TODO to update the version once the branch is merged? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
// TODO update version after backporting runtime fields | ||
runtimeMappings = in.readMap(); | ||
} | ||
} | ||
|
||
@Override | ||
|
@@ -293,6 +302,12 @@ public void writeTo(StreamOutput out) throws IOException { | |
out.writeOptionalWriteable(sliceBuilder); | ||
out.writeOptionalWriteable(collapse); | ||
out.writeOptionalInt(trackTotalHitsUpTo); | ||
if (out.getVersion().onOrAfter(Version.V_8_0_0)) { | ||
// TODO update version after backporting runtime fields | ||
out.writeMap(runtimeMappings); | ||
} else { | ||
throw new IllegalArgumentException("[" + RUNTIME_MAPPINGS.getPreferredName() + "] are not supported on nodes older than 8.0.0"); | ||
} | ||
} | ||
|
||
/** | ||
|
@@ -895,6 +910,21 @@ public List<String> stats() { | |
return stats; | ||
} | ||
|
||
/** | ||
* Extra runtime field mappings. | ||
*/ | ||
public SearchSourceBuilder runtimeMappings(Map<String, Object> runtimeMappings) { | ||
this.runtimeMappings = runtimeMappings; | ||
return this; | ||
} | ||
|
||
/** | ||
* Extra runtime field mappings. | ||
*/ | ||
public Map<String, Object> runtimeMappings() { | ||
return runtimeMappings; | ||
} | ||
|
||
public SearchSourceBuilder ext(List<SearchExtBuilder> searchExtBuilders) { | ||
this.extBuilders = Objects.requireNonNull(searchExtBuilders, "searchExtBuilders must not be null"); | ||
return this; | ||
|
@@ -996,6 +1026,7 @@ private SearchSourceBuilder shallowCopy(QueryBuilder queryBuilder, QueryBuilder | |
rewrittenBuilder.version = version; | ||
rewrittenBuilder.seqNoAndPrimaryTerm = seqNoAndPrimaryTerm; | ||
rewrittenBuilder.collapse = collapse; | ||
rewrittenBuilder.runtimeMappings = runtimeMappings; | ||
return rewrittenBuilder; | ||
} | ||
|
||
|
@@ -1104,6 +1135,8 @@ public void parseXContent(XContentParser parser, boolean checkTrailingTokens) th | |
sliceBuilder = SliceBuilder.fromXContent(parser); | ||
} else if (COLLAPSE.match(currentFieldName, parser.getDeprecationHandler())) { | ||
collapse = CollapseBuilder.fromXContent(parser); | ||
} else if (RUNTIME_MAPPINGS.match(currentFieldName, parser.getDeprecationHandler())) { | ||
runtimeMappings = parser.map(); | ||
} else { | ||
throw new ParsingException(parser.getTokenLocation(), "Unknown key for a " + token + " in [" + currentFieldName + "].", | ||
parser.getTokenLocation()); | ||
|
@@ -1551,7 +1584,8 @@ public boolean equals(Object obj) { | |
&& Objects.equals(profile, other.profile) | ||
&& Objects.equals(extBuilders, other.extBuilders) | ||
&& Objects.equals(collapse, other.collapse) | ||
&& Objects.equals(trackTotalHitsUpTo, other.trackTotalHitsUpTo); | ||
&& Objects.equals(trackTotalHitsUpTo, other.trackTotalHitsUpTo) | ||
&& Objects.equals(runtimeMappings, other.runtimeMappings); | ||
} | ||
|
||
@Override | ||
|
Uh oh!
There was an error while loading. Please reload this page.