Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.next.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ Thanks, you're awesome :-) -->
* Added support for marking fields, field sets, or field reuse as beta in the documentation. #1051
* Added support for `constant_keyword`'s optional parameter `value`. #1112
* Added component templates for ECS field sets. #1156, #1186, #1191
* Added functionality for merging custom and core multi-fields. #982
Comment thread
ebeahan marked this conversation as resolved.

#### Improvements

Expand Down
30 changes: 30 additions & 0 deletions scripts/schema/loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,28 @@ def nest_fields(field_array):
return schema_root


def array_of_maps_to_map(array_vals):
ret_map = {}
for map_val in array_vals:
name = map_val['name']
# if multiple name fields exist in the same custom definition this will take the last one
ret_map[name] = map_val
return ret_map


def map_of_maps_to_array(map_vals):
ret_list = []
for key in map_vals:
ret_list.append(map_vals[key])
return sorted(ret_list, key=lambda k: k['name'])


def dedup_and_merge_lists(list_a, list_b):
list_a_map = array_of_maps_to_map(list_a)
list_a_map.update(array_of_maps_to_map(list_b))
return map_of_maps_to_array(list_a_map)


def merge_fields(a, b):
"""Merge ECS field sets with custom field sets."""
a = copy.deepcopy(a)
Expand All @@ -199,6 +221,14 @@ def merge_fields(a, b):
a[key].setdefault('field_details', {})
a[key]['field_details'].setdefault('normalize', [])
a[key]['field_details']['normalize'].extend(b[key]['field_details'].pop('normalize'))
if 'multi_fields' in b[key]['field_details']:
a[key].setdefault('field_details', {})
a[key]['field_details'].setdefault('multi_fields', [])
a[key]['field_details']['multi_fields'] = dedup_and_merge_lists(
a[key]['field_details']['multi_fields'], b[key]['field_details']['multi_fields'])
# if we don't do this then the update call below will overwrite a's field_details, with the original
# contents of b, which undoes our merging the multi_fields
del b[key]['field_details']['multi_fields']
a[key]['field_details'].update(b[key]['field_details'])
# merge schema details
if 'schema_details' in b[key]:
Expand Down
161 changes: 161 additions & 0 deletions scripts/tests/unit/test_schema_loader.py
Original file line number Diff line number Diff line change
Expand Up @@ -646,6 +646,167 @@ def test_merge_non_array_attributes(self):
}
self.assertEqual(merged_fields, expected_fields)

def test_merge_multi_fields(self):
schema1 = {
'base': {
'field_details': {
'multi_fields': [
Comment thread
webmat marked this conversation as resolved.
Outdated
{
'type': 'text',
'name': 'text'
},
{
'type': 'keyword',
'name': 'caseless',
'normalizer': 'lowercase'
}
]
},
'fields': {
'message': {
'field_details': {
'multi_fields': [
{
'type': 'text',
'name': 'text'
}
]
}
}
}
}
}

schema2 = {
'base': {
'field_details': {
'multi_fields': [
{
'type': 'text',
'name': 'text'
},
{
'type': 'text',
'name': 'almost_text',
}
]
},
'fields': {
'message': {
'field_details': {
'multi_fields': [
{
'type': 'keyword',
'name': 'a_field'
}
]
}
}
}
}
}
merged_fields = loader.merge_fields(schema1, schema2)
expected_multi_fields = [
{
'type': 'text',
'name': 'almost_text'
},
{
'type': 'keyword',
'name': 'caseless',
'normalizer': 'lowercase'
},
{
'type': 'text',
'name': 'text'
}
]

expected_message_multi_fields = [
{
'type': 'keyword',
'name': 'a_field'
},
{
'type': 'text',
'name': 'text'
}
]
self.assertEqual(merged_fields['base']['field_details']['multi_fields'], expected_multi_fields)
self.assertEqual(merged_fields['base']['fields']['message']['field_details']
['multi_fields'], expected_message_multi_fields)

def test_overwrite_multi_fields(self):
Comment thread
webmat marked this conversation as resolved.
Outdated
schema1 = {
'base': {
'field_details': {
'multi_fields': [
{
'type': 'text',
'name': 'text'
}
]
},
'fields': {
'message': {
'field_details': {
'multi_fields': [
{
'type': 'text',
'name': 'text'
}
]
}
}
}
}
}

# this schema should overwrite thee base and message fields
Comment thread
webmat marked this conversation as resolved.
Outdated
schema2 = {
'base': {
'field_details': {
'multi_fields': [
{
'type': 'text',
'name': 'text',
'normalizer': 'lowercase',
}
]
},
'fields': {
'message': {
'field_details': {
'multi_fields': [
{
'type': 'keyword',
'name': 'text'
}
]
}
}
}
}
}
merged_fields = loader.merge_fields(schema1, schema2)
expected_base_multi_fields = [
{
'type': 'text',
'name': 'text',
'normalizer': 'lowercase'
}
]

expected_message_multi_fields = [
{
'type': 'keyword',
'name': 'text'
}
]
self.assertEqual(merged_fields['base']['field_details']['multi_fields'], expected_base_multi_fields)
self.assertEqual(merged_fields['base']['fields']['message']['field_details']
['multi_fields'], expected_message_multi_fields)


if __name__ == '__main__':
unittest.main()