Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Expand Up @@ -2,9 +2,9 @@ import { screen } from '@testing-library/react';
import React from 'react';
import selectEvent from 'react-select-event';

import { ElasticsearchQuery, Terms, Average, Derivative, TopMetrics } from '@/types';
import { ElasticsearchQuery, Terms, Average, Derivative, TopMetrics, Percentiles } from '@/types';

import { TermsSettingsEditor } from './TermsSettingsEditor';
import { TermsSettingsEditor, createOrderByOptions } from './TermsSettingsEditor';
import { describeMetric } from 'utils';
import { renderWithESProvider } from 'test-helpers/render';

Expand Down Expand Up @@ -39,4 +39,18 @@ describe('Terms Settings Editor', () => {
// All other metric aggregations can be used in order by
expect(await screen.findByText(describeMetric(avg))).toBeInTheDocument();
});

it('Order by option value for a whole-number percentile should not append ".0"', () => {
// Quickwit's aggregation engine names the percentile sub-aggregation after the
// percent value exactly as sent in the request (e.g. "95"), unlike Elasticsearch
// which requires a ".0" suffix for whole-number bucket paths (e.g. "95.0").
// Sending an orderBy of "1[95.0]" makes Quickwit fail with
// "could not find aggregation with name 1[95] in metric sub_aggregations".
const percentiles: Percentiles = { id: '1', type: 'percentiles', field: '@value', settings: { percents: ['95'] } };

const options = createOrderByOptions([percentiles]);

expect(options.some((option) => option.value === '1[95]')).toBe(true);
expect(options.some((option) => option.value === '1[95.0]')).toBe(false);
});
Comment on lines +43 to +55

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This asserts the broken behaviour: 1[95] is exactly the value Quickwit rejects. Worth asserting no percentile option is produced instead.

Suggested change
it('Order by option value for a whole-number percentile should not append ".0"', () => {
// Quickwit's aggregation engine names the percentile sub-aggregation after the
// percent value exactly as sent in the request (e.g. "95"), unlike Elasticsearch
// which requires a ".0" suffix for whole-number bucket paths (e.g. "95.0").
// Sending an orderBy of "1[95.0]" makes Quickwit fail with
// "could not find aggregation with name 1[95] in metric sub_aggregations".
const percentiles: Percentiles = { id: '1', type: 'percentiles', field: '@value', settings: { percents: ['95'] } };
const options = createOrderByOptions([percentiles]);
expect(options.some((option) => option.value === '1[95]')).toBe(true);
expect(options.some((option) => option.value === '1[95.0]')).toBe(false);
});
it('Percentiles should not be in "order by" options', () => {
// Quickwit refuses percentiles as an order target whatever bucket path is used, failing with
// `InvalidRequest: "percentiles can't be used to order"`, so they must not be offered at all.
const percentiles: Percentiles = { id: '1', type: 'percentiles', field: '@value', settings: { percents: ['95'] } };
const options = createOrderByOptions([percentiles]);
expect(options.every((option) => !option.value?.startsWith('1'))).toBe(true);
});

});
Original file line number Diff line number Diff line change
Expand Up @@ -123,10 +123,10 @@ function createOrderByOptionsForPercentiles(metric: Percentiles): Array<Selectab
return [];
}
return metric.settings.percents.map((percent) => {
// The bucket path for percentile numbers is appended with a `.0` if the number is whole
// otherwise you have to use the actual value.
const percentString = /^\d+\.\d+/.test(`${percent}`) ? percent : `${percent}.0`;
return { label: `${describeMetric(metric)} (${percent})`, value: `${metric.id}[${percentString}]` };
// Unlike Elasticsearch, Quickwit's aggregation engine names the percentile
// sub-aggregation after the percent value exactly as sent in the request
// (e.g. "95"), without appending `.0` for whole numbers.
return { label: `${describeMetric(metric)} (${percent})`, value: `${metric.id}[${percent}]` };
});
}
Comment on lines 125 to 131

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Percentiles can't be an order target in Quickwit at all, so this should return nothing rather than a differently-spelled path.

Suggested change
return metric.settings.percents.map((percent) => {
// The bucket path for percentile numbers is appended with a `.0` if the number is whole
// otherwise you have to use the actual value.
const percentString = /^\d+\.\d+/.test(`${percent}`) ? percent : `${percent}.0`;
return { label: `${describeMetric(metric)} (${percent})`, value: `${metric.id}[${percentString}]` };
// Unlike Elasticsearch, Quickwit's aggregation engine names the percentile
// sub-aggregation after the percent value exactly as sent in the request
// (e.g. "95"), without appending `.0` for whole numbers.
return { label: `${describeMetric(metric)} (${percent})`, value: `${metric.id}[${percent}]` };
});
}
// Quickwit refuses percentiles as an order target whatever bucket path is used, failing with
// `InvalidRequest: "percentiles can't be used to order"`, so don't offer them at all.
return [];
}

See the review body for the tidier version, which drops this function entirely and gates percentiles in isValidOrderTarget.


Expand Down
Loading