mirror of
https://github.com/honeymoose/OpenSearch.git
synced 2025-02-20 03:45:02 +00:00
The fields
option should always return an array for json document fields and single valued field for metadata fields.
Also the `fields` option can only be used to fetch leaf fields, trying to do fetch object fields will return in a client error. Closes #4542
This commit is contained in:
parent
fdfc7d7460
commit
f1bf585089
@ -115,6 +115,12 @@ For backward compatibility, if the requested fields are not stored, they will be
|
|||||||
from the `_source` (parsed and extracted). This functionality has been replaced by the
|
from the `_source` (parsed and extracted). This functionality has been replaced by the
|
||||||
<<get-source-filtering,source filtering>> parameter.
|
<<get-source-filtering,source filtering>> parameter.
|
||||||
|
|
||||||
|
Field values fetched from the document it self are always returned as an array. Metadata fields like `_routing` and
|
||||||
|
`_parent` fields are never returned as an array.
|
||||||
|
|
||||||
|
Also only leaf fields can be returned via the `field` option. So object fields can't be returned and such requests
|
||||||
|
will fail.
|
||||||
|
|
||||||
[float]
|
[float]
|
||||||
[[_source]]
|
[[_source]]
|
||||||
=== Getting the _source directly
|
=== Getting the _source directly
|
||||||
|
@ -34,9 +34,15 @@ For backwards compatibility, if the fields parameter specifies fields which are
|
|||||||
`false`), it will load the `_source` and extract it from it. This functionality has been replaced by the
|
`false`), it will load the `_source` and extract it from it. This functionality has been replaced by the
|
||||||
<<search-request-source-filtering,source filtering>> parameter.
|
<<search-request-source-filtering,source filtering>> parameter.
|
||||||
|
|
||||||
|
Field values fetched from the document it self are always returned as an array. Metadata fields like `_routing` and
|
||||||
|
`_parent` fields are never returned as an array.
|
||||||
|
|
||||||
|
Also only leaf fields can be returned via the `field` option. So object fields can't be returned and such requests
|
||||||
|
will fail.
|
||||||
|
|
||||||
Script fields can also be automatically detected and used as fields, so
|
Script fields can also be automatically detected and used as fields, so
|
||||||
things like `_source.obj1.obj2` can be used, though not recommended, as
|
things like `_source.obj1.field1` can be used, though not recommended, as
|
||||||
`obj1.obj2` will work as well.
|
`obj1.field1` will work as well.
|
||||||
|
|
||||||
[[partial]]
|
[[partial]]
|
||||||
==== Partial
|
==== Partial
|
||||||
|
@ -22,6 +22,7 @@ package org.elasticsearch.index.get;
|
|||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
import org.elasticsearch.common.io.stream.Streamable;
|
import org.elasticsearch.common.io.stream.Streamable;
|
||||||
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -34,11 +35,9 @@ import java.util.List;
|
|||||||
public class GetField implements Streamable, Iterable<Object> {
|
public class GetField implements Streamable, Iterable<Object> {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private List<Object> values;
|
private List<Object> values;
|
||||||
|
|
||||||
private GetField() {
|
private GetField() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public GetField(String name, List<Object> values) {
|
public GetField(String name, List<Object> values) {
|
||||||
@ -61,6 +60,10 @@ public class GetField implements Streamable, Iterable<Object> {
|
|||||||
return values;
|
return values;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean isMetadataField() {
|
||||||
|
return MapperService.isMetadataField(name);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Object> iterator() {
|
public Iterator<Object> iterator() {
|
||||||
return values.iterator();
|
return values.iterator();
|
||||||
|
@ -219,11 +219,11 @@ public class GetResult implements Streamable, Iterable<GetField>, ToXContent {
|
|||||||
if (field.getValues().isEmpty()) {
|
if (field.getValues().isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (field.getValues().size() == 1) {
|
String fieldName = field.getName();
|
||||||
builder.field(field.getName(), field.getValues().get(0));
|
if (field.isMetadataField()) {
|
||||||
|
builder.field(fieldName, field.getValue());
|
||||||
} else {
|
} else {
|
||||||
builder.field(field.getName());
|
builder.startArray(field.getName());
|
||||||
builder.startArray();
|
|
||||||
for (Object value : field.getValues()) {
|
for (Object value : field.getValues()) {
|
||||||
builder.value(value);
|
builder.value(value);
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import com.google.common.collect.ImmutableList;
|
|||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
import org.apache.lucene.index.Term;
|
import org.apache.lucene.index.Term;
|
||||||
import org.elasticsearch.ElasticSearchException;
|
import org.elasticsearch.ElasticSearchException;
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||||
import org.elasticsearch.common.Nullable;
|
import org.elasticsearch.common.Nullable;
|
||||||
import org.elasticsearch.common.bytes.BytesReference;
|
import org.elasticsearch.common.bytes.BytesReference;
|
||||||
import org.elasticsearch.common.collect.Tuple;
|
import org.elasticsearch.common.collect.Tuple;
|
||||||
@ -268,19 +269,18 @@ public class ShardGetService extends AbstractIndexShardComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FieldMapper<?> x = docMapper.mappers().smartNameFieldMapper(field);
|
FieldMapper<?> x = docMapper.mappers().smartNameFieldMapper(field);
|
||||||
// only if the field is stored or source is enabled we should add it..
|
if (x == null) {
|
||||||
if (docMapper.sourceMapper().enabled() || x == null || x.fieldType().stored()) {
|
if (docMapper.objectMappers().get(field) != null) {
|
||||||
value = searchLookup.source().extractValue(field);
|
// Only fail if we know it is a object field, missing paths / fields shouldn't fail.
|
||||||
// normalize the data if needed (mainly for binary fields, to convert from base64 strings to bytes)
|
throw new ElasticSearchIllegalArgumentException("field [" + field + "] isn't a leaf field");
|
||||||
if (value != null && x != null) {
|
}
|
||||||
if (value instanceof List) {
|
} else if (docMapper.sourceMapper().enabled() || x.fieldType().stored()) {
|
||||||
List list = (List) value;
|
List<Object> values = searchLookup.source().extractRawValues(field);
|
||||||
for (int i = 0; i < list.size(); i++) {
|
if (!values.isEmpty()) {
|
||||||
list.set(i, x.valueForSearch(list.get(i)));
|
for (int i = 0; i < values.size(); i++) {
|
||||||
}
|
values.set(i, x.valueForSearch(values.get(i)));
|
||||||
} else {
|
|
||||||
value = x.valueForSearch(value);
|
|
||||||
}
|
}
|
||||||
|
value = values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -388,24 +388,25 @@ public class ShardGetService extends AbstractIndexShardComponent {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
FieldMappers x = docMapper.mappers().smartName(field);
|
FieldMappers x = docMapper.mappers().smartName(field);
|
||||||
if (x == null || !x.mapper().fieldType().stored()) {
|
if (x == null) {
|
||||||
|
if (docMapper.objectMappers().get(field) != null) {
|
||||||
|
// Only fail if we know it is a object field, missing paths / fields shouldn't fail.
|
||||||
|
throw new ElasticSearchIllegalArgumentException("field [" + field + "] isn't a leaf field");
|
||||||
|
}
|
||||||
|
} else if (!x.mapper().fieldType().stored()) {
|
||||||
if (searchLookup == null) {
|
if (searchLookup == null) {
|
||||||
searchLookup = new SearchLookup(mapperService, fieldDataService, new String[]{type});
|
searchLookup = new SearchLookup(mapperService, fieldDataService, new String[]{type});
|
||||||
searchLookup.setNextReader(docIdAndVersion.context);
|
searchLookup.setNextReader(docIdAndVersion.context);
|
||||||
searchLookup.source().setNextSource(source);
|
searchLookup.source().setNextSource(source);
|
||||||
searchLookup.setNextDocId(docIdAndVersion.docId);
|
searchLookup.setNextDocId(docIdAndVersion.docId);
|
||||||
}
|
}
|
||||||
value = searchLookup.source().extractValue(field);
|
|
||||||
// normalize the data if needed (mainly for binary fields, to convert from base64 strings to bytes)
|
List<Object> values = searchLookup.source().extractRawValues(field);
|
||||||
if (value != null && x != null) {
|
if (!values.isEmpty()) {
|
||||||
if (value instanceof List) {
|
for (int i = 0; i < values.size(); i++) {
|
||||||
List list = (List) value;
|
values.set(i, x.mapper().valueForSearch(values.get(i)));
|
||||||
for (int i = 0; i < list.size(); i++) {
|
|
||||||
list.set(i, x.mapper().valueForSearch(list.get(i)));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
value = x.mapper().valueForSearch(value);
|
|
||||||
}
|
}
|
||||||
|
value = values;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package org.elasticsearch.index.mapper;
|
package org.elasticsearch.index.mapper;
|
||||||
|
|
||||||
|
import com.carrotsearch.hppc.ObjectOpenHashSet;
|
||||||
import com.google.common.base.Charsets;
|
import com.google.common.base.Charsets;
|
||||||
import com.google.common.collect.*;
|
import com.google.common.collect.*;
|
||||||
import org.apache.lucene.analysis.Analyzer;
|
import org.apache.lucene.analysis.Analyzer;
|
||||||
@ -75,6 +76,10 @@ import static org.elasticsearch.index.mapper.DocumentMapper.MergeFlags.mergeFlag
|
|||||||
public class MapperService extends AbstractIndexComponent implements Iterable<DocumentMapper> {
|
public class MapperService extends AbstractIndexComponent implements Iterable<DocumentMapper> {
|
||||||
|
|
||||||
public static final String DEFAULT_MAPPING = "_default_";
|
public static final String DEFAULT_MAPPING = "_default_";
|
||||||
|
private static ObjectOpenHashSet<String> META_FIELDS = ObjectOpenHashSet.from(
|
||||||
|
"_uid", "_id", "_type", "_all", "_analyzer", "_boost", "_parent", "_routing", "_index",
|
||||||
|
"_size", "_timestamp", "_ttl"
|
||||||
|
);
|
||||||
|
|
||||||
private final AnalysisService analysisService;
|
private final AnalysisService analysisService;
|
||||||
private final IndexFieldDataService fieldDataService;
|
private final IndexFieldDataService fieldDataService;
|
||||||
@ -841,6 +846,13 @@ public class MapperService extends AbstractIndexComponent implements Iterable<Do
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return Whether a field is a metadata field.
|
||||||
|
*/
|
||||||
|
public static boolean isMetadataField(String fieldName) {
|
||||||
|
return META_FIELDS.contains(fieldName);
|
||||||
|
}
|
||||||
|
|
||||||
public static class SmartNameObjectMapper {
|
public static class SmartNameObjectMapper {
|
||||||
private final ObjectMapper mapper;
|
private final ObjectMapper mapper;
|
||||||
private final DocumentMapper docMapper;
|
private final DocumentMapper docMapper;
|
||||||
|
@ -59,4 +59,9 @@ public interface SearchHitField extends Streamable, Iterable<Object> {
|
|||||||
* The field values.
|
* The field values.
|
||||||
*/
|
*/
|
||||||
List<Object> getValues();
|
List<Object> getValues();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return The field is a metadata field
|
||||||
|
*/
|
||||||
|
boolean isMetadataField();
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ package org.elasticsearch.search.fetch;
|
|||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import org.apache.lucene.index.AtomicReaderContext;
|
import org.apache.lucene.index.AtomicReaderContext;
|
||||||
import org.apache.lucene.index.ReaderUtil;
|
import org.apache.lucene.index.ReaderUtil;
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||||
import org.elasticsearch.common.inject.Inject;
|
import org.elasticsearch.common.inject.Inject;
|
||||||
import org.elasticsearch.common.text.StringAndBytesText;
|
import org.elasticsearch.common.text.StringAndBytesText;
|
||||||
import org.elasticsearch.common.text.Text;
|
import org.elasticsearch.common.text.Text;
|
||||||
@ -117,7 +118,12 @@ public class FetchPhase implements SearchPhase {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
FieldMappers x = context.smartNameFieldMappers(fieldName);
|
FieldMappers x = context.smartNameFieldMappers(fieldName);
|
||||||
if (x != null && x.mapper().fieldType().stored()) {
|
if (x == null) {
|
||||||
|
// Only fail if we know it is a object field, missing paths / fields shouldn't fail.
|
||||||
|
if (context.smartNameObjectMapper(fieldName) != null) {
|
||||||
|
throw new ElasticSearchIllegalArgumentException("field [" + fieldName + "] isn't a leaf field");
|
||||||
|
}
|
||||||
|
} else if (x.mapper().fieldType().stored()) {
|
||||||
if (fieldNames == null) {
|
if (fieldNames == null) {
|
||||||
fieldNames = new HashSet<String>();
|
fieldNames = new HashSet<String>();
|
||||||
}
|
}
|
||||||
@ -180,8 +186,8 @@ public class FetchPhase implements SearchPhase {
|
|||||||
}
|
}
|
||||||
if (extractFieldNames != null) {
|
if (extractFieldNames != null) {
|
||||||
for (String extractFieldName : extractFieldNames) {
|
for (String extractFieldName : extractFieldNames) {
|
||||||
Object value = context.lookup().source().extractValue(extractFieldName);
|
List<Object> values = context.lookup().source().extractRawValues(extractFieldName);
|
||||||
if (value != null) {
|
if (!values.isEmpty()) {
|
||||||
if (searchHit.fieldsOrNull() == null) {
|
if (searchHit.fieldsOrNull() == null) {
|
||||||
searchHit.fields(new HashMap<String, SearchHitField>(2));
|
searchHit.fields(new HashMap<String, SearchHitField>(2));
|
||||||
}
|
}
|
||||||
@ -191,7 +197,9 @@ public class FetchPhase implements SearchPhase {
|
|||||||
hitField = new InternalSearchHitField(extractFieldName, new ArrayList<Object>(2));
|
hitField = new InternalSearchHitField(extractFieldName, new ArrayList<Object>(2));
|
||||||
searchHit.fields().put(extractFieldName, hitField);
|
searchHit.fields().put(extractFieldName, hitField);
|
||||||
}
|
}
|
||||||
hitField.values().add(value);
|
for (Object value : values) {
|
||||||
|
hitField.values().add(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -415,12 +415,12 @@ public class InternalSearchHit implements SearchHit {
|
|||||||
if (field.values().isEmpty()) {
|
if (field.values().isEmpty()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (field.values().size() == 1) {
|
String fieldName = field.getName();
|
||||||
builder.field(field.name(), field.values().get(0));
|
if (field.isMetadataField()) {
|
||||||
|
builder.field(fieldName, field.value());
|
||||||
} else {
|
} else {
|
||||||
builder.field(field.name());
|
builder.startArray(fieldName);
|
||||||
builder.startArray();
|
for (Object value : field.getValues()) {
|
||||||
for (Object value : field.values()) {
|
|
||||||
builder.value(value);
|
builder.value(value);
|
||||||
}
|
}
|
||||||
builder.endArray();
|
builder.endArray();
|
||||||
|
@ -21,6 +21,7 @@ package org.elasticsearch.search.internal;
|
|||||||
|
|
||||||
import org.elasticsearch.common.io.stream.StreamInput;
|
import org.elasticsearch.common.io.stream.StreamInput;
|
||||||
import org.elasticsearch.common.io.stream.StreamOutput;
|
import org.elasticsearch.common.io.stream.StreamOutput;
|
||||||
|
import org.elasticsearch.index.mapper.MapperService;
|
||||||
import org.elasticsearch.search.SearchHitField;
|
import org.elasticsearch.search.SearchHitField;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@ -34,11 +35,9 @@ import java.util.List;
|
|||||||
public class InternalSearchHitField implements SearchHitField {
|
public class InternalSearchHitField implements SearchHitField {
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private List<Object> values;
|
private List<Object> values;
|
||||||
|
|
||||||
private InternalSearchHitField() {
|
private InternalSearchHitField() {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public InternalSearchHitField(String name, List<Object> values) {
|
public InternalSearchHitField(String name, List<Object> values) {
|
||||||
@ -77,6 +76,10 @@ public class InternalSearchHitField implements SearchHitField {
|
|||||||
return values();
|
return values();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isMetadataField() {
|
||||||
|
return MapperService.isMetadataField(name);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Iterator<Object> iterator() {
|
public Iterator<Object> iterator() {
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
|
|
||||||
package org.elasticsearch.get;
|
package org.elasticsearch.get;
|
||||||
|
|
||||||
|
import org.elasticsearch.ElasticSearchIllegalArgumentException;
|
||||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
import org.elasticsearch.action.admin.cluster.health.ClusterHealthResponse;
|
||||||
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
|
import org.elasticsearch.action.admin.cluster.health.ClusterHealthStatus;
|
||||||
import org.elasticsearch.action.delete.DeleteResponse;
|
import org.elasticsearch.action.delete.DeleteResponse;
|
||||||
@ -495,14 +496,14 @@ public class GetActionTests extends ElasticsearchIntegrationTest {
|
|||||||
.endObject())
|
.endObject())
|
||||||
.execute().actionGet();
|
.execute().actionGet();
|
||||||
|
|
||||||
GetResponse responseBeforeFlush = client().prepareGet(index, type, "1").setFields("_source", "included", "excluded").execute().actionGet();
|
GetResponse responseBeforeFlush = client().prepareGet(index, type, "1").setFields("_source", "included.field", "excluded.field").execute().actionGet();
|
||||||
assertThat(responseBeforeFlush.isExists(), is(true));
|
assertThat(responseBeforeFlush.isExists(), is(true));
|
||||||
assertThat(responseBeforeFlush.getSourceAsMap(), not(hasKey("excluded")));
|
assertThat(responseBeforeFlush.getSourceAsMap(), not(hasKey("excluded")));
|
||||||
assertThat(responseBeforeFlush.getSourceAsMap(), not(hasKey("field")));
|
assertThat(responseBeforeFlush.getSourceAsMap(), not(hasKey("field")));
|
||||||
assertThat(responseBeforeFlush.getSourceAsMap(), hasKey("included"));
|
assertThat(responseBeforeFlush.getSourceAsMap(), hasKey("included"));
|
||||||
|
|
||||||
// now tests that extra source filtering works as expected
|
// now tests that extra source filtering works as expected
|
||||||
GetResponse responseBeforeFlushWithExtraFilters = client().prepareGet(index, type, "1").setFields("included", "excluded")
|
GetResponse responseBeforeFlushWithExtraFilters = client().prepareGet(index, type, "1").setFields("included.field", "excluded.field")
|
||||||
.setFetchSource(new String[]{"field", "*.field"}, new String[]{"*.field2"}).get();
|
.setFetchSource(new String[]{"field", "*.field"}, new String[]{"*.field2"}).get();
|
||||||
assertThat(responseBeforeFlushWithExtraFilters.isExists(), is(true));
|
assertThat(responseBeforeFlushWithExtraFilters.isExists(), is(true));
|
||||||
assertThat(responseBeforeFlushWithExtraFilters.getSourceAsMap(), not(hasKey("excluded")));
|
assertThat(responseBeforeFlushWithExtraFilters.getSourceAsMap(), not(hasKey("excluded")));
|
||||||
@ -512,8 +513,8 @@ public class GetActionTests extends ElasticsearchIntegrationTest {
|
|||||||
assertThat((Map<String, Object>) responseBeforeFlushWithExtraFilters.getSourceAsMap().get("included"), not(hasKey("field2")));
|
assertThat((Map<String, Object>) responseBeforeFlushWithExtraFilters.getSourceAsMap().get("included"), not(hasKey("field2")));
|
||||||
|
|
||||||
client().admin().indices().prepareFlush(index).execute().actionGet();
|
client().admin().indices().prepareFlush(index).execute().actionGet();
|
||||||
GetResponse responseAfterFlush = client().prepareGet(index, type, "1").setFields("_source", "included", "excluded").execute().actionGet();
|
GetResponse responseAfterFlush = client().prepareGet(index, type, "1").setFields("_source", "included.field", "excluded.field").execute().actionGet();
|
||||||
GetResponse responseAfterFlushWithExtraFilters = client().prepareGet(index, type, "1").setFields("included", "excluded")
|
GetResponse responseAfterFlushWithExtraFilters = client().prepareGet(index, type, "1").setFields("included.field", "excluded.field")
|
||||||
.setFetchSource("*.field", "*.field2").get();
|
.setFetchSource("*.field", "*.field2").get();
|
||||||
|
|
||||||
assertThat(responseAfterFlush.isExists(), is(true));
|
assertThat(responseAfterFlush.isExists(), is(true));
|
||||||
@ -730,4 +731,135 @@ public class GetActionTests extends ElasticsearchIntegrationTest {
|
|||||||
assertThat(response.getResponses()[2].getResponse().getSourceAsMap().get("field").toString(), equalTo("value2"));
|
assertThat(response.getResponses()[2].getResponse().getSourceAsMap().get("field").toString(), equalTo("value2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFields_metaData() throws Exception {
|
||||||
|
client().admin().indices().prepareCreate("my-index")
|
||||||
|
.setSettings(ImmutableSettings.settingsBuilder().put("index.refresh_interval", -1))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
client().prepareIndex("my-index", "my-type1", "1")
|
||||||
|
.setRouting("1")
|
||||||
|
.setSource(jsonBuilder().startObject().field("field1", "value").endObject())
|
||||||
|
.get();
|
||||||
|
|
||||||
|
GetResponse getResponse = client().prepareGet("my-index", "my-type1", "1")
|
||||||
|
.setRouting("1")
|
||||||
|
.setFields("field1", "_routing")
|
||||||
|
.get();
|
||||||
|
assertThat(getResponse.isExists(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField("field1").isMetadataField(), equalTo(false));
|
||||||
|
assertThat(getResponse.getField("field1").getValue().toString(), equalTo("value"));
|
||||||
|
assertThat(getResponse.getField("_routing").isMetadataField(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField("_routing").getValue().toString(), equalTo("1"));
|
||||||
|
|
||||||
|
client().admin().indices().prepareFlush("my-index").get();
|
||||||
|
|
||||||
|
client().prepareGet("my-index", "my-type1", "1")
|
||||||
|
.setFields("field1", "_routing")
|
||||||
|
.setRouting("1")
|
||||||
|
.get();
|
||||||
|
assertThat(getResponse.isExists(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField("field1").isMetadataField(), equalTo(false));
|
||||||
|
assertThat(getResponse.getField("field1").getValue().toString(), equalTo("value"));
|
||||||
|
assertThat(getResponse.getField("_routing").isMetadataField(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField("_routing").getValue().toString(), equalTo("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFields_nonLeafField() throws Exception {
|
||||||
|
client().admin().indices().prepareCreate("my-index")
|
||||||
|
.setSettings(ImmutableSettings.settingsBuilder().put("index.refresh_interval", -1))
|
||||||
|
.get();
|
||||||
|
|
||||||
|
client().prepareIndex("my-index", "my-type1", "1")
|
||||||
|
.setSource(jsonBuilder().startObject().startObject("field1").field("field2", "value1").endObject().endObject())
|
||||||
|
.get();
|
||||||
|
|
||||||
|
try {
|
||||||
|
client().prepareGet("my-index", "my-type1", "1").setFields("field1").get();
|
||||||
|
assert false;
|
||||||
|
} catch (ElasticSearchIllegalArgumentException e) {}
|
||||||
|
|
||||||
|
client().admin().indices().prepareFlush("my-index").get();
|
||||||
|
|
||||||
|
try {
|
||||||
|
client().prepareGet("my-index", "my-type1", "1").setFields("field1").get();
|
||||||
|
assert false;
|
||||||
|
} catch (ElasticSearchIllegalArgumentException e) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFields_complexField() throws Exception {
|
||||||
|
client().admin().indices().prepareCreate("my-index")
|
||||||
|
.setSettings(ImmutableSettings.settingsBuilder().put("index.refresh_interval", -1))
|
||||||
|
.addMapping("my-type2", jsonBuilder().startObject().startObject("my-type2").startObject("properties")
|
||||||
|
.startObject("field1").field("type", "object")
|
||||||
|
.startObject("field2").field("type", "object")
|
||||||
|
.startObject("field3").field("type", "object")
|
||||||
|
.startObject("field4").field("type", "string").field("store", "yes")
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject().endObject().endObject())
|
||||||
|
.get();
|
||||||
|
|
||||||
|
BytesReference source = jsonBuilder().startObject()
|
||||||
|
.startArray("field1")
|
||||||
|
.startObject()
|
||||||
|
.startObject("field2")
|
||||||
|
.startArray("field3")
|
||||||
|
.startObject()
|
||||||
|
.field("field4", "value1")
|
||||||
|
.endObject()
|
||||||
|
.endArray()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.startObject()
|
||||||
|
.startObject("field2")
|
||||||
|
.startArray("field3")
|
||||||
|
.startObject()
|
||||||
|
.field("field4", "value2")
|
||||||
|
.endObject()
|
||||||
|
.endArray()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endArray()
|
||||||
|
.endObject().bytes();
|
||||||
|
|
||||||
|
client().prepareIndex("my-index", "my-type1", "1").setSource(source).get();
|
||||||
|
client().prepareIndex("my-index", "my-type2", "1").setSource(source).get();
|
||||||
|
|
||||||
|
|
||||||
|
String field = "field1.field2.field3.field4";
|
||||||
|
GetResponse getResponse = client().prepareGet("my-index", "my-type1", "1").setFields(field).get();
|
||||||
|
assertThat(getResponse.isExists(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField(field).isMetadataField(), equalTo(false));
|
||||||
|
assertThat(getResponse.getField(field).getValues().size(), equalTo(2));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(0).toString(), equalTo("value1"));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(1).toString(), equalTo("value2"));
|
||||||
|
|
||||||
|
getResponse = client().prepareGet("my-index", "my-type2", "1").setFields(field).get();
|
||||||
|
assertThat(getResponse.isExists(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField(field).isMetadataField(), equalTo(false));
|
||||||
|
assertThat(getResponse.getField(field).getValues().size(), equalTo(2));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(0).toString(), equalTo("value1"));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(1).toString(), equalTo("value2"));
|
||||||
|
|
||||||
|
client().admin().indices().prepareFlush("my-index").get();
|
||||||
|
|
||||||
|
getResponse = client().prepareGet("my-index", "my-type1", "1").setFields(field).get();
|
||||||
|
assertThat(getResponse.isExists(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField(field).isMetadataField(), equalTo(false));
|
||||||
|
assertThat(getResponse.getField(field).getValues().size(), equalTo(2));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(0).toString(), equalTo("value1"));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(1).toString(), equalTo("value2"));
|
||||||
|
|
||||||
|
getResponse = client().prepareGet("my-index", "my-type2", "1").setFields(field).get();
|
||||||
|
assertThat(getResponse.isExists(), equalTo(true));
|
||||||
|
assertThat(getResponse.getField(field).isMetadataField(), equalTo(false));
|
||||||
|
assertThat(getResponse.getField(field).getValues().size(), equalTo(2));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(0).toString(), equalTo("value1"));
|
||||||
|
assertThat(getResponse.getField(field).getValues().get(1).toString(), equalTo("value2"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -29,6 +29,7 @@ import org.elasticsearch.common.joda.Joda;
|
|||||||
import org.elasticsearch.common.settings.ImmutableSettings;
|
import org.elasticsearch.common.settings.ImmutableSettings;
|
||||||
import org.elasticsearch.common.settings.Settings;
|
import org.elasticsearch.common.settings.Settings;
|
||||||
import org.elasticsearch.common.xcontent.XContentFactory;
|
import org.elasticsearch.common.xcontent.XContentFactory;
|
||||||
|
import org.elasticsearch.rest.RestStatus;
|
||||||
import org.elasticsearch.search.sort.SortOrder;
|
import org.elasticsearch.search.sort.SortOrder;
|
||||||
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
import org.elasticsearch.test.ElasticsearchIntegrationTest;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
@ -331,4 +332,95 @@ public class SearchFieldsTests extends ElasticsearchIntegrationTest {
|
|||||||
assertThat(((BytesReference) searchResponse.getHits().getAt(0).fields().get("binary_field").value()).toBytesArray(), equalTo((BytesReference) new BytesArray("testing text".getBytes("UTF8"))));
|
assertThat(((BytesReference) searchResponse.getHits().getAt(0).fields().get("binary_field").value()).toBytesArray(), equalTo((BytesReference) new BytesArray("testing text".getBytes("UTF8"))));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchFields_metaData() throws Exception {
|
||||||
|
client().prepareIndex("my-index", "my-type1", "1")
|
||||||
|
.setRouting("1")
|
||||||
|
.setSource(jsonBuilder().startObject().field("field1", "value").endObject())
|
||||||
|
.setRefresh(true)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
SearchResponse searchResponse = client().prepareSearch("my-index")
|
||||||
|
.setTypes("my-type1")
|
||||||
|
.addField("field1").addField("_routing")
|
||||||
|
.get();
|
||||||
|
|
||||||
|
assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field("field1").isMetadataField(), equalTo(false));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field("field1").getValue().toString(), equalTo("value"));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field("_routing").isMetadataField(), equalTo(true));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field("_routing").getValue().toString(), equalTo("1"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSearchFields_nonLeafField() throws Exception {
|
||||||
|
client().prepareIndex("my-index", "my-type1", "1")
|
||||||
|
.setSource(jsonBuilder().startObject().startObject("field1").field("field2", "value1").endObject().endObject())
|
||||||
|
.setRefresh(true)
|
||||||
|
.get();
|
||||||
|
|
||||||
|
SearchResponse searchResponse = client().prepareSearch("my-index").setTypes("my-type1").addField("field1").get();
|
||||||
|
assertThat(searchResponse.getShardFailures().length, equalTo(1));
|
||||||
|
assertThat(searchResponse.getShardFailures()[0].status(), equalTo(RestStatus.BAD_REQUEST));
|
||||||
|
assertThat(searchResponse.getShardFailures()[0].reason(), containsString("field [field1] isn't a leaf field"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetFields_complexField() throws Exception {
|
||||||
|
client().admin().indices().prepareCreate("my-index")
|
||||||
|
.setSettings(ImmutableSettings.settingsBuilder().put("index.refresh_interval", -1))
|
||||||
|
.addMapping("my-type2", jsonBuilder().startObject().startObject("my-type2").startObject("properties")
|
||||||
|
.startObject("field1").field("type", "object")
|
||||||
|
.startObject("field2").field("type", "object")
|
||||||
|
.startObject("field3").field("type", "object")
|
||||||
|
.startObject("field4").field("type", "string").field("store", "yes")
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endObject().endObject().endObject())
|
||||||
|
.get();
|
||||||
|
|
||||||
|
BytesReference source = jsonBuilder().startObject()
|
||||||
|
.startArray("field1")
|
||||||
|
.startObject()
|
||||||
|
.startObject("field2")
|
||||||
|
.startArray("field3")
|
||||||
|
.startObject()
|
||||||
|
.field("field4", "value1")
|
||||||
|
.endObject()
|
||||||
|
.endArray()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.startObject()
|
||||||
|
.startObject("field2")
|
||||||
|
.startArray("field3")
|
||||||
|
.startObject()
|
||||||
|
.field("field4", "value2")
|
||||||
|
.endObject()
|
||||||
|
.endArray()
|
||||||
|
.endObject()
|
||||||
|
.endObject()
|
||||||
|
.endArray()
|
||||||
|
.endObject().bytes();
|
||||||
|
|
||||||
|
client().prepareIndex("my-index", "my-type1", "1").setSource(source).get();
|
||||||
|
client().prepareIndex("my-index", "my-type2", "1").setRefresh(true).setSource(source).get();
|
||||||
|
|
||||||
|
|
||||||
|
String field = "field1.field2.field3.field4";
|
||||||
|
SearchResponse searchResponse = client().prepareSearch("my-index").setTypes("my-type1").addField(field).get();
|
||||||
|
assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).isMetadataField(), equalTo(false));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).getValues().size(), equalTo(2));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).getValues().get(0).toString(), equalTo("value1"));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).getValues().get(1).toString(), equalTo("value2"));
|
||||||
|
|
||||||
|
searchResponse = client().prepareSearch("my-index").setTypes("my-type2").addField(field).get();
|
||||||
|
assertThat(searchResponse.getHits().totalHits(), equalTo(1l));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).isMetadataField(), equalTo(false));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).getValues().size(), equalTo(2));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).getValues().get(0).toString(), equalTo("value1"));
|
||||||
|
assertThat(searchResponse.getHits().getAt(0).field(field).getValues().get(1).toString(), equalTo("value2"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user