Skip to content

Commit

Permalink
[Maps] Move sort out of top hits configuration for ES documents source
Browse files Browse the repository at this point in the history
  • Loading branch information
nreese committed Oct 4, 2019
1 parent d1a99ea commit 4b43785
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 79 deletions.
5 changes: 5 additions & 0 deletions x-pack/legacy/plugins/maps/common/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ export const LAYER_TYPE = {
HEATMAP: 'HEATMAP'
};

export const SORT_ORDER = {
ASC: 'asc',
DESC: 'desc',
};

export const EMS_TMS = 'EMS_TMS';
export const EMS_FILE = 'EMS_FILE';
export const ES_GEO_GRID = 'ES_GEO_GRID';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { SearchSource } from '../../../kibana_services';
import { hitsToGeoJson } from '../../../elasticsearch_geo_utils';
import { CreateSourceEditor } from './create_source_editor';
import { UpdateSourceEditor } from './update_source_editor';
import { ES_SEARCH, ES_GEO_FIELD_TYPE, ES_SIZE_LIMIT } from '../../../../common/constants';
import { ES_SEARCH, ES_GEO_FIELD_TYPE, ES_SIZE_LIMIT, SORT_ORDER } from '../../../../common/constants';
import { i18n } from '@kbn/i18n';
import { getDataSourceLabel } from '../../../../common/i18n_getters';
import { ESTooltipProperty } from '../../tooltips/es_tooltip_property';
Expand Down Expand Up @@ -56,9 +56,10 @@ export class ESSearchSource extends AbstractESSource {
geoField: descriptor.geoField,
filterByMapBounds: _.get(descriptor, 'filterByMapBounds', DEFAULT_FILTER_BY_MAP_BOUNDS),
tooltipProperties: _.get(descriptor, 'tooltipProperties', []),
sortField: _.get(descriptor, 'sortField', ''),
sortOrder: _.get(descriptor, 'sortOrder', SORT_ORDER.DESC),
useTopHits: _.get(descriptor, 'useTopHits', false),
topHitsSplitField: descriptor.topHitsSplitField,
topHitsTimeField: descriptor.topHitsTimeField,
topHitsSize: _.get(descriptor, 'topHitsSize', 1),
}, inspectorAdapters);
}
Expand All @@ -70,9 +71,10 @@ export class ESSearchSource extends AbstractESSource {
onChange={onChange}
filterByMapBounds={this._descriptor.filterByMapBounds}
tooltipProperties={this._descriptor.tooltipProperties}
sortField={this._descriptor.sortField}
sortOrder={this._descriptor.sortOrder}
useTopHits={this._descriptor.useTopHits}
topHitsSplitField={this._descriptor.topHitsSplitField}
topHitsTimeField={this._descriptor.topHitsTimeField}
topHitsSize={this._descriptor.topHitsSize}
/>
);
Expand Down Expand Up @@ -135,10 +137,24 @@ export class ESSearchSource extends AbstractESSource {
];
}

// Returns sort content for an Elasticsearch search body
_buildEsSort() {
const {
sortField,
sortOrder,
} = this._descriptor;
return [
{
[sortField]: {
order: sortOrder
}
}
];
}

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

Expand All @@ -158,7 +174,7 @@ export class ESSearchSource extends AbstractESSource {
});

const searchSource = await this._makeSearchSource(searchFilters, 0);
searchSource.setField('aggs', {
const aggs = {
entitySplit: {
terms: {
field: topHitsSplitField,
Expand All @@ -167,13 +183,6 @@ export class ESSearchSource extends AbstractESSource {
aggs: {
entityHits: {
top_hits: {
sort: [
{
[topHitsTimeField]: {
order: 'desc'
}
}
],
_source: {
includes: searchFilters.fieldNames
},
Expand All @@ -183,7 +192,11 @@ export class ESSearchSource extends AbstractESSource {
}
}
}
});
};
if (this._hasSort()) {
aggs.entitySplit.aggs.entityHits.top_hits.sort = this._buildEsSort();
}
searchSource.setField('aggs', aggs);

const resp = await this._runEsQuery(layerName, searchSource, registerCancelCallback, 'Elasticsearch document top hits request');

Expand Down Expand Up @@ -218,6 +231,10 @@ export class ESSearchSource extends AbstractESSource {
// By setting "fields", SearchSource removes all of defaults
searchSource.setField('fields', searchFilters.fieldNames);

if (this._hasSort()) {
searchSource.setField('sort', this._buildEsSort());
}

const resp = await this._runEsQuery(layerName, searchSource, registerCancelCallback, 'Elasticsearch document request');

return {
Expand All @@ -228,9 +245,16 @@ export class ESSearchSource extends AbstractESSource {
};
}

// Returns true when top hits is enabled and properly configured
_isTopHits() {
const { useTopHits, topHitsSplitField, topHitsTimeField } = this._descriptor;
return !!(useTopHits && topHitsSplitField && topHitsTimeField);
const { useTopHits, topHitsSplitField } = this._descriptor;
return !!(useTopHits && topHitsSplitField);
}

// Returns true when sort is properly configured
_hasSort() {
const { sortField, sortOrder } = this._descriptor;
return !!(sortField && sortOrder);
}

async getGeoJsonWithMeta(layerName, searchFilters, registerCancelCallback) {
Expand Down Expand Up @@ -406,9 +430,10 @@ export class ESSearchSource extends AbstractESSource {

getSyncMeta() {
return {
sortField: this._descriptor.sortField,
sortOrder: this._descriptor.sortOrder,
useTopHits: this._descriptor.useTopHits,
topHitsSplitField: this._descriptor.topHitsSplitField,
topHitsTimeField: this._descriptor.topHitsTimeField,
topHitsSize: this._descriptor.topHitsSize,
};
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,39 @@

import React, { Fragment, Component } from 'react';
import PropTypes from 'prop-types';
import { EuiFormRow, EuiSwitch } from '@elastic/eui';
import {
EuiFormRow,
EuiSwitch,
EuiFlexGroup,
EuiFlexItem,
EuiSelect,
} from '@elastic/eui';
import { SingleFieldSelect } from '../../../components/single_field_select';
import { TooltipSelector } from '../../../components/tooltip_selector';

import { indexPatternService } from '../../../kibana_services';
import { i18n } from '@kbn/i18n';
import { getTermsFields, getSourceFields } from '../../../index_pattern_util';
import { ValidatedRange } from '../../../components/validated_range';
import { SORT_ORDER } from '../../../../common/constants';

export class UpdateSourceEditor extends Component {
static propTypes = {
indexPatternId: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
filterByMapBounds: PropTypes.bool.isRequired,
tooltipProperties: PropTypes.arrayOf(PropTypes.string).isRequired,
sortField: PropTypes.string,
sortOrder: PropTypes.string.isRequired,
useTopHits: PropTypes.bool.isRequired,
topHitsSplitField: PropTypes.string,
topHitsTimeField: PropTypes.string,
topHitsSize: PropTypes.number.isRequired,
};

state = {
tooltipFields: null,
termFields: null,
dateFields: null,
sortFields: null,
};

componentDidMount() {
Expand Down Expand Up @@ -64,27 +72,13 @@ export class UpdateSourceEditor extends Component {
return;
}

const dateFields = indexPattern.fields.filter(field => {
return field.type === 'date';
});

this.setState({
dateFields,
tooltipFields: getSourceFields(indexPattern.fields),
termFields: getTermsFields(indexPattern.fields),
sortFields: indexPattern.fields.filter(field => {
return field.sortable;
}),
});

if (!this.props.topHitsTimeField) {
// prefer default time field
if (indexPattern.timeFieldName) {
this.onTopHitsTimeFieldChange(indexPattern.timeFieldName);
} else {
// fall back to first date field in index
if (dateFields.length > 0) {
this.onTopHitsTimeFieldChange(dateFields[0].name);
}
}
}
}
_onTooltipPropertiesChange = propertyNames => {
this.props.onChange({ propName: 'tooltipProperties', value: propertyNames });
Expand All @@ -102,10 +96,14 @@ export class UpdateSourceEditor extends Component {
this.props.onChange({ propName: 'topHitsSplitField', value: topHitsSplitField });
};

onTopHitsTimeFieldChange = topHitsTimeField => {
this.props.onChange({ propName: 'topHitsTimeField', value: topHitsTimeField });
onSortFieldChange = sortField => {
this.props.onChange({ propName: 'sortField', value: sortField });
};

onSortOrderChange = e => {
this.props.onChange({ propName: 'sortOrder', value: e.target.value });
}

onTopHitsSizeChange = size => {
this.props.onChange({ propName: 'topHitsSize', value: size });
};
Expand All @@ -115,31 +113,8 @@ export class UpdateSourceEditor extends Component {
return null;
}

let timeFieldSelect;
let sizeSlider;
if (this.props.topHitsSplitField) {
timeFieldSelect = (
<EuiFormRow
label={i18n.translate('xpack.maps.source.esSearch.topHitsTimeFieldLabel', {
defaultMessage: 'Time',
})}
display="rowCompressed"
>
<SingleFieldSelect
placeholder={i18n.translate(
'xpack.maps.source.esSearch.topHitsTimeFieldSelectPlaceholder',
{
defaultMessage: 'Select time field',
}
)}
value={this.props.topHitsTimeField}
onChange={this.onTopHitsTimeFieldChange}
fields={this.state.dateFields}
compressed
/>
</EuiFormRow>
);

sizeSlider = (
<EuiFormRow
label={i18n.translate('xpack.maps.source.esSearch.topHitsSizeLabel', {
Expand Down Expand Up @@ -185,29 +160,12 @@ export class UpdateSourceEditor extends Component {
/>
</EuiFormRow>

{timeFieldSelect}

{sizeSlider}
</Fragment>
);
}

render() {
let topHitsCheckbox;
if (this.state.dateFields && this.state.dateFields.length) {
topHitsCheckbox = (
<EuiFormRow>
<EuiSwitch
label={i18n.translate('xpack.maps.source.esSearch.useTopHitsLabel', {
defaultMessage: `Show most recent documents by entity`,
})}
checked={this.props.useTopHits}
onChange={this.onUseTopHitsChange}
/>
</EuiFormRow>
);
}

return (
<Fragment>
<TooltipSelector
Expand All @@ -216,6 +174,44 @@ export class UpdateSourceEditor extends Component {
fields={this.state.tooltipFields}
/>

<EuiFormRow
label={i18n.translate('xpack.maps.source.esSearch.sortLabel', {
defaultMessage: `Sort`,
})}
>
<EuiFlexGroup
gutterSize="none"
justifyContent="flexEnd"
>
<EuiFlexItem>
<SingleFieldSelect
placeholder={i18n.translate(
'xpack.maps.source.esSearch.sortFieldSelectPlaceholder',
{
defaultMessage: 'Select sort field',
}
)}
value={this.props.sortField}
onChange={this.onSortFieldChange}
fields={this.state.sortFields}
compressed
/>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiSelect
disabled={!this.props.sortField}
options={[
{ label: 'ASC', value: SORT_ORDER.ASC },
{ label: 'DESC', value: SORT_ORDER.DESC }
]}
value={this.props.sortOrder}
onChange={this.onSortOrderChange}
compressed
/>
</EuiFlexItem>
</EuiFlexGroup>
</EuiFormRow>

<EuiFormRow>
<EuiSwitch
label={i18n.translate('xpack.maps.source.esSearch.extentFilterLabel', {
Expand All @@ -226,7 +222,15 @@ export class UpdateSourceEditor extends Component {
/>
</EuiFormRow>

{topHitsCheckbox}
<EuiFormRow>
<EuiSwitch
label={i18n.translate('xpack.maps.source.esSearch.useTopHitsLabel', {
defaultMessage: `Show most recent documents by entity`,
})}
checked={this.props.useTopHits}
onChange={this.onUseTopHitsChange}
/>
</EuiFormRow>

{this.renderTopHitsForm()}
</Fragment>
Expand Down

0 comments on commit 4b43785

Please sign in to comment.