mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 01:13:23 -04:00
[TSVB] Rollup Search - override index pattern functionality is not working with Rollup search (#36641) (#37078)
This commit is contained in:
parent
ed5fe5fea3
commit
d710b06714
33 changed files with 168 additions and 172 deletions
|
@ -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();
|
||||
}
|
|
@ -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-*',
|
||||
]);
|
||||
});
|
||||
});
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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({});
|
||||
});
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() {
|
||||
|
|
|
@ -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();
|
||||
});
|
||||
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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];
|
||||
|
|
|
@ -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,
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -62,7 +62,6 @@ describe('DefaultSearchStrategy', () => {
|
|||
expect(value.isViable).toBe(true);
|
||||
expect(value.capabilities).toEqual({
|
||||
request: req,
|
||||
batchRequestsSupport: true,
|
||||
fieldsCapabilities: {},
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}, {});
|
||||
|
|
|
@ -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
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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', () => {
|
||||
|
|
|
@ -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),
|
||||
}));
|
||||
}
|
||||
|
|
|
@ -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];
|
||||
}
|
||||
},
|
||||
|
||||
};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
|
@ -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`, {});
|
||||
|
|
|
@ -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',
|
||||
|
|
|
@ -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,
|
||||
}));
|
||||
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue