Skip to content

Add a format option to docvalue_fields. #29639

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

Merged
merged 32 commits into from
May 23, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
b25ccfc
Add a `format` option to `docvalue_fields`.
jpountz Apr 20, 2018
c62e5bc
iter
jpountz Apr 20, 2018
3e373e1
iter
jpountz Apr 20, 2018
9991b80
iter
jpountz Apr 23, 2018
46ba35e
iter
jpountz Apr 23, 2018
ad7130c
Merge branch 'master' into feature/doc_value_format
jpountz Apr 25, 2018
b2d3de8
iter
jpountz Apr 25, 2018
ae28857
Make the format an optional constructor arg.
jpountz Apr 26, 2018
a177292
Merge branch 'master' into feature/doc_value_format
jpountz Apr 27, 2018
b38cde6
Fix docs of the `_ignored` meta field.
jpountz May 2, 2018
c422c36
Post backport of #29658.
jpountz May 2, 2018
9080853
Merge branch 'master' into feature/doc_value_format
jpountz May 2, 2018
886bae6
iter
jpountz May 2, 2018
88374e1
Fix changelog.
jpountz May 2, 2018
b228a29
Merge branch 'master' into feature/doc_value_format
jpountz May 2, 2018
677c75d
iter
jpountz May 2, 2018
99e2718
iter
jpountz May 4, 2018
a5932de
Merge branch 'master' into feature/doc_value_format
jpountz May 4, 2018
20c863c
Merge branch 'master' into feature/doc_value_format
jpountz May 9, 2018
1b74854
iter
jpountz May 9, 2018
0098d6c
Merge branch 'master' into feature/doc_value_format
jpountz May 11, 2018
710a420
iter
jpountz May 11, 2018
d106a26
iter
jpountz May 14, 2018
defe800
Merge branch 'master' into feature/doc_value_format
jpountz May 14, 2018
0ec669b
Merge branch 'master' into feature/doc_value_format
jpountz May 15, 2018
92a3b2d
Make SQL happy.
jpountz May 16, 2018
73b9472
Merge branch 'master' into feature/doc_value_format
jpountz May 16, 2018
2acd722
Fix docs.
jpountz May 17, 2018
4294d1d
Merge branch 'master' into feature/doc_value_format
jpountz May 17, 2018
ff2df6a
Merge branch 'master' into feature/doc_value_format
jpountz May 22, 2018
2e33fb5
iter
jpountz May 22, 2018
99a0249
iter
jpountz May 23, 2018
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 26 additions & 1 deletion docs/reference/search/request/docvalue-fields.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,38 @@ GET /_search
"query" : {
"match_all": {}
},
"docvalue_fields" : ["test1", "test2"]
"docvalue_fields" : [
{
"field": "my_ip_field", <1>
"format": "use_field_mapping" <2>
},
{
"field": "my_date_field",
"format": "epoch_millis" <3>
}
]
}
--------------------------------------------------
// CONSOLE
<1> the name of the field
<2> the special `use_field_mapping` format tells Elasticsearch to use the format from the mapping
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we not make the format field optional and indicate to use the field mapping by the option not being present? This would be in line with other places we support format such as in the date range query and date range aggregation

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the goal. The issue is that if we do this in 6.4 this will be a breaking change. For instance today date fields are returned as the output of Joda's ReadableInstant#toString(). I plan to make using the format from mappings the default in a follow-up PR that will only target 7.0.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok great, thanks for clarifying

<3> date fields may use a custom format

Doc value fields can work on fields that are not stored.

Note that if the fields parameter specifies fields without docvalues it will try to load the value from the fielddata cache
causing the terms for that field to be loaded to memory (cached), which will result in more memory consumption.

[float]
==== Custom formats

While most fields do not support custom formats, some of them do:
- <<date,Date>> fields can take any <<mapping-date-format,date format>>.
- <<number,Numeric>> fields accept a https://docs.oracle.com/javase/8/docs/api/java/text/DecimalFormat.html[DecimalFormat pattern].

All fields support the special `use_field_mapping` format, which tells
Elasticsearch to use the mappings to figure out a default format.

NOTE: The default is currently to return the same output as
<<search-request-script-fields,script fields>>. However it will change in 7.0
to behave as if the `use_field_mapping` format was provided.
7 changes: 6 additions & 1 deletion docs/reference/search/request/inner-hits.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,12 @@ POST test/_search
},
"inner_hits": {
"_source" : false,
"docvalue_fields" : ["comments.text.keyword"]
"docvalue_fields" : [
{
"field": "comments.text.keyword",
"format": "use_field_mapping"
}
]
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,8 @@ setup:
"Nested doc version and seqIDs":

- skip:
# fixed in 6.0.1
version: " - 6.0.0"
reason: "version and seq IDs where not accurate in previous versions"
version: " - 6.99.99" # TODO change to 6.3.99 on backport
reason: "object notation for docvalue_fields was introduced in 6.4"

- do:
index:
Expand All @@ -61,7 +60,7 @@ setup:

- do:
search:
body: { "query" : { "nested" : { "path" : "nested_field", "query" : { "match_all" : {} }, "inner_hits" : { version: true, "docvalue_fields": ["_seq_no"]} }}, "version": true, "docvalue_fields" : ["_seq_no"] }
body: { "query" : { "nested" : { "path" : "nested_field", "query" : { "match_all" : {} }, "inner_hits" : { version: true, "docvalue_fields": [ { "field": "_seq_no", "format": "use_field_mapping" } ]} }}, "version": true, "docvalue_fields" : [ { "field": "_seq_no", "format": "use_field_mapping" } ] }

- match: { hits.total: 1 }
- match: { hits.hits.0._index: "test" }
Expand All @@ -84,7 +83,7 @@ setup:

- do:
search:
body: { "query" : { "nested" : { "path" : "nested_field", "query" : { "match_all" : {} }, "inner_hits" : { version: true, "docvalue_fields": ["_seq_no"]} }}, "version": true, "docvalue_fields" : ["_seq_no"] }
body: { "query" : { "nested" : { "path" : "nested_field", "query" : { "match_all" : {} }, "inner_hits" : { version: true, "docvalue_fields": [ { "field": "_seq_no", "format": "use_field_mapping" } ]} }}, "version": true, "docvalue_fields" : [ { "field": "_seq_no", "format": "use_field_mapping" } ] }

- match: { hits.total: 1 }
- match: { hits.hits.0._index: "test" }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,53 @@ setup:

---
"docvalue_fields":
- skip:
version: " - 6.99.99" # TODO: change version on backport
reason: format option was added in 6.4
features: warnings
- do:
warnings:
- 'Doc-value field [count] is not using a format. The output will change in 7.0 when doc value fields get formatted based on mappings by default. It is recommended to pass [format=use_field_mapping] with the doc value field in order to opt in for the future behaviour and ease the migration to 7.0.'
search:
body:
docvalue_fields: [ "count" ]
- match: { hits.hits.0.fields.count: [1] }

---
"docvalue_fields as url param":
- skip:
version: " - 6.99.99" # TODO: change version on backport
reason: format option was added in 6.4
features: warnings
- do:
warnings:
- 'Doc-value field [count] is not using a format. The output will change in 7.0 when doc value fields get formatted based on mappings by default. It is recommended to pass [format=use_field_mapping] with the doc value field in order to opt in for the future behaviour and ease the migration to 7.0.'
search:
docvalue_fields: [ "count" ]
- match: { hits.hits.0.fields.count: [1] }

---
"docvalue_fields with default format":
- skip:
version: " - 6.99.99" # TODO: change version on backport
reason: format option was added in 6.4
- do:
search:
body:
docvalue_fields:
- field: "count"
format: "use_field_mapping"
- match: { hits.hits.0.fields.count: [1] }

---
"docvalue_fields with explicit format":
- skip:
version: " - 6.99.99" # TODO: change version on backport
reason: format option was added in 6.4
- do:
search:
body:
docvalue_fields:
- field: "count"
format: "#.0"
- match: { hits.hits.0.fields.count: ["1.0"] }
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,23 @@ setup:
---
"Docvalues_fields size limit":

- skip:
version: " - 6.99.99" # TODO: change to 6.3.99 on backport
reason: "The object notation for docvalue_fields is only supported on 6.4+"
- do:
catch: /Trying to retrieve too many docvalue_fields\. Must be less than or equal to[:] \[2\] but was \[3\]\. This limit can be set by changing the \[index.max_docvalue_fields_search\] index level setting\./
search:
index: test_1
body:
query:
match_all: {}
docvalue_fields: ["one", "two", "three"]
docvalue_fields:
- field: "one"
format: "use_field_mapping"
- field: "two"
format: "use_field_mapping"
- field: "three"
format: "use_field_mapping"

---
"Script_fields size limit":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ private SearchSourceBuilder buildExpandSearchSourceBuilder(InnerHitBuilder optio
}
}
if (options.getDocValueFields() != null) {
options.getDocValueFields().forEach(groupSource::docValueField);
options.getDocValueFields().forEach(ff -> groupSource.docValueField(ff.field, ff.format));
}
if (options.getStoredFieldsContext() != null && options.getStoredFieldsContext().fieldNames() != null) {
options.getStoredFieldsContext().fieldNames().forEach(groupSource::storedField);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -290,11 +290,21 @@ public SearchRequestBuilder setFetchSource(@Nullable String[] includes, @Nullabl
*
* @param name The field to get from the docvalue
*/
public SearchRequestBuilder addDocValueField(String name) {
sourceBuilder().docValueField(name);
public SearchRequestBuilder addDocValueField(String name, String format) {
sourceBuilder().docValueField(name, format);
return this;
}

/**
* Adds a docvalue based field to load and return. The field does not have to be stored,
* but its recommended to use non analyzed or numeric fields.
*
* @param name The field to get from the docvalue
*/
public SearchRequestBuilder addDocValueField(String name) {
return addDocValueField(name, null);
}

/**
* Adds a stored field to load and return (note, it must be stored) as part of the search request.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
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.FieldAndFormat;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
import org.elasticsearch.search.sort.SortBuilder;
Expand All @@ -45,6 +46,7 @@
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.stream.Collectors;

import static org.elasticsearch.common.xcontent.XContentParser.Token.END_OBJECT;

Expand All @@ -65,7 +67,8 @@ public final class InnerHitBuilder implements Writeable, ToXContentObject {
PARSER.declareBoolean(InnerHitBuilder::setVersion, SearchSourceBuilder.VERSION_FIELD);
PARSER.declareBoolean(InnerHitBuilder::setTrackScores, SearchSourceBuilder.TRACK_SCORES_FIELD);
PARSER.declareStringArray(InnerHitBuilder::setStoredFieldNames, SearchSourceBuilder.STORED_FIELDS_FIELD);
PARSER.declareStringArray(InnerHitBuilder::setDocValueFields, SearchSourceBuilder.DOCVALUE_FIELDS_FIELD);
PARSER.declareObjectArray(InnerHitBuilder::setDocValueFields,
(p,c) -> FieldAndFormat.fromXContent(p), SearchSourceBuilder.DOCVALUE_FIELDS_FIELD);
PARSER.declareField((p, i, c) -> {
try {
Set<ScriptField> scriptFields = new HashSet<>();
Expand Down Expand Up @@ -102,7 +105,7 @@ public final class InnerHitBuilder implements Writeable, ToXContentObject {
private StoredFieldsContext storedFieldsContext;
private QueryBuilder query = DEFAULT_INNER_HIT_QUERY;
private List<SortBuilder<?>> sorts;
private List<String> docValueFields;
private List<FieldAndFormat> docValueFields;
private Set<ScriptField> scriptFields;
private HighlightBuilder highlightBuilder;
private FetchSourceContext fetchSourceContext;
Expand Down Expand Up @@ -134,7 +137,18 @@ public InnerHitBuilder(StreamInput in) throws IOException {
version = in.readBoolean();
trackScores = in.readBoolean();
storedFieldsContext = in.readOptionalWriteable(StoredFieldsContext::new);
docValueFields = (List<String>) in.readGenericValue();
if (in.getVersion().before(Version.V_7_0_0_alpha1)) { // TODO: change to 6.4.0 after backport
List<String> fieldList = (List<String>) in.readGenericValue();
if (fieldList == null) {
docValueFields = null;
} else {
docValueFields = fieldList.stream()
.map(field -> new FieldAndFormat(field, null))
.collect(Collectors.toList());
}
} else {
docValueFields = in.readBoolean() ? in.readList(FieldAndFormat::new) : null;
}
if (in.readBoolean()) {
int size = in.readVInt();
scriptFields = new HashSet<>(size);
Expand Down Expand Up @@ -174,7 +188,16 @@ public void writeTo(StreamOutput out) throws IOException {
out.writeBoolean(version);
out.writeBoolean(trackScores);
out.writeOptionalWriteable(storedFieldsContext);
out.writeGenericValue(docValueFields);
if (out.getVersion().before(Version.V_7_0_0_alpha1)) { // TODO: change to 6.4.0 after backport
out.writeGenericValue(docValueFields == null
? null
: docValueFields.stream().map(ff -> ff.field).collect(Collectors.toList()));
} else {
out.writeBoolean(docValueFields != null);
if (docValueFields != null) {
out.writeList(docValueFields);
}
}
boolean hasScriptFields = scriptFields != null;
out.writeBoolean(hasScriptFields);
if (hasScriptFields) {
Expand Down Expand Up @@ -248,7 +271,9 @@ private void writeToBWC(StreamOutput out,
out.writeBoolean(version);
out.writeBoolean(trackScores);
out.writeOptionalWriteable(storedFieldsContext);
out.writeGenericValue(docValueFields);
out.writeGenericValue(docValueFields == null
? null
: docValueFields.stream().map(ff -> ff.field).collect(Collectors.toList()));
boolean hasScriptFields = scriptFields != null;
out.writeBoolean(hasScriptFields);
if (hasScriptFields) {
Expand Down Expand Up @@ -390,29 +415,36 @@ public InnerHitBuilder setStoredFieldNames(List<String> fieldNames) {
/**
* Gets the docvalue fields.
*/
public List<String> getDocValueFields() {
public List<FieldAndFormat> getDocValueFields() {
return docValueFields;
}

/**
* Sets the stored fields to load from the docvalue and return.
*/
public InnerHitBuilder setDocValueFields(List<String> docValueFields) {
public InnerHitBuilder setDocValueFields(List<FieldAndFormat> docValueFields) {
this.docValueFields = docValueFields;
return this;
}

/**
* Adds a field to load from the docvalue and return.
*/
public InnerHitBuilder addDocValueField(String field) {
public InnerHitBuilder addDocValueField(String field, String format) {
if (docValueFields == null) {
docValueFields = new ArrayList<>();
}
docValueFields.add(field);
docValueFields.add(new FieldAndFormat(field, null));
return this;
}

/**
* Adds a field to load from doc values and return.
*/
public InnerHitBuilder addDocValueField(String field) {
return addDocValueField(field, null);
}

public Set<ScriptField> getScriptFields() {
return scriptFields;
}
Expand Down Expand Up @@ -489,8 +521,15 @@ public XContentBuilder toXContent(XContentBuilder builder, Params params) throws
}
if (docValueFields != null) {
builder.startArray(SearchSourceBuilder.DOCVALUE_FIELDS_FIELD.getPreferredName());
for (String docValueField : docValueFields) {
builder.value(docValueField);
for (FieldAndFormat docValueField : docValueFields) {
if (docValueField.format == null) {
builder.value(docValueField.field);
} else {
builder.startObject()
.field("field", docValueField.field)
.field("format", docValueField.format)
.endObject();
}
}
builder.endArray();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ private static void parseSearchSource(final SearchSourceBuilder searchSourceBuil
if (Strings.hasText(sDocValueFields)) {
String[] sFields = Strings.splitStringByCommaToArray(sDocValueFields);
for (String field : sFields) {
searchSourceBuilder.docValueField(field);
searchSourceBuilder.docValueField(field, null);
}
}
}
Expand Down
Loading