Skip to content

Commit

Permalink
[eem] _search accepts kql filters (elastic#203089)
Browse files Browse the repository at this point in the history
## Summary

`searchEntities` now accepts kql filters instead of esql and translates
that to dsl filters at the query level
  • Loading branch information
klacabane authored and CAWilson94 committed Dec 12, 2024
1 parent 7cb35dd commit ece6f62
Show file tree
Hide file tree
Showing 5 changed files with 76 additions and 18 deletions.
7 changes: 5 additions & 2 deletions x-pack/plugins/entity_manager/server/lib/v2/entity_client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ export class EntityClient {
);
}

const query = getEntityInstancesQuery({
const { query, filter } = getEntityInstancesQuery({
source: {
...source,
metadata_fields: availableMetadataFields,
Expand All @@ -109,10 +109,13 @@ export class EntityClient {
sort,
limit,
});
this.options.logger.debug(`Entity query: ${query}`);
this.options.logger.debug(
() => `Entity query: ${query}\nfilter: ${JSON.stringify(filter, null, 2)}`
);

const rawEntities = await runESQLQuery<EntityV2>('resolve entities', {
query,
filter,
esClient: this.options.clusterClient.asCurrentUser,
logger: this.options.logger,
});
Expand Down
57 changes: 54 additions & 3 deletions x-pack/plugins/entity_manager/server/lib/v2/queries/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { getEntityInstancesQuery } from '.';
describe('getEntityInstancesQuery', () => {
describe('getEntityInstancesQuery', () => {
it('generates a valid esql query', () => {
const query = getEntityInstancesQuery({
const { query, filter } = getEntityInstancesQuery({
source: {
id: 'service_source',
type_id: 'service',
Expand All @@ -29,14 +29,65 @@ describe('getEntityInstancesQuery', () => {

expect(query).toEqual(
'FROM logs-*, metrics-* | ' +
'WHERE service.name::keyword IS NOT NULL | ' +
'WHERE custom_timestamp_field >= "2024-11-20T19:00:00.000Z" AND custom_timestamp_field <= "2024-11-20T20:00:00.000Z" | ' +
'STATS host.name = VALUES(host.name::keyword), entity.last_seen_timestamp = MAX(custom_timestamp_field), service.id = MAX(service.id::keyword) BY service.name::keyword | ' +
'RENAME `service.name::keyword` AS service.name | ' +
'EVAL entity.type = "service", entity.id = service.name, entity.display_name = COALESCE(service.id, entity.id) | ' +
'SORT entity.id DESC | ' +
'LIMIT 5'
);

expect(filter).toEqual({
bool: {
filter: [
{
bool: {
should: [
{
exists: {
field: 'service.name',
},
},
],
minimum_should_match: 1,
},
},
{
bool: {
filter: [
{
bool: {
should: [
{
range: {
custom_timestamp_field: {
gte: '2024-11-20T19:00:00.000Z',
},
},
},
],
minimum_should_match: 1,
},
},
{
bool: {
should: [
{
range: {
custom_timestamp_field: {
lte: '2024-11-20T20:00:00.000Z',
},
},
},
],
minimum_should_match: 1,
},
},
],
},
},
],
},
});
});
});
});
17 changes: 8 additions & 9 deletions x-pack/plugins/entity_manager/server/lib/v2/queries/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
* 2.0.
*/

import { fromKueryExpression, toElasticsearchQuery } from '@kbn/es-query';
import { asKeyword } from './utils';
import { EntitySourceDefinition, SortBy } from '../types';

Expand All @@ -21,7 +22,7 @@ const sourceCommand = ({ source }: { source: EntitySourceDefinition }) => {
return query;
};

const whereCommand = ({
const dslFilter = ({
source,
start,
end,
Expand All @@ -30,18 +31,16 @@ const whereCommand = ({
start: string;
end: string;
}) => {
const filters = [
source.identity_fields.map((field) => `${asKeyword(field)} IS NOT NULL`).join(' AND '),
...source.filters,
];
const filters = [...source.filters, ...source.identity_fields.map((field) => `${field}: *`)];

if (source.timestamp_field) {
filters.push(
`${source.timestamp_field} >= "${start}" AND ${source.timestamp_field} <= "${end}"`
);
}

return filters.map((filter) => `WHERE ${filter}`).join(' | ');
const kuery = filters.map((filter) => '(' + filter + ')').join(' AND ');
return toElasticsearchQuery(fromKueryExpression(kuery));
};

const statsCommand = ({ source }: { source: EntitySourceDefinition }) => {
Expand Down Expand Up @@ -108,16 +107,16 @@ export function getEntityInstancesQuery({
start: string;
end: string;
sort?: SortBy;
}): string {
}) {
const commands = [
sourceCommand({ source }),
whereCommand({ source, start, end }),
statsCommand({ source }),
renameCommand({ source }),
evalCommand({ source }),
sortCommand({ source, sort }),
`LIMIT ${limit}`,
];
const filter = dslFilter({ source, start, end });

return commands.join(' | ');
return { query: commands.join(' | '), filter };
}
11 changes: 8 additions & 3 deletions x-pack/plugins/entity_manager/server/lib/v2/run_esql_query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

import { withSpan } from '@kbn/apm-utils';
import { ElasticsearchClient, Logger } from '@kbn/core/server';
import { QueryDslQueryContainer } from '@elastic/elasticsearch/lib/api/types';
import { ESQLColumn, ESQLRow, ESQLSearchResponse } from '@kbn/es-types';

export interface SourceAs<T> {
Expand All @@ -19,19 +20,24 @@ export async function runESQLQuery<T>(
esClient,
logger,
query,
filter,
}: {
esClient: ElasticsearchClient;
logger: Logger;
query: string;
filter?: QueryDslQueryContainer;
}
): Promise<T[]> {
logger.trace(() => `Request (${operationName}):\n${query}`);
logger.trace(
() => `Request (${operationName}):\nquery: ${query}\nfilter: ${JSON.stringify(filter, null, 2)}`
);
return withSpan(
{ name: operationName, labels: { plugin: '@kbn/entityManager-plugin' } },
async () =>
esClient.esql.query(
{
query,
filter,
format: 'json',
},
{ querystring: { drop_null_columns: true } }
Expand Down Expand Up @@ -62,8 +68,7 @@ function rowToObject(row: ESQLRow, columns: ESQLColumn[]) {
return object;
}

// Removes the type suffix from the column name
const name = column.name.replace(/\.(text|keyword)$/, '');
const name = column.name;
if (!object[name]) {
object[name] = value;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ function EntitySourceForm({
</EuiFlexItem>

<EuiFlexItem>
<EuiFormRow label="Filters (comma-separated ESQL filters)">
<EuiFormRow label="Filters (comma-separated KQL filters)">
<EuiFieldText
data-test-subj="entityManagerFormFilters"
name="filters"
Expand Down

0 comments on commit ece6f62

Please sign in to comment.