Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Maps] Fix document source top hits split by scripted field #57481

Merged
merged 5 commits into from
Feb 13, 2020
Merged
Show file tree
Hide file tree
Changes from 2 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
Original file line number Diff line number Diff line change
Expand Up @@ -241,8 +241,21 @@ export class ESSearchSource extends AbstractESSource {
});
}

_getField(indexPattern, fieldName) {
nreese marked this conversation as resolved.
Show resolved Hide resolved
const field = indexPattern.fields.getByName(fieldName);
if (!field) {
throw new Error(
i18n.translate('xpack.maps.source.esSearch.fieldNotFoundMsg', {
defaultMessage: `Unable to find '{fieldName}' in index-pattern '{indexPatternTitle}'.`,
values: { fieldName, indexPatternTitle: indexPattern.title },
})
);
}
return field;
}

async _getTopHits(layerName, searchFilters, registerCancelCallback) {
const { topHitsSplitField, topHitsSize } = this._descriptor;
const { topHitsSplitField: topHitsSplitFieldName, topHitsSize } = this._descriptor;

const indexPattern = await this.getIndexPattern();
const geoField = await this._getGeoField();
Expand Down Expand Up @@ -279,20 +292,31 @@ export class ESSearchSource extends AbstractESSource {
};
}

const cardinalityAgg = { precision_threshold: 1 };
const termsAgg = {
size: DEFAULT_MAX_BUCKETS_LIMIT,
shard_size: DEFAULT_MAX_BUCKETS_LIMIT,
};
const topHitsSplitField = this._getField(indexPattern, topHitsSplitFieldName);
if (topHitsSplitField.scripted) {
nreese marked this conversation as resolved.
Show resolved Hide resolved
const script = {
source: topHitsSplitField.script,
lang: topHitsSplitField.lang,
};
cardinalityAgg.script = script;
termsAgg.script = script;
} else {
cardinalityAgg.field = topHitsSplitFieldName;
termsAgg.field = topHitsSplitFieldName;
}

const searchSource = await this._makeSearchSource(searchFilters, 0);
searchSource.setField('aggs', {
totalEntities: {
cardinality: {
field: topHitsSplitField,
precision_threshold: 1,
},
cardinality: cardinalityAgg,
},
entitySplit: {
terms: {
field: topHitsSplitField,
size: DEFAULT_MAX_BUCKETS_LIMIT,
shard_size: DEFAULT_MAX_BUCKETS_LIMIT,
},
terms: termsAgg,
aggs: {
entityHits: {
top_hits: topHits,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.mapStopInputComboBox {
max-width: $euiSizeXL * 4;
}
95 changes: 54 additions & 41 deletions x-pack/test/functional/apps/maps/documents_source/top_hits.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,60 +13,73 @@ export default function({ getPageObjects, getService }) {
const inspector = getService('inspector');
const find = getService('find');

describe('top hits', () => {
before(async () => {
await PageObjects.maps.loadSavedMap('document example top hits');
});

it('should not fetch any search hits', async () => {
await inspector.open();
await inspector.openInspectorRequestsView();
const requestStats = await inspector.getTableData();
const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits');
expect(hits).to.equal('0'); // aggregation requests do not return any documents
});

it('should display top hits per entity', async () => {
const mapboxStyle = await PageObjects.maps.getMapboxStyle();
expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(10);
});

describe('configuration', () => {
describe('geo top hits', () => {
describe('split on string field', () => {
before(async () => {
await PageObjects.maps.openLayerPanel('logstash');
// Can not use testSubjects because data-test-subj is placed range input and number input
const sizeInput = await find.byCssSelector(
`input[data-test-subj="layerPanelTopHitsSize"][type='number']`
);
await sizeInput.click();
await sizeInput.clearValue();
await sizeInput.type('3');
await PageObjects.maps.waitForLayersToLoad();
await PageObjects.maps.loadSavedMap('document example top hits');
});

after(async () => {
await PageObjects.maps.closeLayerPanel();
it('should not fetch any search hits', async () => {
await inspector.open();
await inspector.openInspectorRequestsView();
const requestStats = await inspector.getTableData();
const hits = PageObjects.maps.getInspectorStatRowHit(requestStats, 'Hits');
expect(hits).to.equal('0'); // aggregation requests do not return any documents
});

it('should update top hits when configation changes', async () => {
it('should display top hits per entity', async () => {
const mapboxStyle = await PageObjects.maps.getMapboxStyle();
expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(15);
expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(10);
});
});

describe('query', () => {
before(async () => {
await PageObjects.maps.setAndSubmitQuery('machine.os.raw : "win 8"');
describe('configuration', () => {
before(async () => {
await PageObjects.maps.openLayerPanel('logstash');
// Can not use testSubjects because data-test-subj is placed range input and number input
const sizeInput = await find.byCssSelector(
`input[data-test-subj="layerPanelTopHitsSize"][type='number']`
);
await sizeInput.click();
await sizeInput.clearValue();
await sizeInput.type('3');
await PageObjects.maps.waitForLayersToLoad();
});

after(async () => {
await PageObjects.maps.closeLayerPanel();
});

it('should update top hits when configation changes', async () => {
const mapboxStyle = await PageObjects.maps.getMapboxStyle();
expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(15);
});
});

describe('query', () => {
before(async () => {
await PageObjects.maps.setAndSubmitQuery('machine.os.raw : "win 8"');
});

after(async () => {
await PageObjects.maps.setAndSubmitQuery('');
});

it('should apply query to top hits request', async () => {
await PageObjects.maps.setAndSubmitQuery('machine.os.raw : "win 8"');
const mapboxStyle = await PageObjects.maps.getMapboxStyle();
expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(2);
});
});
});

after(async () => {
await PageObjects.maps.setAndSubmitQuery('');
describe('split on scripted field', () => {
before(async () => {
await PageObjects.maps.loadSavedMap('document example top hits split with scripted field');
});

it('should apply query to top hits request', async () => {
await PageObjects.maps.setAndSubmitQuery('machine.os.raw : "win 8"');
it('should display top hits per entity', async () => {
const mapboxStyle = await PageObjects.maps.getMapboxStyle();
expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(2);
expect(mapboxStyle.sources[VECTOR_SOURCE_ID].data.features.length).to.equal(24);
});
});
});
Expand Down
56 changes: 56 additions & 0 deletions x-pack/test/functional/es_archives/maps/kibana/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,62 @@
}
}

{
"type": "doc",
"value": {
"id": "map:4ea1e4f0-4dba-11ea-b554-4ba0def79f86",
"index": ".kibana",
"source": {
"map": {
"title" : "document example top hits split with scripted field",
"description" : "",
"mapStateJSON" : "{\"zoom\":4.1,\"center\":{\"lon\":-100.61091,\"lat\":33.23887},\"timeFilters\":{\"from\":\"2015-09-20T00:00:00.000Z\",\"to\":\"2015-09-24T01:00:00.000Z\"},\"refreshConfig\":{\"isPaused\":true,\"interval\":1000},\"query\":{\"query\":\"\",\"language\":\"kuery\"},\"filters\":[]}",
"layerListJSON" : "[{\"id\":\"0hmz5\",\"sourceDescriptor\":{\"type\":\"EMS_TMS\",\"id\":\"road_map\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"TILE\",\"properties\":{}},\"type\":\"VECTOR_TILE\",\"minZoom\":0,\"maxZoom\":24},{\"id\":\"z52lq\",\"label\":\"logstash\",\"minZoom\":0,\"maxZoom\":24,\"sourceDescriptor\":{\"id\":\"e1a5e1a6-676c-4a89-8ea9-0d91d64b73c6\",\"type\":\"ES_SEARCH\",\"geoField\":\"geo.coordinates\",\"limit\":2048,\"filterByMapBounds\":true,\"showTooltip\":true,\"tooltipProperties\":[],\"useTopHits\":true,\"topHitsSplitField\":\"hour_of_day\",\"topHitsSize\":1,\"sortField\":\"@timestamp\",\"sortOrder\":\"desc\",\"applyGlobalQuery\":true,\"indexPatternRefName\":\"layer_1_source_index_pattern\"},\"visible\":true,\"temporary\":false,\"style\":{\"type\":\"VECTOR\",\"properties\":{\"fillColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#e6194b\"}},\"lineColor\":{\"type\":\"STATIC\",\"options\":{\"color\":\"#FFFFFF\"}},\"lineWidth\":{\"type\":\"STATIC\",\"options\":{\"size\":1}},\"iconSize\":{\"type\":\"STATIC\",\"options\":{\"size\":10}},\"symbolizeAs\":{\"options\":{\"value\":\"circle\"}},\"icon\":{\"type\":\"STATIC\",\"options\":{\"value\":\"airfield\"}}},\"previousStyle\":null},\"type\":\"VECTOR\"}]",
"uiStateJSON" : "{\"isLayerTOCOpen\":true,\"openTOCDetails\":[]}",
"bounds" : {
"type" : "Polygon",
"coordinates" : [
[
[
-141.61334,
47.30762
],
[
-141.61334,
16.49119
],
[
-59.60848,
16.49119
],
[
-59.60848,
47.30762
],
[
-141.61334,
47.30762
]
]
]
}
},
"type" : "map",
"references" : [
{
"name" : "layer_1_source_index_pattern",
"type" : "index-pattern",
"id" : "c698b940-e149-11e8-a35a-370a8516603a"
}
],
"migrationVersion" : {
"map" : "7.7.0"
},
"updated_at" : "2020-02-12T17:08:36.671Z"
}
}
}

{
"type": "doc",
"value": {
Expand Down