diff --git a/src/server/index_patterns/service/lib/field_capabilities/__tests__/field_caps_response.js b/src/server/index_patterns/service/lib/field_capabilities/__tests__/field_caps_response.js index 2a43ca2b55a39..c0db141bb1dca 100644 --- a/src/server/index_patterns/service/lib/field_capabilities/__tests__/field_caps_response.js +++ b/src/server/index_patterns/service/lib/field_capabilities/__tests__/field_caps_response.js @@ -19,7 +19,7 @@ describe('index_patterns/field_capabilities/field_caps_response', () => { describe('conflicts', () => { it('returns a field for each in response, no filtering', () => { const fields = readFieldCapsResponse(esResponse); - expect(fields).to.have.length(13); + expect(fields).to.have.length(19); }); it('includes only name, type, searchable, aggregatable, readFromDocValues, and maybe conflictDescriptions of each field', () => { @@ -65,8 +65,8 @@ describe('index_patterns/field_capabilities/field_caps_response', () => { { name: 'success', type: 'conflict', - searchable: false, - aggregatable: false, + searchable: true, + aggregatable: true, readFromDocValues: false, conflictDescriptions: { boolean: [ @@ -79,6 +79,30 @@ describe('index_patterns/field_capabilities/field_caps_response', () => { } ]); }); + + it('does not return conflicted fields if the types are resolvable to the same kibana type', () => { + const fields = readFieldCapsResponse(esResponse); + const resolvableToString = fields.find(f => f.name === 'resolvable_to_string'); + const resolvableToNumber = fields.find(f => f.name === 'resolvable_to_number'); + expect(resolvableToString.type).to.be('string'); + expect(resolvableToNumber.type).to.be('number'); + }); + + it('returns aggregatable if at least one field is aggregatable', () => { + const fields = readFieldCapsResponse(esResponse); + const mixAggregatable = fields.find(f => f.name === 'mix_aggregatable'); + const mixAggregatableOther = fields.find(f => f.name === 'mix_aggregatable_other'); + expect(mixAggregatable.aggregatable).to.be(true); + expect(mixAggregatableOther.aggregatable).to.be(true); + }); + + it('returns searchable if at least one field is searchable', () => { + const fields = readFieldCapsResponse(esResponse); + const mixSearchable = fields.find(f => f.name === 'mix_searchable'); + const mixSearchableOther = fields.find(f => f.name === 'mix_searchable_other'); + expect(mixSearchable.searchable).to.be(true); + expect(mixSearchableOther.searchable).to.be(true); + }); }); }); }); diff --git a/src/server/index_patterns/service/lib/field_capabilities/__tests__/fixtures/es_field_caps_response.json b/src/server/index_patterns/service/lib/field_capabilities/__tests__/fixtures/es_field_caps_response.json index 659489c7361c5..d6fc2963f504e 100644 --- a/src/server/index_patterns/service/lib/field_capabilities/__tests__/fixtures/es_field_caps_response.json +++ b/src/server/index_patterns/service/lib/field_capabilities/__tests__/fixtures/es_field_caps_response.json @@ -101,6 +101,98 @@ "searchable": false, "aggregatable": true } + }, + "resolvable_to_string": { + "text": { + "type": "text", + "searchable": true, + "aggregatable": true, + "indices": [ + "index1" + ] + }, + "keyword": { + "type": "keyword", + "searchable": true, + "aggregatable": true, + "indices": [ + "index2" + ] + } + }, + "resolvable_to_number": { + "integer": { + "type": "integer", + "searchable": true, + "aggregatable": true, + "indices": [ + "index1" + ] + }, + "long": { + "type": "long", + "searchable": true, + "aggregatable": true, + "indices": [ + "index2" + ] + } + }, + "mix_searchable": { + "text": { + "type": "text", + "searchable": false, + "aggregatable": true, + "indices": [ + "index1" + ] + }, + "keyword": { + "type": "keyword", + "searchable": true, + "aggregatable": true, + "indices": [ + "index2" + ] + } + }, + "mix_aggregatable": { + "text": { + "type": "text", + "searchable": true, + "aggregatable": false, + "indices": [ + "index1" + ] + }, + "keyword": { + "type": "keyword", + "searchable": true, + "aggregatable": true, + "indices": [ + "index2" + ] + } + }, + "mix_searchable_other": { + "int": { + "type": "integer", + "searchable": false, + "aggregatable": false, + "non_searchable_indices": [ + "index1" + ] + } + }, + "mix_aggregatable_other": { + "int": { + "type": "integer", + "searchable": false, + "aggregatable": false, + "non_aggregatable_indices": [ + "index1" + ] + } } } } diff --git a/src/server/index_patterns/service/lib/field_capabilities/field_caps_response.js b/src/server/index_patterns/service/lib/field_capabilities/field_caps_response.js index 94e8b6395804c..8f50f4b454514 100644 --- a/src/server/index_patterns/service/lib/field_capabilities/field_caps_response.js +++ b/src/server/index_patterns/service/lib/field_capabilities/field_caps_response.js @@ -1,3 +1,4 @@ +import { uniq } from 'lodash'; import { castEsToKbnFieldTypeName } from '../../../../../utils'; import { shouldReadFieldFromDocValues } from './should_read_field_from_doc_values'; @@ -63,12 +64,27 @@ export function readFieldCapsResponse(fieldCapsResponse) { const capsByType = capsByNameThenType[fieldName]; const types = Object.keys(capsByType); - if (types.length > 1) { + // If a single type is marked as searchable or aggregatable, all the types are searchable or aggregatable + const isSearchable = types.some(type => { + return !!capsByType[type].searchable || + (!!capsByType[type].non_searchable_indices && capsByType[type].non_searchable_indices.length > 0); + }); + + const isAggregatable = types.some(type => { + return !!capsByType[type].aggregatable || + (!!capsByType[type].non_aggregatable_indices && capsByType[type].non_aggregatable_indices.length > 0); + }); + + + // If there are multiple types but they all resolve to the same kibana type + // ignore the conflict and carry on (my wayward son) + const uniqueKibanaTypes = uniq(types.map(castEsToKbnFieldTypeName)); + if (uniqueKibanaTypes.length > 1) { return { name: fieldName, type: 'conflict', - searchable: false, - aggregatable: false, + searchable: isSearchable, + aggregatable: isAggregatable, readFromDocValues: false, conflictDescriptions: types.reduce((acc, esType) => ({ ...acc, @@ -78,13 +94,12 @@ export function readFieldCapsResponse(fieldCapsResponse) { } const esType = types[0]; - const caps = capsByType[esType]; return { name: fieldName, type: castEsToKbnFieldTypeName(esType), - searchable: caps.searchable, - aggregatable: caps.aggregatable, - readFromDocValues: shouldReadFieldFromDocValues(caps.aggregatable, esType), + searchable: isSearchable, + aggregatable: isAggregatable, + readFromDocValues: shouldReadFieldFromDocValues(isAggregatable, esType), }; }); } diff --git a/test/api_integration/apis/index_patterns/fields_for_wildcard_route/conflicts.js b/test/api_integration/apis/index_patterns/fields_for_wildcard_route/conflicts.js index e477f59b96011..0c2aab44d0988 100644 --- a/test/api_integration/apis/index_patterns/fields_for_wildcard_route/conflicts.js +++ b/test/api_integration/apis/index_patterns/fields_for_wildcard_route/conflicts.js @@ -23,11 +23,25 @@ export default function ({ getService }) { searchable: true, readFromDocValues: true, }, + { + name: 'number_conflict', + type: 'number', + aggregatable: true, + searchable: true, + readFromDocValues: true, + }, + { + name: 'string_conflict', + type: 'string', + aggregatable: true, + searchable: true, + readFromDocValues: false, + }, { name: 'success', type: 'conflict', - aggregatable: false, - searchable: false, + aggregatable: true, + searchable: true, readFromDocValues: false, conflictDescriptions: { boolean: [ diff --git a/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/data.json.gz b/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/data.json.gz index aa3c439e6834b..cf767f8331ef4 100644 Binary files a/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/data.json.gz and b/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/data.json.gz differ diff --git a/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/mappings.json b/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/mappings.json index ffbb7946ec7b9..98e62cf2462a0 100644 --- a/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/mappings.json +++ b/test/api_integration/fixtures/es_archiver/index_patterns/conflicts/mappings.json @@ -1,7 +1,7 @@ { "type": "index", "value": { - "index": "logs-2017.01.01", + "index": "logs-2017.01.02", "settings": { "index": { "number_of_shards": "1", @@ -14,8 +14,14 @@ "@timestamp": { "type": "date" }, - "success": { + "number_conflict": { + "type": "float" + }, + "string_conflict": { "type": "keyword" + }, + "success": { + "type": "boolean" } } } @@ -26,7 +32,7 @@ { "type": "index", "value": { - "index": "logs-2017.01.02", + "index": "logs-2017.01.01", "settings": { "index": { "number_of_shards": "1", @@ -39,11 +45,17 @@ "@timestamp": { "type": "date" }, + "number_conflict": { + "type": "integer" + }, + "string_conflict": { + "type": "text" + }, "success": { - "type": "boolean" + "type": "keyword" } } } } } -} \ No newline at end of file +}