Add a GetFieldMapping API

This new API allows to get the mapping for a specific set of fields rather than get the whole index mapping and traverse it.
The fields to be retrieved can be specified by their full path, index name and field name and will be resolved in this order.
In case multiple field match, the first one will be returned.

Since we are now generating the output (rather then fall back to the stored mapping), you can specify `include_defaults`=true on the request to have default values returned.

Closes #3941
This commit is contained in:
Boaz Leskes 2013-10-14 08:53:07 +02:00
parent f16eb7a243
commit 8819f91d47
54 changed files with 1374 additions and 201 deletions

View File

@ -21,6 +21,8 @@ and warmers.
== Mapping management:
* <<indices-put-mapping>>
* <<indices-get-mapping>>
* <<indices-get-field-mapping>>
* <<indices-delete-mapping>>
* <<indices-types-exists>>
@ -68,6 +70,8 @@ include::indices/put-mapping.asciidoc[]
include::indices/get-mapping.asciidoc[]
include::indices/get-field-mapping.asciidoc[]
include::indices/types-exists.asciidoc[]
include::indices/delete-mapping.asciidoc[]

View File

@ -0,0 +1,137 @@
[[indices-get-field-mapping]]
== Get Field Mapping
The get field mapping API allows you to retrieve mapping definitions for one or more fields.
This is useful when you do not need the complete type mapping returned by
the <<indices-get-mapping>> API.
The following returns the mapping of the field `text` only:
[source,js]
--------------------------------------------------
curl -XGET 'http://localhost:9200/twitter/tweet/_mapping/field/text'
--------------------------------------------------
For which the response is (assuming `text` is a default string field):
[source,js]
--------------------------------------------------
{
"twitter": {
"tweet": {
"text": {
"full_name": "text",
"mapping": {
"text": { "type": "string" }
}
}
}
}
}
--------------------------------------------------
[float]
=== Multiple Indices, Types and Fields
The get field mapping API can be used to get the mapping of multiple fields from more than one index or type
with a single call. General usage of the API follows the
following syntax: `host:port/{index}/{type}/_mapping/field/{field}` where
`{index}`, `{type}` and `{field}` can stand for comma-separated list of names. To
get mappings for all indices you can use `_all` for `{index}`. The
following are some examples:
[source,js]
--------------------------------------------------
curl -XGET 'http://localhost:9200/twitter,kimchy/_mapping/field/message'
curl -XGET 'http://localhost:9200/_all/tweet,book/_mapping/field/message,user.id'
--------------------------------------------------
[float]
=== Specifying fields
The get mapping api allows you to specify fields using any of the following:
[horizontal]
Full names:: the full path, including any parent object name the field is
part of (ex. `user.id`).
Index names:: the name of the lucene field (can be different than the
field name if the `index_name` option of the mapping is used).
Field names:: the name of the field without the path to it (ex. `id` for `{ "user" : { "id" : 1 } }`).
The above options are specified in the order the `field` parameter is resolved.
The first field found which matches is returned. This is especially important
if index names or field names are used as those can be ambiguous.
For example, consider the following mapping:
[source,js]
--------------------------------------------------
{
"article": {
"properties": {
"id": { "type": "string" },
"title": { "type": "string", "index_name": "text" },
"abstract": { "type": "string", "index_name": "text" },
"author": {
"properties": {
"id": { "type": "string" },
"name": { "type": "string", "index_name": "author" }
}
}
}
}
}
--------------------------------------------------
To select the `id` of the `author` field, you can use it's full name `author.id`. Using `text` will return
the mapping of `abstract` as it is one of the fields which map to the Lucene field `text`. `name` will return
the field `author.name`:
[source,js]
--------------------------------------------------
curl -XGET "http://localhost:9200/publications/article/_mapping/field/author.id,text,name"
--------------------------------------------------
returns:
[source,js]
--------------------------------------------------
{
"publications": {
"article": {
"text": {
"full_name": "abstract",
"mapping": {
"abstract": { "type": "string", "index_name": "text" }
}
},
"author.id": {
"full_name": "author.id",
"mapping": {
"id": { "type": "string" }
}
},
"name": {
"full_name": "author.name",
"mapping": {
"name": { "type": "string", "index_name": "author" }
}
}
}
}
}
--------------------------------------------------
Note how the response always use the same fields specified in the request as keys.
The `full_name` in every entry contains the full name of the field whose mapping were returned.
This is useful when the request can refer to to multiple fields (like `text` above).
[float]
=== Other options
[horizontal]
include_defaults:: adding `include_defaults=true` to the query string will cause the response to
include default values, which are normally suppressed.

View File

@ -6,7 +6,7 @@ index/type.
[source,js]
--------------------------------------------------
$ curl -XGET 'http://localhost:9200/twitter/tweet/_mapping'
curl -XGET 'http://localhost:9200/twitter/tweet/_mapping'
--------------------------------------------------
[float]
@ -21,9 +21,9 @@ following are some examples:
[source,js]
--------------------------------------------------
$ curl -XGET 'http://localhost:9200/twitter,kimchy/_mapping'
curl -XGET 'http://localhost:9200/twitter,kimchy/_mapping'
$ curl -XGET 'http://localhost:9200/_all/tweet,book/_mapping'
curl -XGET 'http://localhost:9200/_all/tweet,book/_mapping'
--------------------------------------------------
If you want to get mappings of all indices and types then the following
@ -31,7 +31,7 @@ two examples are equivalent:
[source,js]
--------------------------------------------------
$ curl -XGET 'http://localhost:9200/_all/_mapping'
curl -XGET 'http://localhost:9200/_all/_mapping'
$ curl -XGET 'http://localhost:9200/_mapping'
curl -XGET 'http://localhost:9200/_mapping'
--------------------------------------------------

View File

@ -68,7 +68,9 @@ import org.elasticsearch.action.admin.indices.gateway.snapshot.GatewaySnapshotAc
import org.elasticsearch.action.admin.indices.gateway.snapshot.TransportGatewaySnapshotAction;
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingAction;
import org.elasticsearch.action.admin.indices.mapping.delete.TransportDeleteMappingAction;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsAction;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsAction;
import org.elasticsearch.action.admin.indices.mapping.get.TransportGetFieldMappingsAction;
import org.elasticsearch.action.admin.indices.mapping.get.TransportGetMappingsAction;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingAction;
import org.elasticsearch.action.admin.indices.mapping.put.TransportPutMappingAction;
@ -200,6 +202,7 @@ public class ActionModule extends AbstractModule {
registerAction(IndicesExistsAction.INSTANCE, TransportIndicesExistsAction.class);
registerAction(TypesExistsAction.INSTANCE, TransportTypesExistsAction.class);
registerAction(GetMappingsAction.INSTANCE, TransportGetMappingsAction.class);
registerAction(GetFieldMappingsAction.INSTANCE, TransportGetFieldMappingsAction.class);
registerAction(PutMappingAction.INSTANCE, TransportPutMappingAction.class);
registerAction(DeleteMappingAction.INSTANCE, TransportDeleteMappingAction.class);
registerAction(IndicesAliasesAction.INSTANCE, TransportIndicesAliasesAction.class);

View File

@ -0,0 +1,46 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.action.admin.indices.mapping.get;
import org.elasticsearch.action.admin.indices.IndicesAction;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.internal.InternalGenericClient;
/**
*/
public class GetFieldMappingsAction extends IndicesAction<GetFieldMappingsRequest, GetFieldMappingsResponse, GetFieldMappingsRequestBuilder> {
public static final GetFieldMappingsAction INSTANCE = new GetFieldMappingsAction();
public static final String NAME = "mappings/fields/get";
private GetFieldMappingsAction() {
super(NAME);
}
@Override
public GetFieldMappingsRequestBuilder newRequestBuilder(IndicesAdminClient client) {
return new GetFieldMappingsRequestBuilder((InternalGenericClient) client);
}
@Override
public GetFieldMappingsResponse newResponse() {
return new GetFieldMappingsResponse();
}
}

View File

@ -0,0 +1,75 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.action.admin.indices.mapping.get;
import org.elasticsearch.action.ActionRequestValidationException;
import org.elasticsearch.action.support.master.info.ClusterInfoRequest;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import java.io.IOException;
/** Request the mappings of specific fields */
public class GetFieldMappingsRequest extends ClusterInfoRequest<GetFieldMappingsRequest> {
private String[] fields = Strings.EMPTY_ARRAY;
private boolean includeDefaults = false;
/** @param fields a list of fields to retrieve the mapping for */
public GetFieldMappingsRequest fields(String... fields) {
this.fields = fields;
return this;
}
public String[] fields() {
return fields;
}
public boolean includeDefaults() {
return includeDefaults;
}
/** Indicates whether default mapping settings should be returned */
public GetFieldMappingsRequest includeDefaults(boolean includeDefaults) {
this.includeDefaults = includeDefaults;
return this;
}
@Override
public ActionRequestValidationException validate() {
return null;
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeStringArray(fields);
out.writeBoolean(includeDefaults);
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
fields = in.readStringArray();
includeDefaults = in.readBoolean();
}
}

View File

@ -0,0 +1,52 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.action.admin.indices.mapping.get;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.support.master.info.ClusterInfoRequestBuilder;
import org.elasticsearch.client.IndicesAdminClient;
import org.elasticsearch.client.internal.InternalGenericClient;
/** A helper class to build {@link GetFieldMappingsRequest} objects */
public class GetFieldMappingsRequestBuilder extends ClusterInfoRequestBuilder<GetFieldMappingsRequest, GetFieldMappingsResponse, GetFieldMappingsRequestBuilder> {
public GetFieldMappingsRequestBuilder(InternalGenericClient client, String... indices) {
super(client, new GetFieldMappingsRequest().indices(indices));
}
/** Sets the fields to retrieve. */
public GetFieldMappingsRequestBuilder setFields(String... fields) {
request.fields(fields);
return this;
}
/** Indicates whether default mapping settings should be returned */
public GetFieldMappingsRequestBuilder includeDefaults(boolean includeDefaults) {
request.includeDefaults(includeDefaults);
return this;
}
@Override
protected void doExecute(ActionListener<GetFieldMappingsResponse> listener) {
((IndicesAdminClient) client).getFieldMappings(request, listener);
}
}

View File

@ -0,0 +1,156 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.action.admin.indices.mapping.get;
import com.google.common.collect.ImmutableMap;
import org.elasticsearch.action.ActionResponse;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.io.stream.StreamInput;
import org.elasticsearch.common.io.stream.StreamOutput;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.index.mapper.Mapper;
import java.io.IOException;
import java.util.Map;
/** Response object for {@link GetFieldMappingsRequest} API */
public class GetFieldMappingsResponse extends ActionResponse implements ToXContent {
private ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> mappings = ImmutableMap.of();
GetFieldMappingsResponse(ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> mappings) {
this.mappings = mappings;
}
GetFieldMappingsResponse() {
}
/** returns the retrieved field mapping. The return map keys are index, type, field (as specified in the request). */
public ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> mappings() {
return mappings;
}
/**
* Returns the mappings of a specific field.
*
* @param field field name as specified in the {@link GetFieldMappingsRequest}
* @return FieldMappingMetaData for the requested field or null if not found.
*/
public FieldMappingMetaData fieldMappings(String index, String type, String field) {
ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>> indexMapping = mappings.get(index);
if (indexMapping == null) {
return null;
}
ImmutableMap<String, FieldMappingMetaData> typeMapping = indexMapping.get(type);
if (typeMapping == null) {
return null;
}
return typeMapping.get(field);
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
for (Map.Entry<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexEntry : mappings.entrySet()) {
builder.startObject(indexEntry.getKey(), XContentBuilder.FieldCaseConversion.NONE);
for (Map.Entry<String, ImmutableMap<String, FieldMappingMetaData>> typeEntry : indexEntry.getValue().entrySet()) {
builder.startObject(typeEntry.getKey(), XContentBuilder.FieldCaseConversion.NONE);
for (Map.Entry<String, FieldMappingMetaData> fieldEntry : typeEntry.getValue().entrySet()) {
builder.startObject(fieldEntry.getKey());
fieldEntry.getValue().toXContent(builder, params);
builder.endObject();
}
builder.endObject();
}
builder.endObject();
}
return builder;
}
public static class FieldMappingMetaData implements ToXContent {
private String fullName;
private BytesReference source;
public FieldMappingMetaData(String fullName, BytesReference source) {
this.fullName = fullName;
this.source = source;
}
public String fullName() {
return fullName;
}
/** Returns the mappings as a map. Note that the returned map has a single key which is always the field's {@link Mapper#name}. */
public Map<String, Object> sourceAsMap() {
return XContentHelper.convertToMap(source.array(), source.arrayOffset(), source.length(), true).v2();
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.field("full_name", fullName);
XContentHelper.writeRawField("mapping", source, builder, params);
return builder;
}
}
@Override
public void readFrom(StreamInput in) throws IOException {
super.readFrom(in);
int size = in.readVInt();
ImmutableMap.Builder<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexMapBuilder = ImmutableMap.builder();
for (int i = 0; i < size; i++) {
String index = in.readString();
int typesSize = in.readVInt();
ImmutableMap.Builder<String, ImmutableMap<String, FieldMappingMetaData>> typeMapBuilder = ImmutableMap.builder();
for (int j = 0; j < typesSize; j++) {
String type = in.readString();
ImmutableMap.Builder<String, FieldMappingMetaData> fieldMapBuilder = ImmutableMap.builder();
int fieldSize = in.readVInt();
for (int k = 0; k < fieldSize; k++) {
fieldMapBuilder.put(in.readString(), new FieldMappingMetaData(in.readString(), in.readBytesReference()));
}
typeMapBuilder.put(type, fieldMapBuilder.build());
}
indexMapBuilder.put(index, typeMapBuilder.build());
}
mappings = indexMapBuilder.build();
}
@Override
public void writeTo(StreamOutput out) throws IOException {
super.writeTo(out);
out.writeVInt(mappings.size());
for (Map.Entry<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexEntry : mappings.entrySet()) {
out.writeString(indexEntry.getKey());
out.writeVInt(indexEntry.getValue().size());
for (Map.Entry<String, ImmutableMap<String, FieldMappingMetaData>> typeEntry : indexEntry.getValue().entrySet()) {
out.writeString(typeEntry.getKey());
out.writeVInt(typeEntry.getValue().size());
for (Map.Entry<String, FieldMappingMetaData> fieldEntry : typeEntry.getValue().entrySet()) {
out.writeString(fieldEntry.getKey());
FieldMappingMetaData fieldMapping = fieldEntry.getValue();
out.writeString(fieldMapping.fullName());
out.writeBytesReference(fieldMapping.source);
}
}
}
}
}

View File

@ -0,0 +1,189 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.action.admin.indices.mapping.get;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Sets;
import org.elasticsearch.ElasticSearchException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData;
import org.elasticsearch.action.support.master.info.TransportClusterInfoAction;
import org.elasticsearch.cluster.ClusterService;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.regex.Regex;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.DocumentMapper;
import org.elasticsearch.index.mapper.FieldMapper;
import org.elasticsearch.index.service.IndexService;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.threadpool.ThreadPool;
import org.elasticsearch.transport.TransportService;
import java.io.IOException;
import java.util.Collection;
/**
*/
public class TransportGetFieldMappingsAction extends TransportClusterInfoAction<GetFieldMappingsRequest, GetFieldMappingsResponse> {
private final IndicesService indicesService;
@Inject
public TransportGetFieldMappingsAction(Settings settings, TransportService transportService, ClusterService clusterService,
IndicesService indicesService, ThreadPool threadPool) {
super(settings, transportService, clusterService, threadPool);
this.indicesService = indicesService;
}
@Override
protected String transportAction() {
return GetFieldMappingsAction.NAME;
}
@Override
protected GetFieldMappingsRequest newRequest() {
return new GetFieldMappingsRequest();
}
@Override
protected GetFieldMappingsResponse newResponse() {
return new GetFieldMappingsResponse();
}
@Override
protected void doMasterOperation(final GetFieldMappingsRequest request, final ClusterState state, final ActionListener<GetFieldMappingsResponse> listener) throws ElasticSearchException {
listener.onResponse(new GetFieldMappingsResponse(findMappings(request.indices(), request.types(), request.fields(), request.includeDefaults())));
}
private ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> findMappings(String[] concreteIndices,
final String[] types,
final String[] fields,
boolean includeDefaults) {
assert types != null;
assert concreteIndices != null;
if (concreteIndices.length == 0) {
return ImmutableMap.of();
}
ImmutableMap.Builder<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> indexMapBuilder = ImmutableMap.builder();
Sets.SetView<String> intersection = Sets.intersection(Sets.newHashSet(concreteIndices), indicesService.indices());
for (String index : intersection) {
IndexService indexService = indicesService.indexService(index);
Collection<String> typeIntersection;
if (types.length == 0) {
typeIntersection = indexService.mapperService().types();
} else {
typeIntersection = Collections2.filter(indexService.mapperService().types(), new Predicate<String>() {
@Override
public boolean apply(String type) {
return Regex.simpleMatch(types, type);
}
});
}
MapBuilder<String, ImmutableMap<String, FieldMappingMetaData>> typeMappings = new MapBuilder<String, ImmutableMap<String, FieldMappingMetaData>>();
for (String type : typeIntersection) {
DocumentMapper documentMapper = indexService.mapperService().documentMapper(type);
ImmutableMap<String, FieldMappingMetaData> fieldMapping = findFieldMappingsByType(documentMapper, fields, includeDefaults);
if (!fieldMapping.isEmpty()) {
typeMappings.put(type, fieldMapping);
}
}
if (!typeMappings.isEmpty()) {
indexMapBuilder.put(index, typeMappings.immutableMap());
}
}
return indexMapBuilder.build();
}
private static final ToXContent.Params includeDefaultsParams = new ToXContent.Params() {
final static String INCLUDE_DEFAULTS = "include_defaults";
@Override
public String param(String key) {
if (INCLUDE_DEFAULTS.equals(key)) {
return "true";
}
return null;
}
@Override
public String param(String key, String defaultValue) {
if (INCLUDE_DEFAULTS.equals(key)) {
return "true";
}
return defaultValue;
}
@Override
public boolean paramAsBoolean(String key, boolean defaultValue) {
if (INCLUDE_DEFAULTS.equals(key)) {
return true;
}
return defaultValue;
}
@Override
public Boolean paramAsBooleanOptional(String key, Boolean defaultValue) {
if (INCLUDE_DEFAULTS.equals(key)) {
return true;
}
return defaultValue;
}
};
private ImmutableMap<String, FieldMappingMetaData> findFieldMappingsByType(DocumentMapper documentMapper, String[] fields,
boolean includeDefaults) throws ElasticSearchException {
MapBuilder<String, FieldMappingMetaData> fieldMappings = new MapBuilder<String, FieldMappingMetaData>();
for (String field : fields) {
FieldMapper fieldMapper = documentMapper.mappers().smartNameFieldMapper(field);
if (fieldMapper != null) {
try {
XContentBuilder builder = XContentFactory.contentBuilder(XContentType.JSON);
builder.startObject();
fieldMapper.toXContent(builder, includeDefaults ? includeDefaultsParams : ToXContent.EMPTY_PARAMS);
builder.endObject();
fieldMappings.put(field, new FieldMappingMetaData(fieldMapper.names().fullName(), builder.bytes()));
} catch (IOException e) {
throw new ElasticSearchException("failed to serialize XContent of field [" + field + "]", e);
}
}
}
return fieldMappings.immutableMap();
}
}

View File

@ -59,9 +59,7 @@ import org.elasticsearch.action.admin.indices.gateway.snapshot.GatewaySnapshotRe
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequestBuilder;
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequestBuilder;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.admin.indices.mapping.get.*;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingResponse;
@ -398,12 +396,36 @@ public interface IndicesAdminClient {
*/
OptimizeRequestBuilder prepareOptimize(String... indices);
/**
* Get the complete mappings of one or more types
*/
void getMappings(GetMappingsRequest request, ActionListener<GetMappingsResponse> listener);
/**
* Get the complete mappings of one or more types
*/
ActionFuture<GetMappingsResponse> getMappings(GetMappingsRequest request);
/**
* Get the complete mappings of one or more types
*/
GetMappingsRequestBuilder prepareGetMappings(String... indices);
/**
* Get the mappings of specific fields
*/
void getFieldMappings(GetFieldMappingsRequest request, ActionListener<GetFieldMappingsResponse> listener);
/**
* Get the mappings of specific fields
*/
GetFieldMappingsRequestBuilder prepareGetFieldMappings(String... indices);
/**
* Get the mappings of specific fields
*/
ActionFuture<GetFieldMappingsResponse> getFieldMappings(GetFieldMappingsRequest request);
/**
* Add mapping definition for a type into one or more indices.
*

View File

@ -72,10 +72,7 @@ import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingAction
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingRequestBuilder;
import org.elasticsearch.action.admin.indices.mapping.delete.DeleteMappingResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsAction;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequestBuilder;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.action.admin.indices.mapping.get.*;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingAction;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequestBuilder;
@ -334,6 +331,11 @@ public abstract class AbstractIndicesAdminClient implements InternalIndicesAdmin
execute(GetMappingsAction.INSTANCE, request, listener);
}
@Override
public void getFieldMappings(GetFieldMappingsRequest request, ActionListener<GetFieldMappingsResponse> listener) {
execute(GetFieldMappingsAction.INSTANCE, request, listener);
}
@Override
public GetMappingsRequestBuilder prepareGetMappings(String... indices) {
return new GetMappingsRequestBuilder(this, indices);
@ -344,6 +346,16 @@ public abstract class AbstractIndicesAdminClient implements InternalIndicesAdmin
return execute(GetMappingsAction.INSTANCE, request);
}
@Override
public GetFieldMappingsRequestBuilder prepareGetFieldMappings(String... indices) {
return new GetFieldMappingsRequestBuilder(this, indices);
}
@Override
public ActionFuture<GetFieldMappingsResponse> getFieldMappings(GetFieldMappingsRequest request) {
return execute(GetFieldMappingsAction.INSTANCE, request);
}
@Override
public ActionFuture<PutMappingResponse> putMapping(final PutMappingRequest request) {
return execute(PutMappingAction.INSTANCE, request);

View File

@ -76,6 +76,10 @@ public class MapBuilder<K, V> {
return map.containsKey(key);
}
public boolean isEmpty() {
return map.isEmpty();
}
public Map<K, V> map() {
return this.map;
}

View File

@ -38,7 +38,7 @@ import org.elasticsearch.index.settings.IndexSettings;
* codec layer that allows to use use-case specific file formats &
* data-structures per field. ElasticSearch exposes the full
* {@link Codec} capabilities through this {@link CodecService}.
*
*
* @see PostingsFormatService
* @see DocValuesFormatService
*/
@ -49,6 +49,8 @@ public class CodecService extends AbstractIndexComponent {
private final MapperService mapperService;
private final ImmutableMap<String, Codec> codecs;
public final static String DEFAULT_CODEC = "default";
public CodecService(Index index) {
this(index, ImmutableSettings.Builder.EMPTY_SETTINGS);
}
@ -66,9 +68,11 @@ public class CodecService extends AbstractIndexComponent {
this.mapperService = mapperService;
MapBuilder<String, Codec> codecs = MapBuilder.<String, Codec>newMapBuilder();
if (mapperService == null) {
codecs.put("default", Codec.getDefault());
codecs.put(DEFAULT_CODEC, Codec.getDefault());
} else {
codecs.put("default", new PerFieldMappingPostingFormatCodec(mapperService, postingsFormatService.get("default").get(), docValuesFormatService.get("default").get(), logger));
codecs.put(DEFAULT_CODEC, new PerFieldMappingPostingFormatCodec(mapperService,
postingsFormatService.get(PostingsFormatService.DEFAULT_FORMAT).get(),
docValuesFormatService.get(DocValuesFormatService.DEFAULT_FORMAT).get(), logger));
}
for (String codec : Codec.availableCodecs()) {
codecs.put(codec, Codec.forName(codec));

View File

@ -36,14 +36,15 @@ import java.util.Map;
* The {@link DocValuesFormatService} provides access to
* all configured {@link DocValuesFormatProvider} instances by
* {@link DocValuesFormatProvider#name() name}.
*
*
* @see CodecService
*
*/
public class DocValuesFormatService extends AbstractIndexComponent {
private final ImmutableMap<String, DocValuesFormatProvider> providers;
public final static String DEFAULT_FORMAT = "default";
public DocValuesFormatService(Index index) {
this(index, ImmutableSettings.Builder.EMPTY_SETTINGS);
}

View File

@ -38,7 +38,7 @@ public class DocValuesFormats {
builtInDocValuesFormatsX.put(name, new PreBuiltDocValuesFormatProvider.Factory(DocValuesFormat.forName(name)));
}
// LUCENE UPGRADE: update those DVF if necessary
builtInDocValuesFormatsX.put("default", new PreBuiltDocValuesFormatProvider.Factory("default", DocValuesFormat.forName("Lucene45")));
builtInDocValuesFormatsX.put(DocValuesFormatService.DEFAULT_FORMAT, new PreBuiltDocValuesFormatProvider.Factory(DocValuesFormatService.DEFAULT_FORMAT, DocValuesFormat.forName("Lucene45")));
builtInDocValuesFormatsX.put("memory", new PreBuiltDocValuesFormatProvider.Factory("memory", DocValuesFormat.forName("Memory")));
builtInDocValuesFormatsX.put("disk", new PreBuiltDocValuesFormatProvider.Factory("disk", DocValuesFormat.forName("Disk")));
builtInDocValuesFormats = builtInDocValuesFormatsX.immutableMap();

View File

@ -71,7 +71,7 @@ public class PostingFormats {
buildInPostingFormatsX.put("memory", new PreBuiltPostingsFormatProvider.Factory("memory", PostingsFormat.forName("Memory")));
// LUCENE UPGRADE: Need to change this to the relevant ones on a lucene upgrade
buildInPostingFormatsX.put("pulsing", new PreBuiltPostingsFormatProvider.Factory("pulsing", PostingsFormat.forName("Pulsing41")));
buildInPostingFormatsX.put("default", new PreBuiltPostingsFormatProvider.Factory("default", defaultFormat));
buildInPostingFormatsX.put(PostingsFormatService.DEFAULT_FORMAT, new PreBuiltPostingsFormatProvider.Factory(PostingsFormatService.DEFAULT_FORMAT, defaultFormat));
buildInPostingFormatsX.put("bloom_pulsing", new PreBuiltPostingsFormatProvider.Factory("bloom_pulsing", wrapInBloom(PostingsFormat.forName("Pulsing41"))));
buildInPostingFormatsX.put("bloom_default", new PreBuiltPostingsFormatProvider.Factory("bloom_default", wrapInBloom(PostingsFormat.forName("Lucene41"))));

View File

@ -35,15 +35,16 @@ import java.util.Map;
/**
* The {@link PostingsFormatService} provides access to
* all configured {@link PostingsFormatProvider} instances by
* {@link PostingsFormatProvider#name() name}.
*
* @see CodecService
*
* {@link PostingsFormatProvider#name() name}.
*
* @see CodecService
*/
public class PostingsFormatService extends AbstractIndexComponent {
private final ImmutableMap<String, PostingsFormatProvider> providers;
public final static String DEFAULT_FORMAT = "default";
public PostingsFormatService(Index index) {
this(index, ImmutableSettings.Builder.EMPTY_SETTINGS);
}

View File

@ -38,7 +38,7 @@ import java.util.List;
/**
*
*/
public interface FieldMapper<T> {
public interface FieldMapper<T> extends Mapper {
public static final String DOC_VALUES_FORMAT = "doc_values_format";

View File

@ -39,11 +39,14 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.analysis.NamedAnalyzer;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatProvider;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatService;
import org.elasticsearch.index.codec.postingsformat.PostingFormats;
import org.elasticsearch.index.codec.postingsformat.PostingsFormatProvider;
import org.elasticsearch.index.codec.postingsformat.PostingsFormatService;
import org.elasticsearch.index.fielddata.FieldDataType;
import org.elasticsearch.index.mapper.*;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.similarity.SimilarityLookupService;
import org.elasticsearch.index.similarity.SimilarityProvider;
import java.io.IOException;
@ -54,7 +57,7 @@ import java.util.Map;
/**
*
*/
public abstract class AbstractFieldMapper<T> implements FieldMapper<T>, Mapper {
public abstract class AbstractFieldMapper<T> implements FieldMapper<T> {
public static class Defaults {
public static final FieldType FIELD_TYPE = new FieldType();
@ -350,9 +353,7 @@ public abstract class AbstractFieldMapper<T> implements FieldMapper<T>, Mapper {
/** Parse the field value and populate <code>fields</code>. */
protected abstract void parseCreateField(ParseContext context, List<Field> fields) throws IOException;
/**
* Derived classes can override it to specify that boost value is set by derived classes.
*/
/** Derived classes can override it to specify that boost value is set by derived classes. */
protected boolean customBoost() {
return false;
}
@ -550,68 +551,103 @@ public abstract class AbstractFieldMapper<T> implements FieldMapper<T>, Mapper {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(names.name());
doXContentBody(builder);
builder.endObject();
return builder;
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
doXContentBody(builder, includeDefaults, params);
return builder.endObject();
}
protected void doXContentBody(XContentBuilder builder) throws IOException {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
builder.field("type", contentType());
if (!names.name().equals(names.indexNameClean())) {
if (includeDefaults || !names.name().equals(names.indexNameClean())) {
builder.field("index_name", names.indexNameClean());
}
if (boost != 1.0f) {
if (includeDefaults || boost != 1.0f) {
builder.field("boost", boost);
}
FieldType defaultFieldType = defaultFieldType();
if (fieldType.indexed() != defaultFieldType.indexed() ||
if (includeDefaults || fieldType.indexed() != defaultFieldType.indexed() ||
fieldType.tokenized() != defaultFieldType.tokenized()) {
builder.field("index", indexTokenizeOptionToString(fieldType.indexed(), fieldType.tokenized()));
}
if (fieldType.stored() != defaultFieldType.stored()) {
if (includeDefaults || fieldType.stored() != defaultFieldType.stored()) {
builder.field("store", fieldType.stored());
}
if (fieldType.storeTermVectors() != defaultFieldType.storeTermVectors()) {
if (includeDefaults || fieldType.storeTermVectors() != defaultFieldType.storeTermVectors()) {
builder.field("term_vector", termVectorOptionsToString(fieldType));
}
if (fieldType.omitNorms() != defaultFieldType.omitNorms()) {
if (includeDefaults || fieldType.omitNorms() != defaultFieldType.omitNorms()) {
builder.field("omit_norms", fieldType.omitNorms());
}
if (fieldType.indexOptions() != defaultFieldType.indexOptions()) {
if (includeDefaults || fieldType.indexOptions() != defaultFieldType.indexOptions()) {
builder.field("index_options", indexOptionToString(fieldType.indexOptions()));
}
if (indexAnalyzer != null && searchAnalyzer != null && indexAnalyzer.name().equals(searchAnalyzer.name()) && !indexAnalyzer.name().startsWith("_") && !indexAnalyzer.name().equals("default")) {
// same analyzers, output it once
builder.field("analyzer", indexAnalyzer.name());
} else {
if (indexAnalyzer != null && !indexAnalyzer.name().startsWith("_") && !indexAnalyzer.name().equals("default")) {
if (indexAnalyzer == null && searchAnalyzer == null) {
if (includeDefaults) {
builder.field("analyzer", "default");
}
} else if (indexAnalyzer == null) {
// searchAnalyzer != null
if (includeDefaults || (!searchAnalyzer.name().startsWith("_") && !searchAnalyzer.name().equals("default"))) {
builder.field("search_analyzer", searchAnalyzer.name());
}
} else if (searchAnalyzer == null) {
// indexAnalyzer != null
if (includeDefaults || (!indexAnalyzer.name().startsWith("_") && !indexAnalyzer.name().equals("default"))) {
builder.field("index_analyzer", indexAnalyzer.name());
}
if (searchAnalyzer != null && !searchAnalyzer.name().startsWith("_") && !searchAnalyzer.name().equals("default")) {
} else if (indexAnalyzer.name().equals(searchAnalyzer.name())) {
// indexAnalyzer == searchAnalyzer
if (includeDefaults || (!indexAnalyzer.name().startsWith("_") && !indexAnalyzer.name().equals("default"))) {
builder.field("analyzer", indexAnalyzer.name());
}
} else {
// both are there but different
if (includeDefaults || (!indexAnalyzer.name().startsWith("_") && !indexAnalyzer.name().equals("default"))) {
builder.field("index_analyzer", indexAnalyzer.name());
}
if (includeDefaults || (!searchAnalyzer.name().startsWith("_") && !searchAnalyzer.name().equals("default"))) {
builder.field("search_analyzer", searchAnalyzer.name());
}
}
if (postingsFormat != null) {
if (!postingsFormat.name().equals(defaultPostingFormat())) {
if (includeDefaults || !postingsFormat.name().equals(defaultPostingFormat())) {
builder.field("postings_format", postingsFormat.name());
}
} else if (includeDefaults) {
String format = defaultPostingFormat();
if (format == null) {
format = PostingsFormatService.DEFAULT_FORMAT;
}
builder.field("postings_format", format);
}
if (docValuesFormat != null) {
if (!docValuesFormat.name().equals(defaultDocValuesFormat())) {
if (includeDefaults || !docValuesFormat.name().equals(defaultDocValuesFormat())) {
builder.field(DOC_VALUES_FORMAT, docValuesFormat.name());
}
} else if (includeDefaults) {
String format = defaultDocValuesFormat();
if (format == null) {
format = DocValuesFormatService.DEFAULT_FORMAT;
}
builder.field(DOC_VALUES_FORMAT, format);
}
if (similarity() != null) {
builder.field("similarity", similarity().name());
} else if (includeDefaults) {
builder.field("similariry", SimilarityLookupService.DEFAULT_SIMILARITY);
}
if (customFieldDataSettings != null) {
builder.field("fielddata", (Map) customFieldDataSettings.getAsMap());
} else if (includeDefaults) {
builder.field("fielddata", (Map) fieldDataType.getSettings().getAsMap());
}
}

View File

@ -200,23 +200,24 @@ public class BinaryFieldMapper extends AbstractFieldMapper<BytesReference> {
}
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
builder.startObject(names.name());
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
builder.field("type", contentType());
if (!names.name().equals(names.indexNameClean())) {
if (includeDefaults || !names.name().equals(names.indexNameClean())) {
builder.field("index_name", names.indexNameClean());
}
if (compress != null) {
builder.field("compress", compress);
} else if (includeDefaults) {
builder.field("compress", false);
}
if (compressThreshold != -1) {
builder.field("compress_threshold", new ByteSizeValue(compressThreshold).toString());
} else if (includeDefaults) {
builder.field("compress_threshold", -1);
}
if (fieldType.stored() != defaultFieldType().stored()) {
if (includeDefaults || fieldType.stored() != defaultFieldType().stored()) {
builder.field("store", fieldType.stored());
}
builder.endObject();
return builder;
}
@Override

View File

@ -227,9 +227,9 @@ public class BooleanFieldMapper extends AbstractFieldMapper<Boolean> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (nullValue != null) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
}

View File

@ -346,16 +346,19 @@ public class ByteFieldMapper extends NumberFieldMapper<Byte> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
}

View File

@ -244,9 +244,7 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
return parseStringValue(value.toString());
}
/**
* Dates should return as a string.
*/
/** Dates should return as a string. */
@Override
public Object valueForSearch(Object value) {
if (value instanceof String) {
@ -306,11 +304,11 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
return NumericRangeQuery.newLongRange(names.indexName(), precisionStep,
lValue, lValue, true, true);
}
public long parseToMilliseconds(Object value, @Nullable QueryParseContext context) {
return parseToMilliseconds(value, context, false);
}
public long parseToMilliseconds(Object value, @Nullable QueryParseContext context, boolean includeUpper) {
long now = context == null ? System.currentTimeMillis() : context.nowInMillis();
return includeUpper && roundCeil ? dateMathParser.parseRoundCeil(convertToString(value), now) : dateMathParser.parse(convertToString(value), now);
@ -450,24 +448,34 @@ public class DateFieldMapper extends NumberFieldMapper<Long> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
builder.field("format", dateTimeFormatter.format());
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
if (timeUnit != Defaults.TIME_UNIT) {
if (includeDefaults || timeUnit != Defaults.TIME_UNIT) {
builder.field("numeric_resolution", timeUnit.name().toLowerCase(Locale.ROOT));
}
// only serialize locale if needed, ROOT is the default, so no need to serialize that case as well...
if (dateTimeFormatter.locale() != null && dateTimeFormatter.locale() != Locale.ROOT) {
builder.field("locale", dateTimeFormatter.locale());
} else if (includeDefaults) {
if (dateTimeFormatter.locale() == null) {
builder.field("locale", Locale.ROOT);
} else {
builder.field("locale", dateTimeFormatter.locale());
}
}
}

View File

@ -342,17 +342,21 @@ public class DoubleFieldMapper extends NumberFieldMapper<Double> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
}
public static class CustomDoubleNumericField extends CustomNumericField {

View File

@ -339,17 +339,21 @@ public class FloatFieldMapper extends NumberFieldMapper<Float> {
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
}
public static class CustomFloatNumericField extends CustomNumericField {

View File

@ -125,7 +125,7 @@ public class IntegerFieldMapper extends NumberFieldMapper<Integer> {
super(names, precisionStep, boost, fieldType, ignoreMalformed,
NumericIntegerAnalyzer.buildNamedAnalyzer(precisionStep), NumericIntegerAnalyzer.buildNamedAnalyzer(Integer.MAX_VALUE),
postingsProvider, docValuesProvider, similarity, fieldDataSettings, indexSettings);
this.nullValue = nullValue;
this.nullValue = nullValue;
this.nullValueAsString = nullValue == null ? null : nullValue.toString();
}
@ -344,17 +344,21 @@ public class IntegerFieldMapper extends NumberFieldMapper<Integer> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
}
public static class CustomIntegerNumericField extends CustomNumericField {

View File

@ -340,16 +340,19 @@ public class LongFieldMapper extends NumberFieldMapper<Long> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
}

View File

@ -182,26 +182,34 @@ public abstract class NumberFieldMapper<T extends Number> extends AbstractFieldM
}
}
/** Utility method to convert a long to a doc values field using {@link NumericUtils} encoding. */
/**
* Utility method to convert a long to a doc values field using {@link NumericUtils} encoding.
*/
protected final Field toDocValues(long l) {
final BytesRef bytes = new BytesRef();
NumericUtils.longToPrefixCoded(l, 0, bytes);
return new SortedSetDocValuesField(names().indexName(), bytes);
}
/** Utility method to convert an int to a doc values field using {@link NumericUtils} encoding. */
/**
* Utility method to convert an int to a doc values field using {@link NumericUtils} encoding.
*/
protected final Field toDocValues(int i) {
final BytesRef bytes = new BytesRef();
NumericUtils.intToPrefixCoded(i, 0, bytes);
return new SortedSetDocValuesField(names().indexName(), bytes);
}
/** Utility method to convert a float to a doc values field using {@link NumericUtils} encoding. */
/**
* Utility method to convert a float to a doc values field using {@link NumericUtils} encoding.
*/
protected final Field toDocValues(float f) {
return toDocValues(NumericUtils.floatToSortableInt(f));
}
/** Utility method to convert a double to a doc values field using {@link NumericUtils} encoding. */
/**
* Utility method to convert a double to a doc values field using {@link NumericUtils} encoding.
*/
protected final Field toDocValues(double d) {
return toDocValues(NumericUtils.doubleToSortableLong(d));
}
@ -318,9 +326,10 @@ public abstract class NumberFieldMapper<T extends Number> extends AbstractFieldM
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (ignoreMalformed.explicit()) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || ignoreMalformed.explicit()) {
builder.field("ignore_malformed", ignoreMalformed.value());
}
}

View File

@ -345,17 +345,21 @@ public class ShortFieldMapper extends NumberFieldMapper<Short> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
}
public static class CustomShortNumericField extends CustomNumericField {

View File

@ -329,28 +329,36 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (nullValue != null) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
if (positionOffsetGap != Defaults.POSITION_OFFSET_GAP) {
if (includeDefaults || positionOffsetGap != Defaults.POSITION_OFFSET_GAP) {
builder.field("position_offset_gap", positionOffsetGap);
}
if (searchQuotedAnalyzer != null && searchAnalyzer != searchQuotedAnalyzer) {
builder.field("search_quote_analyzer", searchQuotedAnalyzer.name());
} else if (includeDefaults) {
if (searchQuotedAnalyzer == null) {
builder.field("search_quote_analyzer", "default");
} else {
builder.field("search_quote_analyzer", searchQuotedAnalyzer.name());
}
}
if (ignoreAbove != Defaults.IGNORE_ABOVE) {
if (includeDefaults || ignoreAbove != Defaults.IGNORE_ABOVE) {
builder.field("ignore_above", ignoreAbove);
}
}
/**
* Extension of {@link Field} supporting reuse of a cached TokenStream for not-tokenized values.
*/
/** Extension of {@link Field} supporting reuse of a cached TokenStream for not-tokenized values. */
static class StringField extends Field {
public StringField(String name, String value, FieldType fieldType) {
@ -394,9 +402,7 @@ public class StringFieldMapper extends AbstractFieldMapper<String> implements Al
StringTokenStream() {
}
/**
* Sets the string value.
*/
/** Sets the string value. */
StringTokenStream setValue(String value) {
this.value = value;
return this;

View File

@ -152,7 +152,7 @@ public class GeoShapeFieldMapper extends AbstractFieldMapper<String> {
return new GeoShapeFieldMapper(names, prefixTree, strategyName, distanceErrorPct, fieldType, postingsProvider, docValuesProvider);
}
}
private static final int getLevels(int treeLevels, double precisionInMeters, int defaultLevels, boolean geoHash) {
if (treeLevels > 0 || precisionInMeters >= 0) {
return Math.max(treeLevels, precisionInMeters >= 0 ? (geoHash ? GeoUtils.geoHashLevelsForPrecision(precisionInMeters)
@ -161,7 +161,7 @@ public class GeoShapeFieldMapper extends AbstractFieldMapper<String> {
return defaultLevels;
}
public static class TypeParser implements Mapper.TypeParser {
@Override
@ -220,7 +220,7 @@ public class GeoShapeFieldMapper extends AbstractFieldMapper<String> {
public void parse(ParseContext context) throws IOException {
try {
ShapeBuilder shape = ShapeBuilder.parse(context.parser());
if(shape == null) {
if (shape == null) {
return;
}
Field[] fields = defaultStrategy.createIndexableFields(shape.build());
@ -245,24 +245,24 @@ public class GeoShapeFieldMapper extends AbstractFieldMapper<String> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
builder.field("type", contentType());
// TODO: Come up with a better way to get the name, maybe pass it from builder
if (defaultStrategy.getGrid() instanceof GeohashPrefixTree) {
// Don't emit the tree name since GeohashPrefixTree is the default
// Only emit the tree levels if it isn't the default value
if (defaultStrategy.getGrid().getMaxLevels() != Defaults.GEOHASH_LEVELS) {
if (includeDefaults || defaultStrategy.getGrid().getMaxLevels() != Defaults.GEOHASH_LEVELS) {
builder.field(Names.TREE_LEVELS, defaultStrategy.getGrid().getMaxLevels());
}
} else {
builder.field(Names.TREE, Names.TREE_QUADTREE);
if (defaultStrategy.getGrid().getMaxLevels() != Defaults.QUADTREE_LEVELS) {
if (includeDefaults || defaultStrategy.getGrid().getMaxLevels() != Defaults.QUADTREE_LEVELS) {
builder.field(Names.TREE_LEVELS, defaultStrategy.getGrid().getMaxLevels());
}
}
if (defaultStrategy.getDistErrPct() != Defaults.DISTANCE_ERROR_PCT) {
if (includeDefaults || defaultStrategy.getDistErrPct() != Defaults.DISTANCE_ERROR_PCT) {
builder.field(Names.DISTANCE_ERROR_PCT, defaultStrategy.getDistErrPct());
}
}

View File

@ -41,6 +41,7 @@ import org.elasticsearch.index.fielddata.FieldDataType;
import org.elasticsearch.index.mapper.*;
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
import org.elasticsearch.index.query.QueryParseContext;
import org.elasticsearch.index.similarity.SimilarityLookupService;
import org.elasticsearch.index.similarity.SimilarityProvider;
import java.io.IOException;
@ -145,7 +146,7 @@ public class AllFieldMapper extends AbstractFieldMapper<Void> implements Interna
DocValuesFormatProvider docValuesProvider, SimilarityProvider similarity, @Nullable Settings fieldDataSettings,
Settings indexSettings) {
super(new Names(name, name, name, name), 1.0f, fieldType, indexAnalyzer, searchAnalyzer, postingsProvider, docValuesProvider,
similarity, fieldDataSettings, indexSettings);
similarity, fieldDataSettings, indexSettings);
this.enabled = enabled;
this.autoBoost = autoBoost;
@ -256,50 +257,78 @@ public class AllFieldMapper extends AbstractFieldMapper<Void> implements Interna
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
// if all are defaults, no need to write it at all
if (enabled == Defaults.ENABLED && fieldType.stored() == Defaults.FIELD_TYPE.stored() &&
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
if (!includeDefaults && enabled == Defaults.ENABLED && fieldType.stored() == Defaults.FIELD_TYPE.stored() &&
fieldType.storeTermVectors() == Defaults.FIELD_TYPE.storeTermVectors() &&
indexAnalyzer == null && searchAnalyzer == null && customFieldDataSettings == null) {
return builder;
}
builder.startObject(CONTENT_TYPE);
if (enabled != Defaults.ENABLED) {
if (includeDefaults || enabled != Defaults.ENABLED) {
builder.field("enabled", enabled);
}
if (autoBoost != false) {
if (includeDefaults || autoBoost != false) {
builder.field("auto_boost", autoBoost);
}
if (fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
if (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
builder.field("store", fieldType.stored());
}
if (fieldType.storeTermVectors() != Defaults.FIELD_TYPE.storeTermVectors()) {
if (includeDefaults || fieldType.storeTermVectors() != Defaults.FIELD_TYPE.storeTermVectors()) {
builder.field("store_term_vector", fieldType.storeTermVectors());
}
if (fieldType.storeTermVectorOffsets() != Defaults.FIELD_TYPE.storeTermVectorOffsets()) {
if (includeDefaults || fieldType.storeTermVectorOffsets() != Defaults.FIELD_TYPE.storeTermVectorOffsets()) {
builder.field("store_term_vector_offsets", fieldType.storeTermVectorOffsets());
}
if (fieldType.storeTermVectorPositions() != Defaults.FIELD_TYPE.storeTermVectorPositions()) {
if (includeDefaults || fieldType.storeTermVectorPositions() != Defaults.FIELD_TYPE.storeTermVectorPositions()) {
builder.field("store_term_vector_positions", fieldType.storeTermVectorPositions());
}
if (fieldType.storeTermVectorPayloads() != Defaults.FIELD_TYPE.storeTermVectorPayloads()) {
if (includeDefaults || fieldType.storeTermVectorPayloads() != Defaults.FIELD_TYPE.storeTermVectorPayloads()) {
builder.field("store_term_vector_payloads", fieldType.storeTermVectorPayloads());
}
if (indexAnalyzer != null && searchAnalyzer != null && indexAnalyzer.name().equals(searchAnalyzer.name()) && !indexAnalyzer.name().startsWith("_")) {
// same analyzers, output it once
builder.field("analyzer", indexAnalyzer.name());
} else {
if (indexAnalyzer != null && !indexAnalyzer.name().startsWith("_")) {
if (indexAnalyzer == null && searchAnalyzer == null) {
if (includeDefaults) {
builder.field("analyzer", "default");
}
} else if (indexAnalyzer == null) {
// searchAnalyzer != null
if (includeDefaults || !searchAnalyzer.name().startsWith("_")) {
builder.field("search_analyzer", searchAnalyzer.name());
}
} else if (searchAnalyzer == null) {
// indexAnalyzer != null
if (includeDefaults || !indexAnalyzer.name().startsWith("_")) {
builder.field("index_analyzer", indexAnalyzer.name());
}
if (searchAnalyzer != null && !searchAnalyzer.name().startsWith("_")) {
} else if (indexAnalyzer.name().equals(searchAnalyzer.name())) {
// indexAnalyzer == searchAnalyzer
if (includeDefaults || !indexAnalyzer.name().startsWith("_")) {
builder.field("analyzer", indexAnalyzer.name());
}
} else {
// both are there but different
if (includeDefaults || !indexAnalyzer.name().startsWith("_")) {
builder.field("index_analyzer", indexAnalyzer.name());
}
if (includeDefaults || !searchAnalyzer.name().startsWith("_")) {
builder.field("search_analyzer", searchAnalyzer.name());
}
}
if (similarity() != null) {
builder.field("similarity", similarity().name());
} else if (includeDefaults) {
builder.field("similariry", SimilarityLookupService.DEFAULT_SIMILARITY);
}
if (customFieldDataSettings != null) {
builder.field("fielddata", (Map) customFieldDataSettings.getAsMap());
} else if (includeDefaults) {
builder.field("fielddata", (Map) fieldDataType.getSettings().getAsMap());
}
builder.endObject();
return builder;
}

View File

@ -123,7 +123,7 @@ public class BoostFieldMapper extends NumberFieldMapper<Float> implements Intern
}
protected BoostFieldMapper(String name, String indexName, int precisionStep, float boost, FieldType fieldType, Float nullValue,
PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings, Settings indexSettings) {
PostingsFormatProvider postingsProvider, DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings, Settings indexSettings) {
super(new Names(name, indexName, indexName, name), precisionStep, boost, fieldType, Defaults.IGNORE_MALFORMED,
NumericFloatAnalyzer.buildNamedAnalyzer(precisionStep), NumericFloatAnalyzer.buildNamedAnalyzer(Integer.MAX_VALUE),
postingsProvider, docValuesProvider, null, fieldDataSettings, indexSettings);
@ -284,28 +284,33 @@ public class BoostFieldMapper extends NumberFieldMapper<Float> implements Intern
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// all are defaults, don't write it at all
if (name().equals(Defaults.NAME) && nullValue == null &&
fieldType.indexed() == Defaults.FIELD_TYPE.indexed() &&
if (!includeDefaults && name().equals(Defaults.NAME) && nullValue == null &&
fieldType.indexed() == Defaults.FIELD_TYPE.indexed() &&
fieldType.stored() == Defaults.FIELD_TYPE.stored() &&
customFieldDataSettings == null) {
return builder;
}
builder.startObject(contentType());
if (!name().equals(Defaults.NAME)) {
if (includeDefaults || !name().equals(Defaults.NAME)) {
builder.field("name", name());
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
}
if (includeDefaults || fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
builder.field("index", fieldType.indexed());
}
if (fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
if (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
builder.field("store", fieldType.stored());
}
if (customFieldDataSettings != null) {
builder.field("fielddata", (Map) customFieldDataSettings.getAsMap());
} else if (includeDefaults) {
builder.field("fielddata", (Map) fieldDataType.getSettings().getAsMap());
}
builder.endObject();
return builder;

View File

@ -39,7 +39,9 @@ import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatProvider;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatService;
import org.elasticsearch.index.codec.postingsformat.PostingsFormatProvider;
import org.elasticsearch.index.codec.postingsformat.PostingsFormatService;
import org.elasticsearch.index.fielddata.FieldDataType;
import org.elasticsearch.index.mapper.*;
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
@ -325,8 +327,10 @@ public class IdFieldMapper extends AbstractFieldMapper<String> implements Intern
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if all are defaults, no sense to write it at all
if (fieldType.stored() == Defaults.FIELD_TYPE.stored()
if (!includeDefaults && fieldType.stored() == Defaults.FIELD_TYPE.stored()
&& fieldType.indexed() == Defaults.FIELD_TYPE.indexed()
&& path == Defaults.PATH
&& customFieldDataSettings == null
@ -335,23 +339,44 @@ public class IdFieldMapper extends AbstractFieldMapper<String> implements Intern
return builder;
}
builder.startObject(CONTENT_TYPE);
if (fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
if (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
builder.field("store", fieldType.stored());
}
if (fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
if (includeDefaults || fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
builder.field("index", indexTokenizeOptionToString(fieldType.indexed(), fieldType.tokenized()));
}
if (path != Defaults.PATH) {
if (includeDefaults || path != Defaults.PATH) {
builder.field("path", path);
}
if (postingsFormat != null && !postingsFormat.name().equals(defaultPostingFormat())) {
builder.field("postings_format", postingsFormat.name());
if (postingsFormat != null) {
if (includeDefaults || !postingsFormat.name().equals(defaultPostingFormat())) {
builder.field("postings_format", postingsFormat.name());
}
} else if (includeDefaults) {
String format = defaultPostingFormat();
if (format == null) {
format = PostingsFormatService.DEFAULT_FORMAT;
}
builder.field("postings_format", format);
}
if (docValuesFormat != null && !docValuesFormat.name().equals(defaultDocValuesFormat())) {
builder.field(DOC_VALUES_FORMAT, docValuesFormat.name());
if (docValuesFormat != null) {
if (includeDefaults || !docValuesFormat.name().equals(defaultDocValuesFormat())) {
builder.field(DOC_VALUES_FORMAT, docValuesFormat.name());
}
} else if (includeDefaults) {
String format = defaultDocValuesFormat();
if (format == null) {
format = DocValuesFormatService.DEFAULT_FORMAT;
}
builder.field(DOC_VALUES_FORMAT, format);
}
if (customFieldDataSettings != null) {
builder.field("fielddata", (Map) customFieldDataSettings.getAsMap());
} else if (includeDefaults) {
builder.field("fielddata", (Map) fieldDataType.getSettings().getAsMap());
}
builder.endObject();
return builder;

View File

@ -195,19 +195,25 @@ public class IndexFieldMapper extends AbstractFieldMapper<String> implements Int
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if all defaults, no need to write it at all
if (fieldType().stored() == Defaults.FIELD_TYPE.stored() && enabledState == Defaults.ENABLED_STATE) {
if (!includeDefaults && fieldType().stored() == Defaults.FIELD_TYPE.stored() && enabledState == Defaults.ENABLED_STATE) {
return builder;
}
builder.startObject(CONTENT_TYPE);
if (fieldType().stored() != Defaults.FIELD_TYPE.stored() && enabledState.enabled) {
if (includeDefaults || fieldType().stored() != Defaults.FIELD_TYPE.stored() && enabledState.enabled) {
builder.field("store", fieldType().stored());
}
if (enabledState != Defaults.ENABLED_STATE) {
if (includeDefaults || enabledState != Defaults.ENABLED_STATE) {
builder.field("enabled", enabledState.enabled);
}
if (customFieldDataSettings != null) {
builder.field("fielddata", (Map) customFieldDataSettings.getAsMap());
} else if (includeDefaults) {
builder.field("fielddata", (Map) fieldDataType.getSettings().getAsMap());
}
builder.endObject();
return builder;

View File

@ -124,7 +124,7 @@ public class RoutingFieldMapper extends AbstractFieldMapper<String> implements I
}
protected RoutingFieldMapper(FieldType fieldType, boolean required, String path, PostingsFormatProvider postingsProvider,
DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings, Settings indexSettings) {
DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings, Settings indexSettings) {
super(new Names(Defaults.NAME, Defaults.NAME, Defaults.NAME, Defaults.NAME), 1.0f, fieldType, Lucene.KEYWORD_ANALYZER,
Lucene.KEYWORD_ANALYZER, postingsProvider, docValuesProvider, null, fieldDataSettings, indexSettings);
this.required = required;
@ -238,22 +238,24 @@ public class RoutingFieldMapper extends AbstractFieldMapper<String> implements I
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if all are defaults, no sense to write it at all
if (fieldType.indexed() == Defaults.FIELD_TYPE.indexed() &&
if (!includeDefaults && fieldType.indexed() == Defaults.FIELD_TYPE.indexed() &&
fieldType.stored() == Defaults.FIELD_TYPE.stored() && required == Defaults.REQUIRED && path == Defaults.PATH) {
return builder;
}
builder.startObject(CONTENT_TYPE);
if (fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
if (includeDefaults || fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
builder.field("index", indexTokenizeOptionToString(fieldType.indexed(), fieldType.tokenized()));
}
if (fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
if (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
builder.field("store", fieldType.stored());
}
if (required != Defaults.REQUIRED) {
if (includeDefaults || required != Defaults.REQUIRED) {
builder.field("required", required);
}
if (path != Defaults.PATH) {
if (includeDefaults || path != Defaults.PATH) {
builder.field("path", path);
}
builder.endObject();

View File

@ -99,7 +99,7 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper {
}
public SizeFieldMapper(EnabledAttributeMapper enabled, FieldType fieldType, PostingsFormatProvider postingsProvider,
DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings, Settings indexSettings) {
DocValuesFormatProvider docValuesProvider, @Nullable Settings fieldDataSettings, Settings indexSettings) {
super(new Names(Defaults.NAME), Defaults.PRECISION_STEP, Defaults.BOOST, fieldType, Defaults.NULL_VALUE,
Defaults.IGNORE_MALFORMED, postingsProvider, docValuesProvider, null, fieldDataSettings, indexSettings);
this.enabledState = enabled;
@ -156,15 +156,17 @@ public class SizeFieldMapper extends IntegerFieldMapper implements RootMapper {
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// all are defaults, no need to write it at all
if (enabledState == Defaults.ENABLED_STATE && fieldType().stored() == Defaults.SIZE_FIELD_TYPE.stored()) {
if (!includeDefaults && enabledState == Defaults.ENABLED_STATE && fieldType().stored() == Defaults.SIZE_FIELD_TYPE.stored()) {
return builder;
}
builder.startObject(contentType());
if (enabledState != Defaults.ENABLED_STATE) {
if (includeDefaults || enabledState != Defaults.ENABLED_STATE) {
builder.field("enabled", enabledState.enabled);
}
if (fieldType().stored() != Defaults.SIZE_FIELD_TYPE.stored() && enabledState.enabled) {
if (includeDefaults || fieldType().stored() != Defaults.SIZE_FIELD_TYPE.stored() && enabledState.enabled) {
builder.field("store", fieldType().stored());
}
builder.endObject();

View File

@ -370,29 +370,42 @@ public class SourceFieldMapper extends AbstractFieldMapper<byte[]> implements In
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// all are defaults, no need to write it at all
if (enabled == Defaults.ENABLED && compress == null && compressThreshold == -1 && includes == null && excludes == null) {
if (!includeDefaults && enabled == Defaults.ENABLED && compress == null && compressThreshold == -1 && includes == null && excludes == null) {
return builder;
}
builder.startObject(contentType());
if (enabled != Defaults.ENABLED) {
if (includeDefaults || enabled != Defaults.ENABLED) {
builder.field("enabled", enabled);
}
if (!Objects.equal(format, Defaults.FORMAT)) {
if (includeDefaults || !Objects.equal(format, Defaults.FORMAT)) {
builder.field("format", format);
}
if (compress != null) {
builder.field("compress", compress);
} else if (includeDefaults) {
builder.field("compress", false);
}
if (compressThreshold != -1) {
builder.field("compress_threshold", new ByteSizeValue(compressThreshold).toString());
} else if (includeDefaults) {
builder.field("compress_threshold", -1);
}
if (includes != null) {
builder.field("includes", includes);
} else if (includeDefaults) {
builder.field("includes", Strings.EMPTY_ARRAY);
}
if (excludes != null) {
builder.field("excludes", excludes);
} else if (includeDefaults) {
builder.field("excludes", Strings.EMPTY_ARRAY);
}
builder.endObject();
return builder;
}

View File

@ -221,15 +221,17 @@ public class TTLFieldMapper extends LongFieldMapper implements InternalMapper, R
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if all are defaults, no sense to write it at all
if (enabledState == Defaults.ENABLED_STATE && defaultTTL == Defaults.DEFAULT) {
if (!includeDefaults && enabledState == Defaults.ENABLED_STATE && defaultTTL == Defaults.DEFAULT) {
return builder;
}
builder.startObject(CONTENT_TYPE);
if (enabledState != Defaults.ENABLED_STATE) {
if (includeDefaults || enabledState != Defaults.ENABLED_STATE) {
builder.field("enabled", enabledState.enabled);
}
if (defaultTTL != Defaults.DEFAULT && enabledState.enabled) {
if (includeDefaults || defaultTTL != Defaults.DEFAULT && enabledState.enabled) {
builder.field("default", defaultTTL);
}
builder.endObject();

View File

@ -224,32 +224,37 @@ public class TimestampFieldMapper extends DateFieldMapper implements InternalMap
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if all are defaults, no sense to write it at all
if (fieldType.indexed() == Defaults.FIELD_TYPE.indexed() && customFieldDataSettings == null &&
if (!includeDefaults && fieldType.indexed() == Defaults.FIELD_TYPE.indexed() && customFieldDataSettings == null &&
fieldType.stored() == Defaults.FIELD_TYPE.stored() && enabledState == Defaults.ENABLED && path == Defaults.PATH
&& dateTimeFormatter.format().equals(Defaults.DATE_TIME_FORMATTER.format())) {
return builder;
}
builder.startObject(CONTENT_TYPE);
if (enabledState != Defaults.ENABLED) {
if (includeDefaults || enabledState != Defaults.ENABLED) {
builder.field("enabled", enabledState.enabled);
}
if (enabledState.enabled) {
if (fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
if (includeDefaults || fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
builder.field("index", indexTokenizeOptionToString(fieldType.indexed(), fieldType.tokenized()));
}
if (fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
if (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
builder.field("store", fieldType.stored());
}
if (path != Defaults.PATH) {
if (includeDefaults || path != Defaults.PATH) {
builder.field("path", path);
}
if (!dateTimeFormatter.format().equals(Defaults.DATE_TIME_FORMATTER.format())) {
if (includeDefaults || !dateTimeFormatter.format().equals(Defaults.DATE_TIME_FORMATTER.format())) {
builder.field("format", dateTimeFormatter.format());
}
if (customFieldDataSettings != null) {
builder.field("fielddata", (Map) customFieldDataSettings.getAsMap());
} else if (includeDefaults) {
builder.field("fielddata", (Map) fieldDataType.getSettings().getAsMap());
}
}
builder.endObject();
return builder;

View File

@ -194,15 +194,17 @@ public class TypeFieldMapper extends AbstractFieldMapper<String> implements Inte
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if all are defaults, no sense to write it at all
if (fieldType.stored() == Defaults.FIELD_TYPE.stored() && fieldType.indexed() == Defaults.FIELD_TYPE.indexed()) {
if (!includeDefaults && fieldType.stored() == Defaults.FIELD_TYPE.stored() && fieldType.indexed() == Defaults.FIELD_TYPE.indexed()) {
return builder;
}
builder.startObject(CONTENT_TYPE);
if (fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
if (includeDefaults || fieldType.stored() != Defaults.FIELD_TYPE.stored()) {
builder.field("store", fieldType.stored());
}
if (fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
if (includeDefaults || fieldType.indexed() != Defaults.FIELD_TYPE.indexed()) {
builder.field("index", indexTokenizeOptionToString(fieldType.indexed(), fieldType.tokenized()));
}
builder.endObject();

View File

@ -33,7 +33,9 @@ import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatProvider;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatService;
import org.elasticsearch.index.codec.postingsformat.PostingsFormatProvider;
import org.elasticsearch.index.codec.postingsformat.PostingsFormatService;
import org.elasticsearch.index.fielddata.FieldDataType;
import org.elasticsearch.index.mapper.*;
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
@ -204,8 +206,10 @@ public class UidFieldMapper extends AbstractFieldMapper<Uid> implements Internal
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
// if defaults, don't output
if (customFieldDataSettings == null
if (!includeDefaults && customFieldDataSettings == null
&& (postingsFormat == null || postingsFormat.name().equals(defaultPostingFormat()))
&& (docValuesFormat == null || docValuesFormat.name().equals(defaultDocValuesFormat()))) {
return builder;
@ -214,19 +218,33 @@ public class UidFieldMapper extends AbstractFieldMapper<Uid> implements Internal
builder.startObject(CONTENT_TYPE);
if (postingsFormat != null) {
if (!postingsFormat.name().equals(defaultPostingFormat())) {
if (includeDefaults || !postingsFormat.name().equals(defaultPostingFormat())) {
builder.field("postings_format", postingsFormat.name());
}
} else if (includeDefaults) {
String format = defaultPostingFormat();
if (format == null) {
format = PostingsFormatService.DEFAULT_FORMAT;
}
builder.field("postings_format", format);
}
if (docValuesFormat != null) {
if (!docValuesFormat.equals(defaultDocValuesFormat())) {
if (includeDefaults || !docValuesFormat.name().equals(defaultDocValuesFormat())) {
builder.field(DOC_VALUES_FORMAT, docValuesFormat.name());
}
} else if (includeDefaults) {
String format = defaultDocValuesFormat();
if (format == null) {
format = DocValuesFormatService.DEFAULT_FORMAT;
}
builder.field(DOC_VALUES_FORMAT, format);
}
if (customFieldDataSettings != null) {
builder.field("fielddata", (Map) customFieldDataSettings.getAsMap());
} else if (includeDefaults) {
builder.field("fielddata", (Map) fieldDataType.getSettings().getAsMap());
}
builder.endObject();

View File

@ -27,6 +27,7 @@ import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatProvider;
import org.elasticsearch.index.codec.docvaluesformat.DocValuesFormatService;
import org.elasticsearch.index.fielddata.FieldDataType;
import org.elasticsearch.index.mapper.*;
import org.elasticsearch.index.mapper.core.AbstractFieldMapper;
@ -169,11 +170,25 @@ public class VersionFieldMapper extends AbstractFieldMapper<Long> implements Int
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
if (docValuesFormat == null || docValuesFormat.name().equals(defaultDocValuesFormat())) {
boolean includeDefaults = params.paramAsBoolean("include_defaults", false);
if (!includeDefaults && (docValuesFormat == null || docValuesFormat.name().equals(defaultDocValuesFormat()))) {
return builder;
}
builder.startObject(CONTENT_TYPE);
builder.field(DOC_VALUES_FORMAT, docValuesFormat.name());
if (docValuesFormat != null) {
if (includeDefaults || !docValuesFormat.name().equals(defaultDocValuesFormat())) {
builder.field(DOC_VALUES_FORMAT, docValuesFormat.name());
}
} else {
String format = defaultDocValuesFormat();
if (format == null) {
format = DocValuesFormatService.DEFAULT_FORMAT;
}
builder.field(DOC_VALUES_FORMAT, format);
}
builder.endObject();
return builder;
}

View File

@ -321,17 +321,21 @@ public class IpFieldMapper extends NumberFieldMapper<Long> {
}
@Override
protected void doXContentBody(XContentBuilder builder) throws IOException {
super.doXContentBody(builder);
if (precisionStep != Defaults.PRECISION_STEP) {
protected void doXContentBody(XContentBuilder builder, boolean includeDefaults, Params params) throws IOException {
super.doXContentBody(builder, includeDefaults, params);
if (includeDefaults || precisionStep != Defaults.PRECISION_STEP) {
builder.field("precision_step", precisionStep);
}
if (nullValue != null) {
if (includeDefaults || nullValue != null) {
builder.field("null_value", nullValue);
}
if (includeInAll != null) {
builder.field("include_in_all", includeInAll);
} else if (includeDefaults) {
builder.field("include_in_all", false);
}
}
public static class NumericIpAnalyzer extends NumericAnalyzer<NumericIpTokenizer> {

View File

@ -324,6 +324,7 @@ public class MultiFieldMapper implements Mapper, AllFieldMapper.IncludeInAll {
builder.field("path", pathType.name().toLowerCase(Locale.ROOT));
}
builder.startObject("fields");
if (defaultMapper != null) {
defaultMapper.toXContent(builder, params);

View File

@ -21,7 +21,8 @@ package org.elasticsearch.index.similarity;
import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMap;
import org.apache.lucene.search.similarities.*;
import org.apache.lucene.search.similarities.BM25Similarity;
import org.apache.lucene.search.similarities.DefaultSimilarity;
import org.elasticsearch.common.collect.MapBuilder;
/**
@ -33,7 +34,8 @@ public class Similarities {
static {
MapBuilder<String, PreBuiltSimilarityProvider.Factory> similarities = MapBuilder.newMapBuilder();
similarities.put("default", new PreBuiltSimilarityProvider.Factory("default", new DefaultSimilarity()));
similarities.put(SimilarityLookupService.DEFAULT_SIMILARITY,
new PreBuiltSimilarityProvider.Factory(SimilarityLookupService.DEFAULT_SIMILARITY, new DefaultSimilarity()));
similarities.put("BM25", new PreBuiltSimilarityProvider.Factory("BM25", new BM25Similarity()));
PRE_BUILT_SIMILARITIES = similarities.immutableMap();

View File

@ -32,16 +32,18 @@ import java.util.Map;
/**
* Service for looking up configured {@link SimilarityProvider} implementations by name.
*
* <p/>
* The service instantiates the Providers through their Factories using configuration
* values found with the {@link SimilarityModule#SIMILARITY_SETTINGS_PREFIX} prefix.
*/
public class SimilarityLookupService extends AbstractIndexComponent {
public final static String DEFAULT_SIMILARITY = "default";
private final ImmutableMap<String, SimilarityProvider> similarities;
public SimilarityLookupService(Index index, Settings indexSettings) {
this (index, indexSettings, ImmutableMap.<String, SimilarityProvider.Factory>of());
this(index, indexSettings, ImmutableMap.<String, SimilarityProvider.Factory>of());
}
@Inject

View File

@ -22,7 +22,6 @@ package org.elasticsearch.index.similarity;
import org.apache.lucene.search.similarities.PerFieldSimilarityWrapper;
import org.apache.lucene.search.similarities.Similarity;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.inject.name.Named;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.index.AbstractIndexComponent;
@ -46,7 +45,7 @@ public class SimilarityService extends AbstractIndexComponent {
}
public SimilarityService(Index index, Settings settings) {
this (index, settings, new SimilarityLookupService(index, settings), null);
this(index, settings, new SimilarityLookupService(index, settings), null);
}
@Inject
@ -56,7 +55,7 @@ public class SimilarityService extends AbstractIndexComponent {
this.similarityLookupService = similarityLookupService;
this.mapperService = mapperService;
Similarity defaultSimilarity = similarityLookupService.similarity("default").get();
Similarity defaultSimilarity = similarityLookupService.similarity(SimilarityLookupService.DEFAULT_SIMILARITY).get();
// Expert users can configure the base type as being different to default, but out-of-box we use default.
Similarity baseSimilarity = (similarityLookupService.similarity("base") != null) ? similarityLookupService.similarity("base").get() :
defaultSimilarity;

View File

@ -50,6 +50,7 @@ import org.elasticsearch.rest.action.admin.indices.exists.types.RestTypesExistsA
import org.elasticsearch.rest.action.admin.indices.flush.RestFlushAction;
import org.elasticsearch.rest.action.admin.indices.gateway.snapshot.RestGatewaySnapshotAction;
import org.elasticsearch.rest.action.admin.indices.mapping.delete.RestDeleteMappingAction;
import org.elasticsearch.rest.action.admin.indices.mapping.get.RestGetFieldMappingAction;
import org.elasticsearch.rest.action.admin.indices.mapping.get.RestGetMappingAction;
import org.elasticsearch.rest.action.admin.indices.mapping.put.RestPutMappingAction;
import org.elasticsearch.rest.action.admin.indices.open.RestOpenIndexAction;
@ -161,6 +162,7 @@ public class RestActionModule extends AbstractModule {
bind(RestPutMappingAction.class).asEagerSingleton();
bind(RestDeleteMappingAction.class).asEagerSingleton();
bind(RestGetMappingAction.class).asEagerSingleton();
bind(RestGetFieldMappingAction.class).asEagerSingleton();
bind(RestGatewaySnapshotAction.class).asEagerSingleton();

View File

@ -0,0 +1,97 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.rest.action.admin.indices.mapping.get;
import com.google.common.collect.ImmutableMap;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse.FieldMappingMetaData;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.rest.*;
import org.elasticsearch.rest.action.support.RestXContentBuilder;
import java.io.IOException;
import static org.elasticsearch.rest.RestRequest.Method.GET;
import static org.elasticsearch.rest.RestStatus.NOT_FOUND;
import static org.elasticsearch.rest.RestStatus.OK;
/**
*
*/
public class RestGetFieldMappingAction extends BaseRestHandler {
@Inject
public RestGetFieldMappingAction(Settings settings, Client client, RestController controller) {
super(settings, client);
controller.registerHandler(GET, "/_mapping/field/{fields}", this);
controller.registerHandler(GET, "/{index}/_mapping/field/{fields}", this);
controller.registerHandler(GET, "/{index}/{type}/_mapping/field/{fields}", this);
}
@Override
public void handleRequest(final RestRequest request, final RestChannel channel) {
final String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
final String[] types = Strings.splitStringByCommaToArray(request.param("type"));
boolean local = request.paramAsBooleanOptional("local", false);
final String[] fields = Strings.splitStringByCommaToArray(request.param("fields"));
GetFieldMappingsRequest getMappingsRequest = new GetFieldMappingsRequest();
getMappingsRequest.indices(indices).types(types).local(local).fields(fields).includeDefaults(request.paramAsBoolean("include_defaults", false));
client.admin().indices().getFieldMappings(getMappingsRequest, new ActionListener<GetFieldMappingsResponse>() {
@SuppressWarnings("unchecked")
@Override
public void onResponse(GetFieldMappingsResponse response) {
try {
XContentBuilder builder = RestXContentBuilder.restContentBuilder(request);
builder.startObject();
ImmutableMap<String, ImmutableMap<String, ImmutableMap<String, FieldMappingMetaData>>> mappingsByIndex = response.mappings();
RestStatus status = OK;
if (mappingsByIndex.isEmpty() && fields.length > 0) {
status = NOT_FOUND;
}
response.toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
channel.sendResponse(new XContentRestResponse(request, status, builder));
} catch (Throwable e) {
onFailure(e);
}
}
@Override
public void onFailure(Throwable e) {
try {
channel.sendResponse(new XContentThrowableRestResponse(request, e));
} catch (IOException e1) {
logger.error("Failed to send failure response", e1);
}
}
});
}
}

View File

@ -25,7 +25,6 @@ import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsRequest;
import org.elasticsearch.action.admin.indices.mapping.get.GetMappingsResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.MappingMetaData;
import org.elasticsearch.cluster.metadata.MetaData;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.settings.Settings;
@ -60,7 +59,6 @@ public class RestGetMappingAction extends BaseRestHandler {
final String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
final String[] types = Strings.splitStringByCommaToArray(request.param("type"));
boolean local = request.paramAsBooleanOptional("local", false);
GetMappingsRequest getMappingsRequest = new GetMappingsRequest();
getMappingsRequest.indices(indices).types(types).local(local);
client.admin().indices().getMappings(getMappingsRequest, new ActionListener<GetMappingsResponse>() {

View File

@ -19,6 +19,7 @@
package org.elasticsearch.index.mapper.routing;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.json.JsonXContent;
@ -31,7 +32,6 @@ import org.junit.Test;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
/**
@ -59,9 +59,9 @@ public class RoutingTypeMapperTests extends ElasticsearchTestCase {
public void testSetValues() throws Exception {
String mapping = XContentFactory.jsonBuilder().startObject().startObject("type")
.startObject("_routing")
.field("store", "no")
.field("index", "no")
.field("path", "route")
.field("store", "no")
.field("index", "no")
.field("path", "route")
.endObject()
.endObject().endObject().string();
DocumentMapper docMapper = MapperTestUtils.newParser().parse(mapping);
@ -78,7 +78,7 @@ public class RoutingTypeMapperTests extends ElasticsearchTestCase {
DocumentMapper enabledMapper = MapperTestUtils.newParser().parse(enabledMapping);
XContentBuilder builder = JsonXContent.contentBuilder().startObject();
enabledMapper.routingFieldMapper().toXContent(builder, null).endObject();
enabledMapper.routingFieldMapper().toXContent(builder, ToXContent.EMPTY_PARAMS).endObject();
builder.close();
Map<String, Object> serializedMap = JsonXContent.jsonXContent.createParser(builder.bytes()).mapAndClose();
assertThat(serializedMap, hasKey("_routing"));

View File

@ -20,6 +20,7 @@
package org.elasticsearch.index.mapper.timestamp;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.xcontent.ToXContent;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.json.JsonXContent;
@ -34,7 +35,6 @@ import org.junit.Test;
import java.util.Locale;
import java.util.Map;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.*;
/**
@ -128,7 +128,7 @@ public class TimestampMappingTests extends ElasticsearchTestCase {
DocumentMapper mapper = MapperTestUtils.newParser().parse(mapping);
XContentBuilder builder = XContentFactory.jsonBuilder().startObject();
mapper.timestampFieldMapper().toXContent(builder, null);
mapper.timestampFieldMapper().toXContent(builder, ToXContent.EMPTY_PARAMS);
builder.endObject();
assertThat(builder.string(), is(String.format(Locale.ROOT, "{\"%s\":{}}", TimestampFieldMapper.NAME)));
@ -142,7 +142,7 @@ public class TimestampMappingTests extends ElasticsearchTestCase {
DocumentMapper enabledMapper = MapperTestUtils.newParser().parse(enabledMapping);
XContentBuilder builder = JsonXContent.contentBuilder().startObject();
enabledMapper.timestampFieldMapper().toXContent(builder, null).endObject();
enabledMapper.timestampFieldMapper().toXContent(builder, ToXContent.EMPTY_PARAMS).endObject();
builder.close();
Map<String, Object> serializedMap = JsonXContent.jsonXContent.createParser(builder.bytes()).mapAndClose();
assertThat(serializedMap, hasKey("_timestamp"));

View File

@ -0,0 +1,156 @@
/*
* Licensed to ElasticSearch and Shay Banon under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. ElasticSearch licenses this
* file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.indices.mapping;
import com.google.common.base.Predicate;
import org.elasticsearch.action.admin.indices.mapping.get.GetFieldMappingsResponse;
import org.elasticsearch.common.Nullable;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.test.AbstractIntegrationTest;
import org.hamcrest.Matchers;
import org.junit.Test;
import java.io.IOException;
import java.util.Map;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.hamcrest.Matchers.*;
/**
*
*/
public class SimpleGetFieldMappingsTests extends AbstractIntegrationTest {
@Test
public void getMappingsWhereThereAreNone() {
createIndex("index");
GetFieldMappingsResponse response = client().admin().indices().prepareGetFieldMappings().get();
assertThat(response.mappings().size(), equalTo(0));
assertThat(response.fieldMappings("index", "type", "field"), Matchers.nullValue());
}
private XContentBuilder getMappingForType(String type) throws IOException {
return jsonBuilder().startObject().startObject(type).startObject("properties")
.startObject("field1").field("type", "string").endObject()
.startObject("obj").startObject("properties").startObject("subfield").field("type", "string").field("index", "not_analyzed").endObject().endObject().endObject()
.endObject().endObject().endObject();
}
@Test
public void simpleGetFieldMappings() throws Exception {
assertTrue(client().admin().indices().prepareCreate("indexa")
.addMapping("typeA", getMappingForType("typeA"))
.addMapping("typeB", getMappingForType("typeB"))
.get().isAcknowledged());
assertTrue(client().admin().indices().prepareCreate("indexb")
.addMapping("typeA", getMappingForType("typeA"))
.addMapping("typeB", getMappingForType("typeB"))
.get().isAcknowledged());
// Get mappings by full name
GetFieldMappingsResponse response = client().admin().indices().prepareGetFieldMappings("indexa").setTypes("typeA").setFields("field1", "obj.subfield").get();
assertThat(response.fieldMappings("indexa", "typeA", "field1").fullName(), equalTo("field1"));
assertThat(response.fieldMappings("indexa", "typeA", "field1").sourceAsMap(), hasKey("field1"));
assertThat(response.fieldMappings("indexa", "typeA", "obj.subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexa", "typeA", "obj.subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.mappings().get("indexa"), not(hasKey("typeB")));
assertThat(response.fieldMappings("indexa", "typeB", "field1"), nullValue());
assertThat(response.mappings(), not(hasKey("indexb")));
assertThat(response.fieldMappings("indexb", "typeB", "field1"), nullValue());
// Get mappings by name
response = client().admin().indices().prepareGetFieldMappings("indexa").setTypes("typeA").setFields("field1", "subfield").get();
assertThat(response.fieldMappings("indexa", "typeA", "field1").fullName(), equalTo("field1"));
assertThat(response.fieldMappings("indexa", "typeA", "field1").sourceAsMap(), hasKey("field1"));
assertThat(response.fieldMappings("indexa", "typeA", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexa", "typeA", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexa", "typeB", "field1"), nullValue());
assertThat(response.fieldMappings("indexb", "typeB", "field1"), nullValue());
// get mappings by name across multiple indices
response = client().admin().indices().prepareGetFieldMappings().setTypes("typeA").setFields("subfield").get();
assertThat(response.fieldMappings("indexa", "typeA", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexa", "typeA", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexa", "typeB", "subfield"), nullValue());
assertThat(response.fieldMappings("indexb", "typeA", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexb", "typeA", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexb", "typeB", "subfield"), nullValue());
// get mappings by name across multiple types
response = client().admin().indices().prepareGetFieldMappings("indexa").setFields("subfield").get();
assertThat(response.fieldMappings("indexa", "typeA", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexa", "typeA", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexa", "typeA", "field1"), nullValue());
assertThat(response.fieldMappings("indexa", "typeB", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexa", "typeB", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexa", "typeB", "field1"), nullValue());
assertThat(response.fieldMappings("indexb", "typeA", "subfield"), nullValue());
assertThat(response.fieldMappings("indexb", "typeA", "field1"), nullValue());
assertThat(response.fieldMappings("indexb", "typeB", "subfield"), nullValue());
assertThat(response.fieldMappings("indexb", "typeB", "field1"), nullValue());
// get mappings by name across multiple types & indices
response = client().admin().indices().prepareGetFieldMappings().setFields("subfield").get();
assertThat(response.fieldMappings("indexa", "typeA", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexa", "typeA", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexa", "typeA", "field1"), nullValue());
assertThat(response.fieldMappings("indexa", "typeB", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexa", "typeB", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexa", "typeB", "field1"), nullValue());
assertThat(response.fieldMappings("indexb", "typeA", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexb", "typeA", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexb", "typeB", "field1"), nullValue());
assertThat(response.fieldMappings("indexb", "typeB", "subfield").fullName(), equalTo("obj.subfield"));
assertThat(response.fieldMappings("indexb", "typeB", "subfield").sourceAsMap(), hasKey("subfield"));
assertThat(response.fieldMappings("indexb", "typeB", "field1"), nullValue());
}
@SuppressWarnings("unchecked")
@Test
public void simpleGetFieldMappingsWithDefaults() throws Exception {
client().admin().indices().prepareCreate("test")
.addMapping("type", getMappingForType("type")).get();
client().prepareIndex("test", "type", "1").setSource("num", 1).get();
awaitBusy(new Predicate<Object>() {
@Override
public boolean apply(@Nullable java.lang.Object input) {
GetFieldMappingsResponse response = client().admin().indices().prepareGetFieldMappings().setFields("num").get();
return response.fieldMappings("test", "type", "num") != null;
}
});
GetFieldMappingsResponse response = client().admin().indices().prepareGetFieldMappings().setFields("num", "field1", "subfield").includeDefaults(true).get();
assertThat((Map<String, Object>) response.fieldMappings("test", "type", "num").sourceAsMap().get("num"), hasEntry("index", (Object) "not_analyzed"));
assertThat((Map<String, Object>) response.fieldMappings("test", "type", "num").sourceAsMap().get("num"), hasEntry("type", (Object) "long"));
assertThat((Map<String, Object>) response.fieldMappings("test", "type", "field1").sourceAsMap().get("field1"), hasEntry("index", (Object) "analyzed"));
assertThat((Map<String, Object>) response.fieldMappings("test", "type", "field1").sourceAsMap().get("field1"), hasEntry("type", (Object) "string"));
assertThat((Map<String, Object>) response.fieldMappings("test", "type", "subfield").sourceAsMap().get("subfield"), hasEntry("index", (Object) "not_analyzed"));
assertThat((Map<String, Object>) response.fieldMappings("test", "type", "subfield").sourceAsMap().get("subfield"), hasEntry("type", (Object) "string"));
}
}