Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
0e937a9
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Feb 6, 2025
7ffbf4c
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Feb 10, 2025
b426318
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Feb 13, 2025
511ccaa
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Feb 14, 2025
2d71300
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Feb 18, 2025
0076de9
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Feb 21, 2025
2898ce1
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Feb 24, 2025
ace0009
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 3, 2025
6cdd8c1
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 4, 2025
98616e9
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 6, 2025
64e40fd
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 7, 2025
1e3f8d1
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 11, 2025
afd5630
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 13, 2025
31c6cb3
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 18, 2025
08f4b1b
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 18, 2025
0c11f55
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 20, 2025
de2bc7a
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 21, 2025
828d142
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Mar 25, 2025
34bd1ef
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 1, 2025
f0070c6
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 3, 2025
16a27c7
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 3, 2025
cde697e
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 8, 2025
8b66178
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 10, 2025
3555b0c
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 14, 2025
57a5f4a
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 16, 2025
420eb2b
Merge branch 'main' of github.com:elastic/kibana
drewdaemon Apr 29, 2025
8e5e4a8
Merge branch 'main' of github.com:elastic/kibana
drewdaemon May 5, 2025
141765f
Merge branch 'main' of github.com:elastic/kibana
drewdaemon May 21, 2025
cdf4d20
Merge branch 'main' of github.com:elastic/kibana
drewdaemon May 23, 2025
135795f
add sample command to AST
drewdaemon May 23, 2025
dc6ab94
Merge branch 'main' of github.com:elastic/kibana into 217977/support-…
drewdaemon May 27, 2025
dac4ab5
add AST apis
drewdaemon May 27, 2025
12fdf3b
Autocomplete
drewdaemon May 28, 2025
1a04a78
Merge branch 'main' into 217977/support-sample
stratoula May 30, 2025
8eb2a14
Merge branch 'main' of github.com:elastic/kibana into 217977/support-…
drewdaemon May 30, 2025
36bd43e
fix type
drewdaemon May 30, 2025
ea86f80
comment for regex
drewdaemon May 30, 2025
c79cf30
Merge branch 'main' into 217977/support-sample
stratoula Jun 2, 2025
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
@@ -0,0 +1,96 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { Parser } from '../parser';

describe('SAMPLE', () => {
describe('correctly formatted', () => {
test('without seed', () => {
const text = `
FROM employees
| SAMPLE 0.25
`;
const { ast, errors } = Parser.parse(text);

expect(errors.length).toBe(0);
expect(ast).toMatchObject([
{},
{
type: 'command',
name: 'sample',
args: [
{
type: 'literal',
literalType: 'double',
value: 0.25,
},
],
},
]);
});

test('with seed', () => {
const text = `
FROM employees
| SAMPLE 0.25 123
`;
const { ast, errors } = Parser.parse(text);

expect(errors.length).toBe(0);
expect(ast).toMatchObject([
{},
{
type: 'command',
name: 'sample',
args: [
{
type: 'literal',
literalType: 'double',
value: 0.25,
},
{
type: 'literal',
literalType: 'integer',
value: 123,
},
],
},
]);
});
});

describe('errors', () => {
it('wrong data type for probability', () => {
const { errors } = Parser.parse(`
FROM employees
| SAMPLE 25
`);

expect(errors.length).toBe(1);
});

it('wrong data type for seed', () => {
const { errors } = Parser.parse(`
FROM employees
| SAMPLE .25 .123
`);

expect(errors.length).toBe(1);
});

it('command with no args', () => {
const { errors } = Parser.parse(`
FROM employees
| SAMPLE
`);

expect(errors.length).toBe(1);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,11 @@ import {
type WhereCommandContext,
RerankCommandContext,
RrfCommandContext,
SampleCommandContext,
} from '../antlr/esql_parser';
import { default as ESQLParserListener } from '../antlr/esql_parser_listener';
import type { ESQLAst } from '../types';
import { createCommand, createFunction, textExistsAndIsValid } from './factories';
import { createCommand, createFunction, createLiteral, textExistsAndIsValid } from './factories';
import { createChangePointCommand } from './factories/change_point';
import { createDissectCommand } from './factories/dissect';
import { createEvalCommand } from './factories/eval';
Expand Down Expand Up @@ -352,6 +353,18 @@ export class ESQLAstBuilderListener implements ESQLParserListener {
this.ast.push(command);
}

exitSampleCommand(ctx: SampleCommandContext): void {
const command = createCommand('sample', ctx);
this.ast.push(command);

if (ctx._probability) {
command.args.push(createLiteral('double', ctx._probability.DECIMAL_LITERAL()));
}
if (ctx._seed) {
command.args.push(createLiteral('integer', ctx._seed.INTEGER_LITERAL()));
}
}

/**
* Exit a parse tree produced by `esql_parser.rrfCommand`.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,22 @@ describe('single line query', () => {
});
});

describe('SAMPLE', () => {
test('from single line', () => {
const { text } = reprint(`FROM index | SAMPLE 0.1 123`);

expect(text).toBe('FROM index | SAMPLE 0.1 123');
});

test('from multiline', () => {
const { text } = reprint(`FROM index
| SAMPLE 0.1 123
`);

expect(text).toBe('FROM index | SAMPLE 0.1 123');
});
});

describe('RRF', () => {
test('from single line', () => {
const { text } =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
* DISSECT input "pattern"
* ```
*/
export const commandsWithNoCommaArgSeparator = new Set(['grok', 'dissect']);
export const commandsWithNoCommaArgSeparator = new Set(['grok', 'dissect', 'sample']);

/**
* This set tracks command options which use an equals sign to separate
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,13 @@ test('can create a RERANK command', () => {
);
});

test('can create a SAMPLE command', () => {
const node = cmd`SAMPLE 0.23 123`;
const text = node.toString();

expect(text).toBe('SAMPLE 0.23 123');
});

test('can create a complex STATS command', () => {
const node = cmd`STATS count_last_hour = SUM(count_last_hour), total_visits = SUM(total_visits), bytes_transform = SUM(bytes_transform), bytes_transform_last_hour = SUM(bytes_transform_last_hour) BY extension.keyword`;
const text = BasicPrettyPrinter.command(node);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -520,6 +520,12 @@ export class ForkCommandVisitorContext<
Data extends SharedData = SharedData
> extends CommandVisitorContext<Methods, Data, ESQLAstCommand> {}

// SAMPLE <probability> [SEED <seed>]
export class SampleCommandVisitorContext<
Methods extends VisitorMethods = VisitorMethods,
Data extends SharedData = SharedData
> extends CommandVisitorContext<Methods, Data, ESQLAstCommand> {}

// RRF
export class RrfCommandVisitorContext<
Methods extends VisitorMethods = VisitorMethods,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,10 @@ export class GlobalVisitorContext<
if (!this.methods.visitForkCommand) break;
return this.visitForkCommand(parent, commandNode, input as any);
}
case 'sample': {
if (!this.methods.visitSampleCommand) break;
return this.visitSampleCommand(parent, commandNode, input as any);
}
case 'rrf': {
if (!this.methods.visitRrfCommand) break;
return this.visitRrfCommand(parent, commandNode, input as any);
Expand Down Expand Up @@ -421,6 +425,15 @@ export class GlobalVisitorContext<
return this.visitWithSpecificContext('visitForkCommand', context, input);
}

public visitSampleCommand(
parent: contexts.VisitorContext | null,
node: ESQLAstCommand,
input: types.VisitorInput<Methods, 'visitSampleCommand'>
): types.VisitorOutput<Methods, 'visitSampleCommand'> {
const context = new contexts.ForkCommandVisitorContext(this, node, parent);
return this.visitWithSpecificContext('visitSampleCommand', context, input);
}

public visitRrfCommand(
parent: contexts.VisitorContext | null,
node: ESQLAstCommand,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ export interface VisitorMethods<
any
>;
visitForkCommand?: Visitor<contexts.ForkCommandVisitorContext<Visitors, Data>, any, any>;
visitSampleCommand?: Visitor<contexts.SampleCommandVisitorContext<Visitors, Data>, any, any>;
visitCommandOption?: Visitor<contexts.CommandOptionVisitorContext<Visitors, Data>, any, any>;
visitRrfCommand?: Visitor<contexts.RrfCommandVisitorContext<Visitors, Data>, any, any>;
visitExpression?: Visitor<contexts.ExpressionVisitorContext<Visitors, Data>, any, any>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

import { parse } from '../parser';
import { Parser } from '../parser/parser';
import {
ESQLColumn,
ESQLCommand,
Expand Down Expand Up @@ -106,6 +107,21 @@ describe('structurally can walk all nodes', () => {
expect(columns.map(({ name }) => name).sort()).toStrictEqual(['c', 'd']);
});

test('can traverse SAMPLE command', () => {
const { root } = Parser.parse('FROM index | SAMPLE 0.25');
const commands: ESQLCommand[] = [];
const literals: ESQLLiteral[] = [];

walk(root, {
visitCommand: (cmd) => commands.push(cmd),
visitLiteral: (lit) => literals.push(lit),
});

expect(commands.map(({ name }) => name).sort()).toStrictEqual(['from', 'sample']);
expect(literals.length).toBe(1);
expect(literals[0].value).toBe(0.25);
});

test('"visitAny" can capture command nodes', () => {
const { ast } = parse('FROM index | STATS a = 123 | WHERE 123 | LIMIT 10');
const commands: ESQLCommand[] = [];
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/
import { setup } from './helpers';

describe('autocomplete.suggest', () => {
describe('SAMPLE <percentage> [<seed>]', () => {
test('suggests percentages', async () => {
const { assertSuggestions } = await setup();
assertSuggestions('from a | SAMPLE /', ['.1 ', '.01 ', '.001 ']);
});

test('suggests pipe after number', async () => {
const { assertSuggestions } = await setup();
assertSuggestions('from a | SAMPLE .48 /', ['| ']);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import { getDateHistogramCompletionItem } from './commands/stats/util';
import { getSafeInsertText, TIME_SYSTEM_PARAMS, TRIGGER_SUGGESTION_COMMAND } from './factories';
import { getRecommendedQueries } from './recommended_queries/templates';

const commandDefinitions = unmodifiedCommandDefinitions.filter(({ hidden }) => !hidden);
const commandDefinitions = unmodifiedCommandDefinitions.filter(
({ name, hidden }) => !hidden && name !== 'rrf'
);

const getRecommendedQueriesSuggestions = (fromCommand: string, timeField?: string) =>
getRecommendedQueries({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

import { CommandSuggestParams } from '../../../definitions/types';
import type { SuggestionRawDefinition } from '../../types';
import { buildConstantsDefinitions } from '../../factories';
import { pipeCompleteItem } from '../../complete_items';

export function suggest({ innerText }: CommandSuggestParams<'sample'>): SuggestionRawDefinition[] {
// test for a number and at least one whitespace char at the end of the innerText
if (/[0-9]\s+$/.test(innerText)) {
return [pipeCompleteItem];
}

return buildConstantsDefinitions(['.1', '.01', '.001'], '', undefined, {
advanceCursorAndOpenSuggestions: true,
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ import {
suggest as suggestForChangePoint,
fieldsSuggestionsAfter as fieldsSuggestionsAfterChangePoint,
} from '../autocomplete/commands/change_point';
import { suggest as suggestForSample } from '../autocomplete/commands/sample';

import { METADATA_FIELDS } from '../shared/constants';
import { getMessageFromId } from '../validation/errors';
Expand Down Expand Up @@ -710,6 +711,17 @@ export const commandDefinitions: Array<CommandDefinition<any>> = [
},
{
hidden: true,
name: 'sample',
preview: true,
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.sampleDoc', {
defaultMessage:
'Samples a percentage of the results, optionally with a seed for reproducibility.',
}),
declaration: `SAMPLE <percentage> [<seed>]`,
examples: [],
suggest: suggestForSample,
},
{
preview: true,
name: 'rrf',
description: i18n.translate('kbn-esql-validation-autocomplete.esql.definitions.rrfDoc', {
Expand Down