Support include_type_name in the field mapping and index template APIs. (#37210)

* Add include_type_name to the get field mappings API.
* Make sure the API specification lists include_type_name as a boolean.
* Add include_type_name to the get index templates API.
* Add include_type_name to the put index templates API.
This commit is contained in:
Julie Tibshirani 2019-01-10 09:24:08 -08:00 committed by GitHub
parent 9de62f1262
commit a433c4012c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 811 additions and 136 deletions

View File

@ -14,7 +14,7 @@
},
"params": {
"include_type_name": {
"type" : "string",
"type" : "boolean",
"description" : "Whether a type should be expected in the body of the mappings."
},
"wait_for_active_shards": {

View File

@ -21,6 +21,10 @@
}
},
"params": {
"include_type_name": {
"type" : "boolean",
"description" : "Whether a type should be returned in the body of the mappings."
},
"include_defaults": {
"type" : "boolean",
"description" : "Whether the default mapping values should be returned as well"

View File

@ -17,7 +17,7 @@
},
"params": {
"include_type_name": {
"type" : "string",
"type" : "boolean",
"description" : "Whether to add the type name to the response"
},
"ignore_unavailable": {

View File

@ -16,6 +16,10 @@
}
},
"params": {
"include_type_name": {
"type" : "boolean",
"description" : "Whether a type should be returned in the body of the mappings."
},
"flat_settings": {
"type": "boolean",
"description": "Return settings in flat format (default: false)"

View File

@ -17,7 +17,7 @@
},
"params": {
"include_type_name": {
"type" : "string",
"type" : "boolean",
"description" : "Whether a type should be expected in the body of the mappings."
},
"timeout": {

View File

@ -13,6 +13,10 @@
}
},
"params": {
"include_type_name": {
"type" : "boolean",
"description" : "Whether a type should be returned in the body of the mappings."
},
"order": {
"type" : "number",
"description" : "The order for this template when merging multiple matching ones (higher numbers are merged later, overriding the lower numbers)"

View File

@ -1,54 +1,48 @@
---
setup:
- skip:
version: " - 6.99.99"
reason: include_type_name is not supported before 7.0.0
- do:
indices.create:
include_type_name: false
index: test_index
body:
mappings:
test_type:
properties:
text:
type: text
properties:
text:
type: text
---
"Get field mapping with no index and type":
"Get field mapping with no index":
- do:
indices.get_field_mapping:
include_type_name: false
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
- match: {test_index.mappings.text.mapping.text.type: text}
---
"Get field mapping by index only":
- do:
indices.get_field_mapping:
include_type_name: false
index: test_index
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
- match: {test_index.mappings.text.mapping.text.type: text}
---
"Get field mapping by type & field":
"Get field mapping by field, with another field that doesn't exist":
- do:
indices.get_field_mapping:
include_type_name: false
index: test_index
type: test_type
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
---
"Get field mapping by type & field, with another field that doesn't exist":
- do:
indices.get_field_mapping:
index: test_index
type: test_type
fields: [ text , text1 ]
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
- match: {test_index.mappings.text.mapping.text.type: text}
- is_false: test_index.mappings.test_type.text1
---
@ -56,21 +50,10 @@ setup:
- do:
indices.get_field_mapping:
include_type_name: false
index: test_index
type: test_type
fields: text
include_defaults: true
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
- match: {test_index.mappings.test_type.text.mapping.text.analyzer: default}
---
"Get field mapping should work without index specifying type and fields":
- do:
indices.get_field_mapping:
type: test_type
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
- match: {test_index.mappings.text.mapping.text.type: text}
- match: {test_index.mappings.text.mapping.text.analyzer: default}

View File

@ -0,0 +1,76 @@
---
setup:
- do:
indices.create:
index: test_index
body:
mappings:
test_type:
properties:
text:
type: text
---
"Get field mapping with no index and type":
- do:
indices.get_field_mapping:
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
---
"Get field mapping by index only":
- do:
indices.get_field_mapping:
index: test_index
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
---
"Get field mapping by type & field":
- do:
indices.get_field_mapping:
index: test_index
type: test_type
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
---
"Get field mapping by type & field, with another field that doesn't exist":
- do:
indices.get_field_mapping:
index: test_index
type: test_type
fields: [ text , text1 ]
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
- is_false: test_index.mappings.test_type.text1
---
"Get field mapping with include_defaults":
- do:
indices.get_field_mapping:
index: test_index
type: test_type
fields: text
include_defaults: true
- match: {test_index.mappings.test_type.text.mapping.text.type: text}
- match: {test_index.mappings.test_type.text.mapping.text.analyzer: default}
---
"Get field mapping should work without index specifying type and fields":
- do:
indices.get_field_mapping:
type: test_type
fields: text
- match: {test_index.mappings.test_type.text.mapping.text.type: text}

View File

@ -1,21 +1,22 @@
---
"Return empty object if field doesn't exist, but type and index do":
- skip:
version: " - 6.99.99"
reason: types are required in requests before 7.0.0
- do:
indices.create:
include_type_name: false
index: test_index
body:
mappings:
test_type:
properties:
text:
type: text
analyzer: whitespace
mappings:
properties:
text:
type: text
analyzer: whitespace
- do:
indices.get_field_mapping:
index: test_index
type: test_type
fields: not_existent
- match: { '': {}}
- match: { 'test_index.mappings': {}}

View File

@ -0,0 +1,21 @@
---
"Return empty object if field doesn't exist, but type and index do":
- do:
indices.create:
index: test_index
body:
mappings:
test_type:
properties:
text:
type: text
analyzer: whitespace
- do:
indices.get_field_mapping:
index: test_index
type: test_type
fields: not_existent
- match: { '': {}}

View File

@ -5,7 +5,6 @@
catch: missing
indices.get_field_mapping:
index: test_index
type: type
fields: field

View File

@ -1,135 +1,142 @@
---
setup:
- skip:
version: " - 6.99.99"
reason: types are required in requests before 7.0.0
- do:
indices.create:
include_type_name: false
index: test_index
body:
mappings:
test_type:
properties:
t1:
type: text
t2:
type: text
obj:
properties:
t1:
type: text
i_t1:
type: text
i_t3:
type: text
properties:
t1:
type: text
t2:
type: text
obj:
properties:
t1:
type: text
i_t1:
type: text
i_t3:
type: text
- do:
indices.create:
include_type_name: false
index: test_index_2
body:
mappings:
test_type_2:
properties:
t1:
type: text
t2:
type: text
obj:
properties:
t1:
type: text
i_t1:
type: text
i_t3:
type: text
properties:
t1:
type: text
t2:
type: text
obj:
properties:
t1:
type: text
i_t1:
type: text
i_t3:
type: text
---
"Get field mapping with * for fields":
- do:
indices.get_field_mapping:
include_type_name: false
fields: "*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- match: {test_index.mappings.test_type.obj\.t1.full_name: obj.t1 }
- match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.test_type.obj\.i_t3.full_name: obj.i_t3 }
- match: {test_index.mappings.t1.full_name: t1 }
- match: {test_index.mappings.t2.full_name: t2 }
- match: {test_index.mappings.obj\.t1.full_name: obj.t1 }
- match: {test_index.mappings.obj\.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.obj\.i_t3.full_name: obj.i_t3 }
---
"Get field mapping with t* for fields":
- do:
indices.get_field_mapping:
include_type_name: false
index: test_index
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index.mappings.t1.full_name: t1 }
- match: {test_index.mappings.t2.full_name: t2 }
- length: {test_index.mappings: 2}
---
"Get field mapping with *t1 for fields":
- do:
indices.get_field_mapping:
include_type_name: false
index: test_index
fields: "*t1"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.obj\.t1.full_name: obj.t1 }
- match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- length: {test_index.mappings.test_type: 3}
- match: {test_index.mappings.t1.full_name: t1 }
- match: {test_index.mappings.obj\.t1.full_name: obj.t1 }
- match: {test_index.mappings.obj\.i_t1.full_name: obj.i_t1 }
- length: {test_index.mappings: 3}
---
"Get field mapping with wildcarded relative names":
- do:
indices.get_field_mapping:
include_type_name: false
index: test_index
fields: "obj.i_*"
- match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.test_type.obj\.i_t3.full_name: obj.i_t3 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index.mappings.obj\.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.obj\.i_t3.full_name: obj.i_t3 }
- length: {test_index.mappings: 2}
---
"Get field mapping should work using '_all' for indices and types":
"Get field mapping should work using '_all' for index":
- do:
indices.get_field_mapping:
include_type_name: false
index: _all
type: _all
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.t1.full_name: t1 }
- match: {test_index_2.mappings.test_type_2.t2.full_name: t2 }
- length: {test_index_2.mappings.test_type_2: 2}
- match: {test_index.mappings.t1.full_name: t1 }
- match: {test_index.mappings.t2.full_name: t2 }
- length: {test_index.mappings: 2}
- match: {test_index_2.mappings.t1.full_name: t1 }
- match: {test_index_2.mappings.t2.full_name: t2 }
- length: {test_index_2.mappings: 2}
---
"Get field mapping should work using '*' for indices and types":
"Get field mapping should work using '*' for index":
- do:
indices.get_field_mapping:
include_type_name: false
index: '*'
type: '*'
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.t1.full_name: t1 }
- match: {test_index_2.mappings.test_type_2.t2.full_name: t2 }
- length: {test_index_2.mappings.test_type_2: 2}
- match: {test_index.mappings.t1.full_name: t1 }
- match: {test_index.mappings.t2.full_name: t2 }
- length: {test_index.mappings: 2}
- match: {test_index_2.mappings.t1.full_name: t1 }
- match: {test_index_2.mappings.t2.full_name: t2 }
- length: {test_index_2.mappings: 2}
---
"Get field mapping should work using comma_separated values for indices and types":
"Get field mapping should work using comma_separated values for indices":
- do:
indices.get_field_mapping:
include_type_name: false
index: 'test_index,test_index_2'
type: 'test_type,test_type_2'
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.t1.full_name: t1 }
- match: {test_index_2.mappings.test_type_2.t2.full_name: t2 }
- length: {test_index_2.mappings.test_type_2: 2}
- match: {test_index.mappings.t1.full_name: t1 }
- match: {test_index.mappings.t2.full_name: t2 }
- length: {test_index.mappings: 2}
- match: {test_index_2.mappings.t1.full_name: t1 }
- match: {test_index_2.mappings.t2.full_name: t2 }
- length: {test_index_2.mappings: 2}

View File

@ -0,0 +1,135 @@
---
setup:
- do:
indices.create:
index: test_index
body:
mappings:
test_type:
properties:
t1:
type: text
t2:
type: text
obj:
properties:
t1:
type: text
i_t1:
type: text
i_t3:
type: text
- do:
indices.create:
index: test_index_2
body:
mappings:
test_type_2:
properties:
t1:
type: text
t2:
type: text
obj:
properties:
t1:
type: text
i_t1:
type: text
i_t3:
type: text
---
"Get field mapping with * for fields":
- do:
indices.get_field_mapping:
fields: "*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- match: {test_index.mappings.test_type.obj\.t1.full_name: obj.t1 }
- match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.test_type.obj\.i_t3.full_name: obj.i_t3 }
---
"Get field mapping with t* for fields":
- do:
indices.get_field_mapping:
index: test_index
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
---
"Get field mapping with *t1 for fields":
- do:
indices.get_field_mapping:
index: test_index
fields: "*t1"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.obj\.t1.full_name: obj.t1 }
- match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- length: {test_index.mappings.test_type: 3}
---
"Get field mapping with wildcarded relative names":
- do:
indices.get_field_mapping:
index: test_index
fields: "obj.i_*"
- match: {test_index.mappings.test_type.obj\.i_t1.full_name: obj.i_t1 }
- match: {test_index.mappings.test_type.obj\.i_t3.full_name: obj.i_t3 }
- length: {test_index.mappings.test_type: 2}
---
"Get field mapping should work using '_all' for indices and types":
- do:
indices.get_field_mapping:
index: _all
type: _all
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.t1.full_name: t1 }
- match: {test_index_2.mappings.test_type_2.t2.full_name: t2 }
- length: {test_index_2.mappings.test_type_2: 2}
---
"Get field mapping should work using '*' for indices and types":
- do:
indices.get_field_mapping:
index: '*'
type: '*'
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.t1.full_name: t1 }
- match: {test_index_2.mappings.test_type_2.t2.full_name: t2 }
- length: {test_index_2.mappings.test_type_2: 2}
---
"Get field mapping should work using comma_separated values for indices and types":
- do:
indices.get_field_mapping:
index: 'test_index,test_index_2'
type: 'test_type,test_type_2'
fields: "t*"
- match: {test_index.mappings.test_type.t1.full_name: t1 }
- match: {test_index.mappings.test_type.t2.full_name: t2 }
- length: {test_index.mappings.test_type: 2}
- match: {test_index_2.mappings.test_type_2.t1.full_name: t1 }
- match: {test_index_2.mappings.test_type_2.t2.full_name: t2 }
- length: {test_index_2.mappings.test_type_2: 2}

View File

@ -0,0 +1,24 @@
---
"GET mapping with typeless API on an index that has types":
- skip:
version: " - 6.99.99"
reason: include_type_name was introduced in 7.0.0
- do:
indices.create: # not using include_type_name: false on purpose
index: index
body:
mappings:
not_doc:
properties:
foo:
type: "keyword"
- do:
indices.get_field_mapping:
include_type_name: false
index: index
fields: foo
- match: { index.mappings.foo.mapping.foo.type: "keyword" }

View File

@ -1,4 +1,7 @@
setup:
- skip:
version: " - 6.99.99"
reason: include_type_name is not supported before 7.0.0
- do:
indices.put_template:
name: test
@ -7,16 +10,44 @@ setup:
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
_doc:
properties:
field:
type: keyword
---
"Get template":
- do:
indices.get_template:
include_type_name: false
name: test
- match: {test.index_patterns: ["test-*"]}
- match: {test.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
- match: {test.mappings: {properties: {field: {type: keyword}}}}
---
"Get template with no mappings":
- do:
indices.put_template:
name: test_no_mappings
body:
index_patterns: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
indices.get_template:
include_type_name: false
name: test_no_mappings
- match: {test_no_mappings.index_patterns: ["test-*"]}
- match: {test_no_mappings.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
- match: {test_no_mappings.mappings: {}}
---
"Get all templates":

View File

@ -0,0 +1,45 @@
setup:
- do:
indices.put_template:
name: test
body:
index_patterns: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
_doc:
properties:
field:
type: keyword
---
"Get template":
- do:
indices.get_template:
name: test
- match: {test.index_patterns: ["test-*"]}
- match: {test.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
- match: {test.mappings: {_doc: {properties: {field: {type: keyword}}}}}
---
"Get template with no mappings":
- do:
indices.put_template:
name: test_no_mappings
body:
index_patterns: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
- do:
indices.get_template:
name: test_no_mappings
- match: {test_no_mappings.index_patterns: ["test-*"]}
- match: {test_no_mappings.settings: {index: {number_of_shards: '1', number_of_replicas: '0'}}}
- match: {test_no_mappings.mappings: {}}

View File

@ -1,42 +1,87 @@
---
"Put template":
- skip:
version: " - 6.99.99"
reason: include_type_name is not supported before 7.0.0
- do:
indices.put_template:
include_type_name: false
name: test
body:
index_patterns: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
properties:
field:
type: keyword
- do:
indices.get_template:
include_type_name: false
name: test
flat_settings: true
- match: {test.index_patterns: ["test-*"]}
- match: {test.settings: {index.number_of_shards: '1', index.number_of_replicas: '0'}}
- match: {test.mappings: {properties: {field: {type: keyword}}}}
---
"Put multiple template":
- skip:
version: " - 6.99.99"
reason: include_type_name was introduced in 7.0.0
- do:
indices.put_template:
include_type_name: false
name: test
body:
index_patterns: [test-*, test2-*]
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
properties:
field:
type: text
- do:
indices.get_template:
include_type_name: false
name: test
flat_settings: true
- match: {test.index_patterns: ["test-*", "test2-*"]}
- match: {test.settings: {index.number_of_shards: '1', index.number_of_replicas: '0'}}
- match: {test.mappings: {properties: {field: {type: text}}}}
---
"Put template with empty mappings":
- skip:
version: " - 6.99.99"
reason: include_type_name was introduced in 7.0.0
- do:
indices.put_template:
include_type_name: false
name: test
body:
index_patterns: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
mappings: {}
- do:
indices.get_template:
include_type_name: false
name: test
flat_settings: true
- match: {test.mappings: {}}
---
"Put template with aliases":

View File

@ -0,0 +1,68 @@
---
"Put template":
- do:
indices.put_template:
name: test
body:
index_patterns: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
_doc:
properties:
field:
type: keyword
- do:
indices.get_template:
name: test
flat_settings: true
- match: {test.index_patterns: ["test-*"]}
- match: {test.settings: {index.number_of_shards: '1', index.number_of_replicas: '0'}}
- match: {test.mappings: {_doc: {properties: {field: {type: keyword}}}}}
---
"Put multiple template":
- do:
indices.put_template:
name: test
body:
index_patterns: [test-*, test2-*]
settings:
number_of_shards: 1
number_of_replicas: 0
mappings:
_doc:
properties:
field:
type: text
- do:
indices.get_template:
name: test
flat_settings: true
- match: {test.index_patterns: ["test-*", "test2-*"]}
- match: {test.settings: {index.number_of_shards: '1', index.number_of_replicas: '0'}}
- match: {test.mappings: {_doc: {properties: {field: {type: text}}}}}
---
"Put template with empty mappings":
- do:
indices.put_template:
name: test
body:
index_patterns: test-*
settings:
number_of_shards: 1
number_of_replicas: 0
mappings: {}
- do:
indices.get_template:
name: test
flat_settings: true
- match: {test.mappings: {}}

View File

@ -34,6 +34,8 @@ import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.mapper.Mapper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.rest.BaseRestHandler;
import java.io.IOException;
import java.io.InputStream;
@ -112,19 +114,32 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
@Override
public XContentBuilder toXContent(XContentBuilder builder, Params params) throws IOException {
boolean includeTypeName = params.paramAsBoolean(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, true);
builder.startObject();
for (Map.Entry<String, Map<String, Map<String, FieldMappingMetaData>>> indexEntry : mappings.entrySet()) {
builder.startObject(indexEntry.getKey());
builder.startObject(MAPPINGS.getPreferredName());
for (Map.Entry<String, Map<String, FieldMappingMetaData>> typeEntry : indexEntry.getValue().entrySet()) {
builder.startObject(typeEntry.getKey());
for (Map.Entry<String, FieldMappingMetaData> fieldEntry : typeEntry.getValue().entrySet()) {
builder.startObject(fieldEntry.getKey());
fieldEntry.getValue().toXContent(builder, params);
if (includeTypeName == false) {
Map<String, FieldMappingMetaData> mappings = null;
for (Map.Entry<String, Map<String, FieldMappingMetaData>> typeEntry : indexEntry.getValue().entrySet()) {
if (typeEntry.getKey().equals(MapperService.DEFAULT_MAPPING) == false) {
assert mappings == null;
mappings = typeEntry.getValue();
}
}
if (mappings != null) {
addFieldMappingsToBuilder(builder, params, mappings);
}
} else {
for (Map.Entry<String, Map<String, FieldMappingMetaData>> typeEntry : indexEntry.getValue().entrySet()) {
builder.startObject(typeEntry.getKey());
addFieldMappingsToBuilder(builder, params, typeEntry.getValue());
builder.endObject();
}
builder.endObject();
}
builder.endObject();
builder.endObject();
}
@ -132,6 +147,16 @@ public class GetFieldMappingsResponse extends ActionResponse implements ToXConte
return builder;
}
private void addFieldMappingsToBuilder(XContentBuilder builder,
Params params,
Map<String, FieldMappingMetaData> mappings) throws IOException {
for (Map.Entry<String, FieldMappingMetaData> fieldEntry : mappings.entrySet()) {
builder.startObject(fieldEntry.getKey());
fieldEntry.getValue().toXContent(builder, params);
builder.endObject();
}
}
public static GetFieldMappingsResponse fromXContent(XContentParser parser) throws IOException {
ensureExpectedToken(XContentParser.Token.START_OBJECT, parser.nextToken(), parser::getTokenLocation);

View File

@ -20,7 +20,6 @@ package org.elasticsearch.cluster.metadata;
import com.carrotsearch.hppc.cursors.ObjectCursor;
import com.carrotsearch.hppc.cursors.ObjectObjectCursor;
import org.apache.logging.log4j.LogManager;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
@ -42,6 +41,8 @@ import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.rest.BaseRestHandler;
import java.io.IOException;
import java.util.ArrayList;
@ -342,6 +343,8 @@ public class IndexTemplateMetaData extends AbstractDiffable<IndexTemplateMetaDat
public static void toInnerXContent(IndexTemplateMetaData indexTemplateMetaData, XContentBuilder builder, ToXContent.Params params)
throws IOException {
boolean includeTypeName = params.paramAsBoolean(BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER, true);
builder.field("order", indexTemplateMetaData.order());
if (indexTemplateMetaData.version() != null) {
builder.field("version", indexTemplateMetaData.version());
@ -353,18 +356,35 @@ public class IndexTemplateMetaData extends AbstractDiffable<IndexTemplateMetaDat
builder.endObject();
if (params.paramAsBoolean("reduce_mappings", false)) {
builder.startObject("mappings");
for (ObjectObjectCursor<String, CompressedXContent> cursor : indexTemplateMetaData.mappings()) {
byte[] mappingSource = cursor.value.uncompressed();
Map<String, Object> mapping = XContentHelper.convertToMap(new BytesArray(mappingSource), true).v2();
if (mapping.size() == 1 && mapping.containsKey(cursor.key)) {
// the type name is the root value, reduce it
mapping = (Map<String, Object>) mapping.get(cursor.key);
// The parameter include_type_name is only ever used in the REST API, where reduce_mappings is
// always set to true. We therefore only check for include_type_name in this branch.
if (includeTypeName == false) {
Map<String, Object> documentMapping = null;
for (ObjectObjectCursor<String, CompressedXContent> cursor : indexTemplateMetaData.mappings()) {
if (!cursor.key.equals(MapperService.DEFAULT_MAPPING)) {
assert documentMapping == null;
byte[] mappingSource = cursor.value.uncompressed();
Map<String, Object> mapping = XContentHelper.convertToMap(new BytesArray(mappingSource), true).v2();
documentMapping = reduceMapping(cursor.key, mapping);
}
}
builder.field(cursor.key);
builder.map(mapping);
if (documentMapping != null) {
builder.field("mappings", documentMapping);
} else {
builder.startObject("mappings").endObject();
}
} else {
builder.startObject("mappings");
for (ObjectObjectCursor<String, CompressedXContent> cursor : indexTemplateMetaData.mappings()) {
byte[] mappingSource = cursor.value.uncompressed();
Map<String, Object> mapping = XContentHelper.convertToMap(new BytesArray(mappingSource), true).v2();
mapping = reduceMapping(cursor.key, mapping);
builder.field(cursor.key);
builder.map(mapping);
}
builder.endObject();
}
builder.endObject();
} else {
builder.startArray("mappings");
for (ObjectObjectCursor<String, CompressedXContent> cursor : indexTemplateMetaData.mappings()) {
@ -381,6 +401,16 @@ public class IndexTemplateMetaData extends AbstractDiffable<IndexTemplateMetaDat
builder.endObject();
}
@SuppressWarnings("unchecked")
private static Map<String, Object> reduceMapping(String type, Map<String, Object> mapping) {
if (mapping.size() == 1 && mapping.containsKey(type)) {
// the type name is the root value, reduce it
return (Map<String, Object>) mapping.get(type);
} else {
return mapping;
}
}
public static IndexTemplateMetaData fromXContent(XContentParser parser, String templateName) throws IOException {
Builder builder = new Builder(templateName);

View File

@ -60,7 +60,7 @@ public abstract class BaseRestHandler extends AbstractComponent implements RestH
/**
* Parameter that controls whether certain REST apis should include type names in their requests or responses.
* Note: Support for this parameter will be removed after the transition perido to typeless APIs.
* Note: Support for this parameter will be removed after the transition period to typeless APIs.
*/
public static final String INCLUDE_TYPE_NAME_PARAMETER = "include_type_name";

View File

@ -62,6 +62,13 @@ public class RestGetFieldMappingAction extends BaseRestHandler {
final String[] indices = Strings.splitStringByCommaToArray(request.param("index"));
final String[] types = request.paramAsStringArrayOrEmptyIfAll("type");
final String[] fields = Strings.splitStringByCommaToArray(request.param("fields"));
boolean includeTypeName = request.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, true);
if (includeTypeName == false && types.length > 0) {
throw new IllegalArgumentException("Cannot set include_type_name=false and specify" +
" types at the same time.");
}
GetFieldMappingsRequest getMappingsRequest = new GetFieldMappingsRequest();
getMappingsRequest.indices(indices).types(types).fields(fields).includeDefaults(request.paramAsBoolean("include_defaults", false));
getMappingsRequest.indicesOptions(IndicesOptions.fromRequest(request, getMappingsRequest.indicesOptions()));

View File

@ -24,6 +24,7 @@ import org.elasticsearch.action.admin.indices.template.get.GetIndexTemplatesResp
import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.set.Sets;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
@ -31,6 +32,7 @@ import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
import java.util.Collections;
import java.util.Set;
import static org.elasticsearch.rest.RestRequest.Method.GET;
@ -43,6 +45,9 @@ import static org.elasticsearch.rest.RestStatus.OK;
*/
public class RestGetIndexTemplateAction extends BaseRestHandler {
private static final Set<String> RESPONSE_PARAMETERS = Collections.unmodifiableSet(Sets.union(
Collections.singleton(INCLUDE_TYPE_NAME_PARAMETER), Settings.FORMAT_PARAMS));
public RestGetIndexTemplateAction(final Settings settings, final RestController controller) {
super(settings);
controller.registerHandler(GET, "/_template", this);
@ -79,7 +84,7 @@ public class RestGetIndexTemplateAction extends BaseRestHandler {
@Override
protected Set<String> responseParams() {
return Settings.FORMAT_PARAMS;
return RESPONSE_PARAMETERS;
}
}

View File

@ -25,6 +25,8 @@ import org.elasticsearch.client.node.NodeClient;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.logging.DeprecationLogger;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.rest.BaseRestHandler;
import org.elasticsearch.rest.RestController;
import org.elasticsearch.rest.RestRequest;
@ -33,6 +35,8 @@ import org.elasticsearch.rest.action.RestToXContentListener;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class RestPutIndexTemplateAction extends BaseRestHandler {
@ -63,8 +67,23 @@ public class RestPutIndexTemplateAction extends BaseRestHandler {
putRequest.masterNodeTimeout(request.paramAsTime("master_timeout", putRequest.masterNodeTimeout()));
putRequest.create(request.paramAsBoolean("create", false));
putRequest.cause(request.param("cause", ""));
putRequest.source(request.requiredContent(), request.getXContentType());
boolean includeTypeName = request.paramAsBoolean(INCLUDE_TYPE_NAME_PARAMETER, true);
Map<String, Object> sourceAsMap = prepareRequestSource(request, includeTypeName);
putRequest.source(sourceAsMap);
return channel -> client.admin().indices().putTemplate(putRequest, new RestToXContentListener<>(channel));
}
Map<String, Object> prepareRequestSource(RestRequest request, boolean includeTypeName) {
Map<String, Object> sourceAsMap = XContentHelper.convertToMap(request.requiredContent(), false,
request.getXContentType()).v2();
if (includeTypeName == false && sourceAsMap.containsKey("mappings")) {
Map<String, Object> newSourceAsMap = new HashMap<>(sourceAsMap);
newSourceAsMap.put("mappings", Collections.singletonMap(MapperService.SINGLE_MAPPING_NAME, sourceAsMap.get("mappings")));
return newSourceAsMap;
} else {
return sourceAsMap;
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Licensed to Elasticsearch 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;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestStatus;
import org.elasticsearch.test.rest.FakeRestChannel;
import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.test.rest.RestActionTestCase;
import org.junit.Before;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.rest.BaseRestHandler.INCLUDE_TYPE_NAME_PARAMETER;
public class RestGetFieldMappingActionTests extends RestActionTestCase {
@Before
public void setUpAction() {
new RestGetFieldMappingAction(Settings.EMPTY, controller());
}
public void testTypeInPath() {
// Test that specifying a type while setting include_type_name to false
// results in an illegal argument exception.
Map<String, String> params = new HashMap<>();
params.put(INCLUDE_TYPE_NAME_PARAMETER, "false");
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
.withMethod(RestRequest.Method.GET)
.withPath("some_index/some_type/_mapping/field/some_field")
.withParams(params)
.build();
FakeRestChannel channel = new FakeRestChannel(request, false, 1);
ThreadContext threadContext = new ThreadContext(Settings.EMPTY);
controller().dispatchRequest(request, channel, threadContext);
assertEquals(1, channel.errors().get());
assertEquals(RestStatus.BAD_REQUEST, channel.capturedResponse().status());
}
}

View File

@ -0,0 +1,81 @@
/*
* Licensed to Elasticsearch 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;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.test.rest.FakeRestRequest;
import org.elasticsearch.test.rest.RestActionTestCase;
import org.junit.Before;
import java.io.IOException;
import java.util.Map;
public class RestPutIndexTemplateActionTests extends RestActionTestCase {
private RestPutIndexTemplateAction action;
@Before
public void setUpAction() {
action = new RestPutIndexTemplateAction(Settings.EMPTY, controller());
}
public void testPrepareTypelessRequest() throws IOException {
XContentBuilder content = XContentFactory.jsonBuilder().startObject()
.startObject("mappings")
.startObject("properties")
.startObject("field").field("type", "keyword").endObject()
.endObject()
.endObject()
.startObject("aliases")
.startObject("read_alias").endObject()
.endObject()
.endObject();
RestRequest request = new FakeRestRequest.Builder(xContentRegistry())
.withMethod(RestRequest.Method.PUT)
.withPath("/_template/_some_template")
.withContent(BytesReference.bytes(content), XContentType.JSON)
.build();
boolean includeTypeName = false;
Map<String, Object> source = action.prepareRequestSource(request, includeTypeName);
XContentBuilder expectedContent = XContentFactory.jsonBuilder().startObject()
.startObject("mappings")
.startObject("_doc")
.startObject("properties")
.startObject("field").field("type", "keyword").endObject()
.endObject()
.endObject()
.endObject()
.startObject("aliases")
.startObject("read_alias").endObject()
.endObject()
.endObject();
Map<String, Object> expectedContentAsMap = XContentHelper.convertToMap(
BytesReference.bytes(expectedContent), true, expectedContent.contentType()).v2();
assertEquals(expectedContentAsMap, source);
}
}