mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
Kuery/KQL: Support not passing an index pattern (#28010)
* Support not sending index pattern to Kuery functions * fix match all inside is
This commit is contained in:
parent
9311f19732
commit
5de724f772
11 changed files with 80 additions and 7 deletions
|
@ -52,6 +52,8 @@ function fromExpression(expression, parseOptions = {}, parse = parseKuery) {
|
|||
return parse(expression, parseOptions);
|
||||
}
|
||||
|
||||
// indexPattern isn't required, but if you pass one in, we can be more intelligent
|
||||
// about how we craft the queries (e.g. scripted fields)
|
||||
export function toElasticsearchQuery(node, indexPattern) {
|
||||
if (!node || !node.type || !nodeTypes[node.type]) {
|
||||
return toElasticsearchQuery(nodeTypes.function.buildNode('and', []));
|
||||
|
|
|
@ -57,12 +57,21 @@ describe('kuery functions', function () {
|
|||
expect(_.isEqual(expected, result)).to.be(true);
|
||||
});
|
||||
|
||||
it('should return an ES exists query without an index pattern', function () {
|
||||
const expected = {
|
||||
exists: { field: 'response' }
|
||||
};
|
||||
|
||||
const existsNode = nodeTypes.function.buildNode('exists', 'response');
|
||||
const result = exists.toElasticsearchQuery(existsNode);
|
||||
expect(_.isEqual(expected, result)).to.be(true);
|
||||
});
|
||||
|
||||
it('should throw an error for scripted fields', function () {
|
||||
const existsNode = nodeTypes.function.buildNode('exists', 'script string');
|
||||
expect(exists.toElasticsearchQuery)
|
||||
.withArgs(existsNode, indexPattern).to.throwException(/Exists query does not support scripted fields/);
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -83,6 +83,14 @@ describe('kuery functions', function () {
|
|||
expect(result.geo_bounding_box.geo).to.have.property('bottom_right', '50.73, -135.35');
|
||||
});
|
||||
|
||||
it('should return an ES geo_bounding_box query without an index pattern', function () {
|
||||
const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params);
|
||||
const result = geoBoundingBox.toElasticsearchQuery(node);
|
||||
expect(result).to.have.property('geo_bounding_box');
|
||||
expect(result.geo_bounding_box.geo).to.have.property('top_left', '73.12, -174.37');
|
||||
expect(result.geo_bounding_box.geo).to.have.property('bottom_right', '50.73, -135.35');
|
||||
});
|
||||
|
||||
it('should use the ignore_unmapped parameter', function () {
|
||||
const node = nodeTypes.function.buildNode('geoBoundingBox', 'geo', params);
|
||||
const result = geoBoundingBox.toElasticsearchQuery(node, indexPattern);
|
||||
|
|
|
@ -91,6 +91,17 @@ describe('kuery functions', function () {
|
|||
});
|
||||
});
|
||||
|
||||
it('should return an ES geo_polygon query without an index pattern', function () {
|
||||
const node = nodeTypes.function.buildNode('geoPolygon', 'geo', points);
|
||||
const result = geoPolygon.toElasticsearchQuery(node);
|
||||
expect(result).to.have.property('geo_polygon');
|
||||
expect(result.geo_polygon.geo).to.have.property('points');
|
||||
|
||||
result.geo_polygon.geo.points.forEach((point, index) => {
|
||||
const expectedLatLon = `${points[index].lat}, ${points[index].lon}`;
|
||||
expect(point).to.be(expectedLatLon);
|
||||
});
|
||||
});
|
||||
|
||||
it('should use the ignore_unmapped parameter', function () {
|
||||
const node = nodeTypes.function.buildNode('geoPolygon', 'geo', points);
|
||||
|
|
|
@ -143,6 +143,21 @@ describe('kuery functions', function () {
|
|||
expect(result).to.eql(expected);
|
||||
});
|
||||
|
||||
it('should return an ES match query when a concrete fieldName and value are provided without an index pattern', function () {
|
||||
const expected = {
|
||||
bool: {
|
||||
should: [
|
||||
{ match: { extension: 'jpg' } },
|
||||
],
|
||||
minimum_should_match: 1
|
||||
}
|
||||
};
|
||||
|
||||
const node = nodeTypes.function.buildNode('is', 'extension', 'jpg');
|
||||
const result = is.toElasticsearchQuery(node);
|
||||
expect(result).to.eql(expected);
|
||||
});
|
||||
|
||||
it('should support creation of phrase queries', function () {
|
||||
const expected = {
|
||||
bool: {
|
||||
|
|
|
@ -86,6 +86,28 @@ describe('kuery functions', function () {
|
|||
expect(result).to.eql(expected);
|
||||
});
|
||||
|
||||
it('should return an ES range query without an index pattern', function () {
|
||||
const expected = {
|
||||
bool: {
|
||||
should: [
|
||||
{
|
||||
range: {
|
||||
bytes: {
|
||||
gt: 1000,
|
||||
lt: 8000
|
||||
}
|
||||
}
|
||||
}
|
||||
],
|
||||
minimum_should_match: 1
|
||||
}
|
||||
};
|
||||
|
||||
const node = nodeTypes.function.buildNode('range', 'bytes', { gt: 1000, lt: 8000 });
|
||||
const result = range.toElasticsearchQuery(node);
|
||||
expect(result).to.eql(expected);
|
||||
});
|
||||
|
||||
it('should support wildcard field names', function () {
|
||||
const expected = {
|
||||
bool: {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import * as literal from '../node_types/literal';
|
||||
|
||||
export function buildNodeParams(fieldName) {
|
||||
|
@ -28,7 +29,7 @@ export function buildNodeParams(fieldName) {
|
|||
export function toElasticsearchQuery(node, indexPattern) {
|
||||
const { arguments: [ fieldNameArg ] } = node;
|
||||
const fieldName = literal.toElasticsearchQuery(fieldNameArg);
|
||||
const field = indexPattern.fields.find(field => field.name === fieldName);
|
||||
const field = get(indexPattern, 'fields', []).find(field => field.name === fieldName);
|
||||
|
||||
if (field && field.scripted) {
|
||||
throw new Error(`Exists query does not support scripted fields`);
|
||||
|
|
|
@ -37,7 +37,7 @@ export function buildNodeParams(fieldName, params) {
|
|||
export function toElasticsearchQuery(node, indexPattern) {
|
||||
const [ fieldNameArg, ...args ] = node.arguments;
|
||||
const fieldName = nodeTypes.literal.toElasticsearchQuery(fieldNameArg);
|
||||
const field = indexPattern.fields.find(field => field.name === fieldName);
|
||||
const field = _.get(indexPattern, 'fields', []).find(field => field.name === fieldName);
|
||||
const queryParams = args.reduce((acc, arg) => {
|
||||
const snakeArgName = _.snakeCase(arg.name);
|
||||
return {
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* under the License.
|
||||
*/
|
||||
|
||||
import { get } from 'lodash';
|
||||
import { nodeTypes } from '../node_types';
|
||||
import * as ast from '../ast';
|
||||
|
||||
|
@ -35,7 +36,7 @@ export function buildNodeParams(fieldName, points) {
|
|||
export function toElasticsearchQuery(node, indexPattern) {
|
||||
const [ fieldNameArg, ...points ] = node.arguments;
|
||||
const fieldName = nodeTypes.literal.toElasticsearchQuery(fieldNameArg);
|
||||
const field = indexPattern.fields.find(field => field.name === fieldName);
|
||||
const field = get(indexPattern, 'fields', []).find(field => field.name === fieldName);
|
||||
const queryParams = {
|
||||
points: points.map(ast.toElasticsearchQuery)
|
||||
};
|
||||
|
|
|
@ -44,6 +44,7 @@ export function buildNodeParams(fieldName, value, isPhrase = false) {
|
|||
export function toElasticsearchQuery(node, indexPattern) {
|
||||
const { arguments: [ fieldNameArg, valueArg, isPhraseArg ] } = node;
|
||||
|
||||
const fieldName = ast.toElasticsearchQuery(fieldNameArg);
|
||||
const value = !_.isUndefined(valueArg) ? ast.toElasticsearchQuery(valueArg) : valueArg;
|
||||
const type = isPhraseArg.value ? 'phrase' : 'best_fields';
|
||||
|
||||
|
@ -65,7 +66,7 @@ export function toElasticsearchQuery(node, indexPattern) {
|
|||
};
|
||||
}
|
||||
|
||||
const fields = getFields(fieldNameArg, indexPattern);
|
||||
const fields = indexPattern ? getFields(fieldNameArg, indexPattern) : [];
|
||||
|
||||
// If no fields are found in the index pattern we send through the given field name as-is. We do this to preserve
|
||||
// the behaviour of lucene on dashboards where there are panels based on different index patterns that have different
|
||||
|
@ -80,7 +81,10 @@ export function toElasticsearchQuery(node, indexPattern) {
|
|||
}
|
||||
|
||||
const isExistsQuery = valueArg.type === 'wildcard' && value === '*';
|
||||
const isMatchAllQuery = isExistsQuery && fields && fields.length === indexPattern.fields.length;
|
||||
const isAllFieldsQuery =
|
||||
(fieldNameArg.type === 'wildcard' && fieldName === '*')
|
||||
|| (fields && indexPattern && fields.length === indexPattern.fields.length);
|
||||
const isMatchAllQuery = isExistsQuery && isAllFieldsQuery;
|
||||
|
||||
if (isMatchAllQuery) {
|
||||
return { match_all: {} };
|
||||
|
|
|
@ -37,7 +37,7 @@ export function buildNodeParams(fieldName, params) {
|
|||
|
||||
export function toElasticsearchQuery(node, indexPattern) {
|
||||
const [ fieldNameArg, ...args ] = node.arguments;
|
||||
const fields = getFields(fieldNameArg, indexPattern);
|
||||
const fields = indexPattern ? getFields(fieldNameArg, indexPattern) : [];
|
||||
const namedArgs = extractArguments(args);
|
||||
const queryParams = _.mapValues(namedArgs, ast.toElasticsearchQuery);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue