mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
Ensure conflicted fields can be searchable and/or aggregatable (#13070)
* Ensure that conflict fields can be searchable and/or aggregatable in the UI * Use `some` instead of `reduce` * Revert UI changes * Attempt to convert multiple ES types to kibana types, and if they all resolve to the same kibana type, there is no conflict * Add comma back * Cleaner code * Add tests * Update failing test to handle searchable and aggregatable properly * Add functional test to ensure similar ES types are properly merged * Update tests * Revert shard size
This commit is contained in:
parent
d14da34032
commit
389115cad0
6 changed files with 195 additions and 38 deletions
|
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
|
|
@ -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: [
|
||||
|
|
Binary file not shown.
|
@ -1,28 +1,3 @@
|
|||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"index": "logs-2017.01.01",
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_shards": "1",
|
||||
"number_of_replicas": "1"
|
||||
}
|
||||
},
|
||||
"mappings": {
|
||||
"type": {
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"success": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
|
@ -39,6 +14,12 @@
|
|||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"number_conflict": {
|
||||
"type": "float"
|
||||
},
|
||||
"string_conflict": {
|
||||
"type": "keyword"
|
||||
},
|
||||
"success": {
|
||||
"type": "boolean"
|
||||
}
|
||||
|
@ -46,4 +27,35 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
"type": "index",
|
||||
"value": {
|
||||
"index": "logs-2017.01.01",
|
||||
"settings": {
|
||||
"index": {
|
||||
"number_of_shards": "1",
|
||||
"number_of_replicas": "1"
|
||||
}
|
||||
},
|
||||
"mappings": {
|
||||
"type": {
|
||||
"properties": {
|
||||
"@timestamp": {
|
||||
"type": "date"
|
||||
},
|
||||
"number_conflict": {
|
||||
"type": "integer"
|
||||
},
|
||||
"string_conflict": {
|
||||
"type": "text"
|
||||
},
|
||||
"success": {
|
||||
"type": "keyword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue