[TSVB] Rollup Search - override index pattern functionality is not working with Rollup search (#36641) (#37078)

This commit is contained in:
Alexey Antonov 2019-05-24 16:58:31 +03:00 committed by GitHub
parent ed5fe5fea3
commit d710b06714
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 168 additions and 172 deletions

View file

@ -18,32 +18,32 @@
*/
import { uniq } from 'lodash';
export function extractIndexPatterns(params, fetchedFields = {}) {
const patternsToFetch = [];
export function extractIndexPatterns(panel, excludedFields = {}) {
const patterns = [];
if (!fetchedFields[params.index_pattern]) {
patternsToFetch.push(params.index_pattern);
if (!excludedFields[panel.index_pattern]) {
patterns.push(panel.index_pattern);
}
params.series.forEach(series => {
panel.series.forEach(series => {
const indexPattern = series.series_index_pattern;
if (series.override_index_pattern && !fetchedFields[indexPattern]) {
patternsToFetch.push(indexPattern);
if (indexPattern && series.override_index_pattern && !excludedFields[indexPattern]) {
patterns.push(indexPattern);
}
});
if (params.annotations) {
params.annotations.forEach(item => {
if (panel.annotations) {
panel.annotations.forEach(item => {
const indexPattern = item.index_pattern;
if (indexPattern && !fetchedFields[indexPattern]) {
patternsToFetch.push(indexPattern);
if (indexPattern && !excludedFields[indexPattern]) {
patterns.push(indexPattern);
}
});
}
if (patternsToFetch.length === 0) {
patternsToFetch.push('');
if (patterns.length === 0) {
patterns.push('');
}
return uniq(patternsToFetch).sort();
return uniq(patterns).sort();
}

View file

@ -17,49 +17,51 @@
* under the License.
*/
import { extractIndexPatterns } from '../extract_index_patterns';
import { expect } from 'chai';
import { extractIndexPatterns } from './extract_index_patterns';
describe('extractIndexPatterns(vis)', () => {
let visParams;
let visFields;
beforeEach(() => {
visFields = {
'*': []
'*': [],
};
visParams = {
index_pattern: '*',
series: [
{
override_index_pattern: 1,
series_index_pattern: 'example-1-*'
series_index_pattern: 'example-1-*',
},
{
override_index_pattern: 1,
series_index_pattern: 'example-2-*'
}
series_index_pattern: 'example-2-*',
},
],
annotations: [
{ index_pattern: 'notes-*' },
{ index_pattern: 'example-1-*' }
]
{ index_pattern: 'example-1-*' },
],
};
});
it('should return index patterns', () => {
test('should return index patterns', () => {
visFields = {};
expect(extractIndexPatterns(visParams, visFields)).to.eql([
expect(extractIndexPatterns(visParams, visFields)).toEqual([
'*',
'example-1-*',
'example-2-*',
'notes-*'
'notes-*',
]);
});
it('should return index patterns that do not exist in visFields', () => {
expect(extractIndexPatterns(visParams, visFields)).to.eql([
test('should return index patterns that do not exist in visFields', () => {
expect(extractIndexPatterns(visParams, visFields)).toEqual([
'example-1-*',
'example-2-*',
'notes-*'
'notes-*',
]);
});
});

View file

@ -28,7 +28,7 @@ import VisPicker from './vis_picker';
import PanelConfig from './panel_config';
import brushHandler from '../lib/create_brush_handler';
import { fetchFields } from '../lib/fetch_fields';
import { extractIndexPatterns } from '../lib/extract_index_patterns';
import { extractIndexPatterns } from '../../common/extract_index_patterns';
const VIS_STATE_DEBOUNCE_DELAY = 200;

View file

@ -19,7 +19,7 @@
import { kfetch } from 'ui/kfetch';
import { toastNotifications } from 'ui/notify';
import { i18n } from '@kbn/i18n';
import { extractIndexPatterns } from './extract_index_patterns';
import { extractIndexPatterns } from '../../common/extract_index_patterns';
export async function fetchFields(indexPatterns = ['*']) {
const patterns = Array.isArray(indexPatterns) ? indexPatterns : [indexPatterns];

View file

@ -23,9 +23,8 @@ const getTimezoneFromRequest = request => {
};
export class DefaultSearchCapabilities {
constructor(request, batchRequestsSupport, fieldsCapabilities = {}) {
constructor(request, fieldsCapabilities = {}) {
this.request = request;
this.batchRequestsSupport = batchRequestsSupport;
this.fieldsCapabilities = fieldsCapabilities;
}

View file

@ -20,18 +20,15 @@ import { DefaultSearchCapabilities } from './default_search_capabilities';
describe('DefaultSearchCapabilities', () => {
let defaultSearchCapabilities;
let batchRequestsSupport;
let req;
beforeEach(() => {
req = {};
batchRequestsSupport = true;
defaultSearchCapabilities = new DefaultSearchCapabilities(req, batchRequestsSupport);
defaultSearchCapabilities = new DefaultSearchCapabilities(req);
});
test('should init default search capabilities', () => {
expect(defaultSearchCapabilities.request).toBe(req);
expect(defaultSearchCapabilities.batchRequestsSupport).toBe(batchRequestsSupport);
expect(defaultSearchCapabilities.fieldsCapabilities).toEqual({});
});

View file

@ -21,6 +21,8 @@ import { AbstractSearchRequest } from './searh_requests/abstract_request';
import { DefaultSearchStrategy } from './strategies/default_search_strategy';
import { DefaultSearchCapabilities } from './default_search_capabilities';
import { extractIndexPatterns } from '../../../common/extract_index_patterns';
const strategies = [];
const addStrategy = searchStrategy => {
@ -52,4 +54,10 @@ export class SearchStrategiesRegister {
}
}
}
static async getViableStrategyForPanel(req, panel) {
const indexPattern = extractIndexPatterns(panel).join(',');
return SearchStrategiesRegister.getViableStrategy(req, indexPattern);
}
}

View file

@ -17,10 +17,9 @@
* under the License.
*/
export class AbstractSearchRequest {
constructor(req, callWithRequest, indexPattern) {
constructor(req, callWithRequest) {
this.req = req;
this.callWithRequest = callWithRequest;
this.indexPattern = indexPattern;
}
search() {

View file

@ -22,19 +22,16 @@ describe('AbstractSearchRequest', () => {
let searchRequest;
let req;
let callWithRequest;
let indexPattern;
beforeEach(() => {
req = {};
callWithRequest = jest.fn();
indexPattern = 'indexPattern';
searchRequest = new AbstractSearchRequest(req, callWithRequest, indexPattern);
searchRequest = new AbstractSearchRequest(req, callWithRequest);
});
test('should init an AbstractSearchRequest instance', () => {
expect(searchRequest.req).toBe(req);
expect(searchRequest.callWithRequest).toBe(callWithRequest);
expect(searchRequest.indexPattern).toBe(indexPattern);
expect(searchRequest.search).toBeDefined();
});

View file

@ -21,10 +21,19 @@ import { AbstractSearchRequest } from './abstract_request';
const SEARCH_METHOD = 'msearch';
export class MultiSearchRequest extends AbstractSearchRequest {
async search(options) {
async search(searches) {
const includeFrozen = await this.req.getUiSettingsService().get('search:includeFrozen');
const multiSearchBody = searches.reduce((acc, { body, index }) => ([
...acc,
{
index,
ignoreUnavailable: true,
},
body,
]), []);
const { responses } = await this.callWithRequest(this.req, SEARCH_METHOD, {
...options,
body: multiSearchBody,
rest_total_hits_as_int: true,
ignore_throttled: !includeFrozen,
});

View file

@ -22,7 +22,6 @@ describe('MultiSearchRequest', () => {
let searchRequest;
let req;
let callWithRequest;
let indexPattern;
let getServiceMock;
let includeFrozen;
@ -30,30 +29,36 @@ describe('MultiSearchRequest', () => {
includeFrozen = false;
getServiceMock = jest.fn().mockResolvedValue(includeFrozen);
req = {
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock })
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }),
};
callWithRequest = jest.fn().mockReturnValue({ responses: [] });
indexPattern = 'indexPattern';
searchRequest = new MultiSearchRequest(req, callWithRequest, indexPattern);
searchRequest = new MultiSearchRequest(req, callWithRequest);
});
test('should init an MultiSearchRequest instance', () => {
expect(searchRequest.req).toBe(req);
expect(searchRequest.callWithRequest).toBe(callWithRequest);
expect(searchRequest.indexPattern).toBe(indexPattern);
expect(searchRequest.search).toBeDefined();
});
test('should get the response from elastic msearch', async () => {
const options = {};
const searches = [
{ body: 'body1', index: 'index' },
{ body: 'body2', index: 'index' },
];
const responses = await searchRequest.search(options);
const responses = await searchRequest.search(searches);
expect(responses).toEqual([]);
expect(req.getUiSettingsService).toHaveBeenCalled();
expect(getServiceMock).toHaveBeenCalledWith('search:includeFrozen');
expect(callWithRequest).toHaveBeenCalledWith(req, 'msearch', {
...options,
body: [
{ ignoreUnavailable: true, index: 'index' },
'body1',
{ ignoreUnavailable: true, index: 'index' },
'body2',
],
rest_total_hits_as_int: true,
ignore_throttled: !includeFrozen,
});

View file

@ -22,11 +22,11 @@ import { MultiSearchRequest } from './multi_search_request';
import { SingleSearchRequest } from './single_search_request';
export class SearchRequest extends AbstractSearchRequest {
getSearchRequestType(options) {
const isMultiSearch = Array.isArray(options.body);
getSearchRequestType(searches) {
const isMultiSearch = Array.isArray(searches) && searches.length > 1;
const SearchRequest = isMultiSearch ? MultiSearchRequest : SingleSearchRequest;
return new SearchRequest(this.req, this.callWithRequest, this.indexPattern);
return new SearchRequest(this.req, this.callWithRequest);
}
async search(options) {

View file

@ -24,7 +24,6 @@ describe('SearchRequest', () => {
let searchRequest;
let req;
let callWithRequest;
let indexPattern;
let getServiceMock;
let includeFrozen;
@ -32,23 +31,21 @@ describe('SearchRequest', () => {
includeFrozen = false;
getServiceMock = jest.fn().mockResolvedValue(includeFrozen);
req = {
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock })
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }),
};
callWithRequest = jest.fn().mockReturnValue({ responses: [] });
indexPattern = 'indexPattern';
searchRequest = new SearchRequest(req, callWithRequest, indexPattern);
searchRequest = new SearchRequest(req, callWithRequest);
});
test('should init an AbstractSearchRequest instance', () => {
expect(searchRequest.req).toBe(req);
expect(searchRequest.callWithRequest).toBe(callWithRequest);
expect(searchRequest.indexPattern).toBe(indexPattern);
expect(searchRequest.search).toBeDefined();
});
test('should return search value', async () => {
const concreteSearchRequest = {
search: jest.fn().mockReturnValue('concreteSearchRequest')
search: jest.fn().mockReturnValue('concreteSearchRequest'),
};
const options = {};
searchRequest.getSearchRequestType = jest.fn().mockReturnValue(concreteSearchRequest);
@ -58,20 +55,18 @@ describe('SearchRequest', () => {
expect(result).toBe('concreteSearchRequest');
});
test('should return a MultiSearchRequest if options has body as an array', () => {
const options = {
body: []
};
test('should return a MultiSearchRequest for multi searches', () => {
const searches = [{ index: 'index', body: 'body' }, { index: 'index', body: 'body' }];
const result = searchRequest.getSearchRequestType(options);
const result = searchRequest.getSearchRequestType(searches);
expect(result instanceof MultiSearchRequest).toBe(true);
});
test('should return a SingleSearchRequest if options has body', () => {
const options = {};
test('should return a SingleSearchRequest for single search', () => {
const searches = [{ index: 'index', body: 'body' }];
const result = searchRequest.getSearchRequestType(options);
const result = searchRequest.getSearchRequestType(searches);
expect(result instanceof SingleSearchRequest).toBe(true);
});

View file

@ -21,12 +21,12 @@ import { AbstractSearchRequest } from './abstract_request';
const SEARCH_METHOD = 'search';
export class SingleSearchRequest extends AbstractSearchRequest {
async search(options) {
async search([{ body, index }]) {
const includeFrozen = await this.req.getUiSettingsService().get('search:includeFrozen');
const resp = await this.callWithRequest(this.req, SEARCH_METHOD, {
...options,
index: this.indexPattern,
ignore_throttled: !includeFrozen,
body,
index,
});
return [resp];

View file

@ -22,7 +22,6 @@ describe('SingleSearchRequest', () => {
let searchRequest;
let req;
let callWithRequest;
let indexPattern;
let getServiceMock;
let includeFrozen;
@ -30,31 +29,29 @@ describe('SingleSearchRequest', () => {
includeFrozen = false;
getServiceMock = jest.fn().mockResolvedValue(includeFrozen);
req = {
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock })
getUiSettingsService: jest.fn().mockReturnValue({ get: getServiceMock }),
};
callWithRequest = jest.fn().mockReturnValue({});
indexPattern = 'indexPattern';
searchRequest = new SingleSearchRequest(req, callWithRequest, indexPattern);
searchRequest = new SingleSearchRequest(req, callWithRequest);
});
test('should init an SingleSearchRequest instance', () => {
expect(searchRequest.req).toBe(req);
expect(searchRequest.callWithRequest).toBe(callWithRequest);
expect(searchRequest.indexPattern).toBe(indexPattern);
expect(searchRequest.search).toBeDefined();
});
test('should get the response from elastic search', async () => {
const options = {};
const searches = [{ body: 'body', index: 'index' }];
const responses = await searchRequest.search(options);
const responses = await searchRequest.search(searches);
expect(responses).toEqual([{}]);
expect(req.getUiSettingsService).toHaveBeenCalled();
expect(getServiceMock).toHaveBeenCalledWith('search:includeFrozen');
expect(callWithRequest).toHaveBeenCalledWith(req, 'search', {
...options,
index: indexPattern,
body: 'body',
index: 'index',
ignore_throttled: !includeFrozen,
});
});

View file

@ -21,10 +21,10 @@ export class AbstractSearchStrategy {
constructor(server, callWithRequestFactory, SearchRequest) {
this.getCallWithRequestInstance = req => callWithRequestFactory(server, req);
this.getSearchRequest = (req, indexPattern) => {
this.getSearchRequest = (req) => {
const callWithRequest = this.getCallWithRequestInstance(req);
return new SearchRequest(req, callWithRequest, indexPattern);
return new SearchRequest(req, callWithRequest);
};
}

View file

@ -19,10 +19,9 @@
import { AbstractSearchStrategy } from './abstract_search_strategy';
class SearchRequest {
constructor(req, callWithRequest, indexPattern) {
constructor(req, callWithRequest) {
this.req = req;
this.callWithRequest = callWithRequest;
this.indexPattern = indexPattern;
}
}
@ -38,7 +37,6 @@ describe('AbstractSearchStrategy', () => {
server = {};
callWithRequestFactory = jest.fn().mockReturnValue('callWithRequest');
mockedFields = {};
indexPattern = '*';
req = {
pre: {
indexPatternsService: {
@ -73,10 +71,9 @@ describe('AbstractSearchStrategy', () => {
});
test('should return a search request', () => {
const searchRequest = abstractSearchStrategy.getSearchRequest(req, indexPattern);
const searchRequest = abstractSearchStrategy.getSearchRequest(req);
expect(searchRequest instanceof SearchRequest).toBe(true);
expect(searchRequest.indexPattern).toBe(indexPattern);
expect(searchRequest.callWithRequest).toBe('callWithRequest');
expect(searchRequest.req).toBe(req);
});

View file

@ -25,7 +25,6 @@ const callWithRequestFactory = (server, request) => {
return callWithRequest;
};
const batchRequestsSupport = true;
export class DefaultSearchStrategy extends AbstractSearchStrategy {
name = 'default';
@ -37,7 +36,7 @@ export class DefaultSearchStrategy extends AbstractSearchStrategy {
checkForViability(req) {
return {
isViable: true,
capabilities: new DefaultSearchCapabilities(req, batchRequestsSupport)
capabilities: new DefaultSearchCapabilities(req)
};
}
}

View file

@ -62,7 +62,6 @@ describe('DefaultSearchStrategy', () => {
expect(value.isViable).toBe(true);
expect(value.capabilities).toEqual({
request: req,
batchRequestsSupport: true,
fieldsCapabilities: {},
});
});

View file

@ -21,24 +21,16 @@ import { getEsShardTimeout } from '../helpers/get_es_shard_timeout';
import { getIndexPatternObject } from '../helpers/get_index_pattern';
export async function getAnnotationRequestParams(req, panel, annotation, esQueryConfig, capabilities) {
const bodies = [];
const esShardTimeout = await getEsShardTimeout(req);
const indexPattern = annotation.index_pattern;
const { indexPatternObject, indexPatternString } = await getIndexPatternObject(req, indexPattern);
const request = buildAnnotationRequest(req, panel, annotation, esQueryConfig, indexPatternObject, capabilities);
if (capabilities.batchRequestsSupport) {
bodies.push({
index: indexPatternString,
ignoreUnavailable: true,
});
}
if (esShardTimeout > 0) {
request.timeout = `${esShardTimeout}ms`;
}
bodies.push(request);
return bodies;
return {
index: indexPatternString,
body: {
...request,
timeout: esShardTimeout > 0 ? `${esShardTimeout}ms` : undefined,
},
};
}

View file

@ -37,24 +37,23 @@ export async function getAnnotations({
capabilities,
series
}) {
const panelIndexPattern = panel.index_pattern;
const searchRequest = searchStrategy.getSearchRequest(req, panelIndexPattern);
const searchRequest = searchStrategy.getSearchRequest(req);
const annotations = panel.annotations.filter(validAnnotation);
const lastSeriesTimestamp = getLastSeriesTimestamp(series);
const handleAnnotationResponseBy = handleAnnotationResponse(lastSeriesTimestamp);
const bodiesPromises = annotations.map(annotation => getAnnotationRequestParams(req, panel, annotation, esQueryConfig, capabilities));
const body = (await Promise.all(bodiesPromises))
const searches = (await Promise.all(bodiesPromises))
.reduce((acc, items) => acc.concat(items), []);
if (!body.length) return { responses: [] };
if (!searches.length) return { responses: [] };
try {
const responses = await searchRequest.search({ body });
const data = await searchRequest.search(searches);
return annotations
.reduce((acc, annotation, index) => {
acc[annotation.id] = handleAnnotationResponseBy(responses[index], annotation);
acc[annotation.id] = handleAnnotationResponseBy(data[index], annotation);
return acc;
}, {});

View file

@ -25,15 +25,13 @@ import { getEsQueryConfig } from './helpers/get_es_query_uisettings';
import { getActiveSeries } from './helpers/get_active_series';
export async function getSeriesData(req, panel) {
const panelIndexPattern = panel.index_pattern;
const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy(req, panelIndexPattern);
const searchRequest = searchStrategy.getSearchRequest(req, panelIndexPattern);
const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategyForPanel(req, panel);
const searchRequest = searchStrategy.getSearchRequest(req);
const esQueryConfig = await getEsQueryConfig(req);
const bodiesPromises = getActiveSeries(panel)
.map(series => getSeriesRequestParams(req, panel, series, esQueryConfig, capabilities));
const body = (await Promise.all(bodiesPromises))
const searches = (await Promise.all(bodiesPromises))
.reduce((acc, items) => acc.concat(items), []);
const meta = {
@ -42,7 +40,7 @@ export async function getSeriesData(req, panel) {
};
try {
const data = await searchRequest.search({ body });
const data = await searchRequest.search(searches);
const series = data.map(handleResponseBody(panel));
let annotations = null;
@ -50,11 +48,11 @@ export async function getSeriesData(req, panel) {
if (panel.annotations && panel.annotations.length) {
annotations = await getAnnotations({
req,
panel,
series,
esQueryConfig,
searchStrategy,
panel,
capabilities,
series
});
}

View file

@ -27,7 +27,7 @@ import { getIndexPatternObject } from './helpers/get_index_pattern';
export async function getTableData(req, panel) {
const panelIndexPattern = panel.index_pattern;
const { searchStrategy, capabilities } = await SearchStrategiesRegister.getViableStrategy(req, panelIndexPattern);
const searchRequest = searchStrategy.getSearchRequest(req, panelIndexPattern);
const searchRequest = searchStrategy.getSearchRequest(req);
const esQueryConfig = await getEsQueryConfig(req);
const { indexPatternObject } = await getIndexPatternObject(req, panelIndexPattern);
const body = buildRequestBody(req, panel, esQueryConfig, indexPatternObject, capabilities);
@ -38,7 +38,10 @@ export async function getTableData(req, panel) {
};
try {
const [resp] = await searchRequest.search({ body });
const [resp] = await searchRequest.search([{
body,
index: panelIndexPattern,
}]);
const buckets = get(resp, 'aggregations.pivot.buckets', []);
return {

View file

@ -33,6 +33,12 @@ describe('unit_to_seconds', () => {
unit: 'd',
}));
test('should parse "0.5d" interval (positive)', () =>
expect(parseInterval('0.5d')).toEqual({
value: 0.5,
unit: 'd',
}));
test('should parse "30M" interval (positive)', () =>
expect(parseInterval('30M')).toEqual({
value: 30,
@ -65,6 +71,12 @@ describe('unit_to_seconds', () => {
unit: 'h',
}));
test('should convert "0.5h" interval to "m" unit (positive)', () =>
expect(convertIntervalToUnit('0.5h', 'm')).toEqual({
value: 30,
unit: 'm',
}));
test('should convert "1h" interval to "m" unit (positive)', () =>
expect(convertIntervalToUnit('1h', 'm')).toEqual({
value: 60,

View file

@ -52,7 +52,7 @@ describe('dateHistogram(req, panel, series)', () => {
queryStringOptions: {},
};
indexPatternObject = {};
capabilities = new DefaultSearchCapabilities(req, true);
capabilities = new DefaultSearchCapabilities(req);
});
it('calls next when finished', () => {

View file

@ -17,15 +17,13 @@
* under the License.
*/
import { get } from 'lodash';
import { get, isEmpty } from 'lodash';
export function getAnnotationBuckets(resp, annotation) {
return get(resp, `aggregations.${annotation.id}.buckets`, [])
.filter(bucket => bucket.hits.hits.total)
.map((bucket) => {
return {
key: bucket.key,
docs: bucket.hits.hits.hits.map(doc => doc._source)
};
});
.filter(bucket => !isEmpty(bucket.hits.hits.hits))
.map(bucket => ({
key: bucket.key,
docs: bucket.hits.hits.hits.map(doc => doc._source),
}));
}

View file

@ -23,11 +23,13 @@ function mean(values) {
return _.sum(values) / values.length;
}
const extractValue = r => r && r[1] || 0;
const basic = fnName => targetSeries => {
const data = [];
_.zip(...targetSeries).forEach(row => {
const key = row[0][0];
const values = row.map(r => r && r[1] || 0);
const values = row.map(extractValue);
const fn = _[fnName] || (() => null);
data.push([key, fn(values)]);
});
@ -40,7 +42,7 @@ const overall = fnName => targetSeries => {
const values = [];
_.zip(...targetSeries).forEach(row => {
keys.push(row[0][0]);
values.push(fn(row.map(r => r && r[1] || 0)));
values.push(fn(row.map(extractValue)));
});
return [keys.map(k => [k, fn(values)])];
};
@ -54,7 +56,7 @@ export default {
const data = [];
_.zip(...targetSeries).forEach(row => {
const key = row[0][0];
const values = row.map(r => r && r[1] || 0);
const values = row.map(extractValue);
data.push([key, mean(values)]);
});
return [data];
@ -71,7 +73,7 @@ export default {
const values = [];
_.zip(...targetSeries).forEach(row => {
keys.push(row[0][0]);
values.push(_.sum(row.map(r => r && r[1] || 0)));
values.push(_.sum(row.map(extractValue)));
});
return [keys.map(k => [k, fn(values)])];
},
@ -81,10 +83,10 @@ export default {
let sum = 0;
_.zip(...targetSeries).forEach(row => {
const key = row[0][0];
sum += _.sum(row.map(r => r && r[1] || 0));
sum += _.sum(row.map(extractValue));
data.push([key, sum]);
});
return [data];
}
},
};

View file

@ -21,23 +21,16 @@ import { getEsShardTimeout } from '../helpers/get_es_shard_timeout';
import { getIndexPatternObject } from '../helpers/get_index_pattern';
export async function getSeriesRequestParams(req, panel, series, esQueryConfig, capabilities) {
const bodies = [];
const indexPattern = series.override_index_pattern && series.series_index_pattern || panel.index_pattern;
const { indexPatternObject, indexPatternString } = await getIndexPatternObject(req, indexPattern);
const request = buildRequestBody(req, panel, series, esQueryConfig, indexPatternObject, capabilities);
const esShardTimeout = await getEsShardTimeout(req);
if (capabilities.batchRequestsSupport) {
bodies.push({
index: indexPatternString,
});
}
if (esShardTimeout > 0) {
request.timeout = `${esShardTimeout}ms`;
}
bodies.push(request);
return bodies;
return {
index: indexPatternString,
body: {
...request,
timeout: esShardTimeout > 0 ? `${esShardTimeout}ms` : undefined
}
};
}

View file

@ -8,8 +8,8 @@ import { leastCommonInterval, isCalendarInterval } from './lib/interval_helper';
export const getRollupSearchCapabilities = (DefaultSearchCapabilities) =>
(class RollupSearchCapabilities extends DefaultSearchCapabilities {
constructor(req, batchRequestsSupport, fieldsCapabilities, rollupIndex) {
super(req, batchRequestsSupport, fieldsCapabilities);
constructor(req, fieldsCapabilities, rollupIndex) {
super(req, fieldsCapabilities);
this.rollupIndex = rollupIndex;
this.availableMetrics = get(fieldsCapabilities, `${rollupIndex}.aggs`, {});

View file

@ -6,7 +6,7 @@
import { getRollupSearchCapabilities } from './rollup_search_capabilities';
class DefaultSearchCapabilities {
constructor(request, batchRequestsSupport, fieldsCapabilities = {}) {
constructor(request, fieldsCapabilities = {}) {
this.fieldsCapabilities = fieldsCapabilities;
this.parseInterval = jest.fn((interval) => interval);
}
@ -16,7 +16,6 @@ describe('Rollup Search Capabilities', () => {
const testTimeZone = 'time_zone';
const testInterval = '10s';
const rollupIndex = 'rollupIndex';
const batchRequestsSupport = true;
const request = {};
let RollupSearchCapabilities;
@ -38,7 +37,7 @@ describe('Rollup Search Capabilities', () => {
},
};
rollupSearchCaps = new RollupSearchCapabilities(request, batchRequestsSupport, fieldsCapabilities, rollupIndex);
rollupSearchCaps = new RollupSearchCapabilities(request, fieldsCapabilities, rollupIndex);
});
test('should create instance of RollupSearchRequest', () => {
@ -69,7 +68,7 @@ describe('Rollup Search Capabilities', () => {
rollupSearchCaps.getSuitableUnit = jest.fn(() => getSuitableUnit);
});
test('should return 1w as common interval for 5d(user interval) and 1d(rollup interval) - calendar intervals', () => {
test('should return 1d as common interval for 5d(user interval) and 1d(rollup interval) - calendar intervals', () => {
rollupJobInterval = {
value: 1,
unit: 'd',

View file

@ -7,12 +7,11 @@ const SEARCH_METHOD = 'rollup.search';
export const getRollupSearchRequest = (AbstractSearchRequest) =>
(class RollupSearchRequest extends AbstractSearchRequest {
async search(options) {
const bodies = Array.isArray(options.body) ? options.body : [options.body];
const requests = bodies
.map(body => this.callWithRequest(SEARCH_METHOD, {
async search(searches) {
const requests = searches
.map(({ body, index }) => this.callWithRequest(SEARCH_METHOD, {
body,
index: this.indexPattern,
index,
rest_total_hits_as_int: true,
}));

View file

@ -22,30 +22,29 @@ describe('Rollup search request', () => {
expect(rollupSearchRequest).toBeInstanceOf(AbstractSearchRequest);
expect(rollupSearchRequest.search).toBeDefined();
expect(rollupSearchRequest.indexPattern).toBeDefined();
expect(rollupSearchRequest.callWithRequest).toBeDefined();
});
test('should send one request for single search', async () => {
const rollupSearchRequest = new RollupSearchRequest();
const body = 'body';
const searches = [{ body: 'body', index: 'index' }];
await rollupSearchRequest.search({ body });
await rollupSearchRequest.search(searches);
expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledTimes(1);
expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledWith('rollup.search', {
body,
index: 'indexPattern',
body: 'body',
index: 'index',
rest_total_hits_as_int: true,
});
});
test('should send multiple request for multi search', async () => {
const rollupSearchRequest = new RollupSearchRequest();
const body = ['firstRequestBody', 'secondRequestBody'];
const searches = [{ body: 'body', index: 'index' }, { body: 'body1', index: 'index' }];
await rollupSearchRequest.search({ body });
await rollupSearchRequest.search(searches);
expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledTimes(body.length);
expect(rollupSearchRequest.callWithRequest).toHaveBeenCalledTimes(2);
});
});

View file

@ -9,7 +9,6 @@ import { mergeCapabilitiesWithFields } from '../merge_capabilities_with_fields';
import { getCapabilitiesForRollupIndices } from '../map_capabilities';
const ROLLUP_INDEX_CAPABILITIES_METHOD = 'rollup.rollupIndexCapabilities';
const batchRequestsSupport = false;
const getRollupIndices = rollupData => Object.keys(rollupData);
@ -47,7 +46,7 @@ export const getRollupSearchStrategy = (AbstractSearchStrategy, RollupSearchRequ
const [rollupIndex] = rollupIndices;
const fieldsCapabilities = getCapabilitiesForRollupIndices(rollupData);
capabilities = new RollupSearchCapabilities(req, batchRequestsSupport, fieldsCapabilities, rollupIndex);
capabilities = new RollupSearchCapabilities(req, fieldsCapabilities, rollupIndex);
}
}