Skip to content

Commit d514c50

Browse files
committed
feat: Add additional MV granularity options
1 parent 87d9f3c commit d514c50

File tree

4 files changed

+58
-14
lines changed

4 files changed

+58
-14
lines changed

.changeset/purple-bats-smile.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"@hyperdx/api": patch
3+
"@hyperdx/app": patch
4+
---
5+
6+
feat: Add MV granularities and infer config from SummingMergeTree

packages/app/src/components/SourceForm.tsx

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
import {
5858
inferMaterializedViewConfig,
5959
MV_AGGREGATE_FUNCTIONS,
60+
MV_GRANULARITY_OPTIONS,
6061
} from '@/utils/materializedViews';
6162

6263
import ConfirmDeleteMenu from './ConfirmDeleteMenu';
@@ -69,15 +70,6 @@ import { SQLInlineEditorControlled } from './SQLInlineEditor';
6970

7071
const DEFAULT_DATABASE = 'default';
7172

72-
const MV_GRANULARITY_OPTIONS = [
73-
{ value: '1 second', label: '1 second' },
74-
{ value: '1 minute', label: '1 minute' },
75-
{ value: '5 minute', label: '5 minutes' },
76-
{ value: '15 minute', label: '15 minutes' },
77-
{ value: '1 hour', label: '1 hour' },
78-
{ value: '1 day', label: '1 day' },
79-
];
80-
8173
const MV_AGGREGATE_FUNCTION_OPTIONS = MV_AGGREGATE_FUNCTIONS.map(fn => ({
8274
value: fn,
8375
label: fn,
@@ -551,12 +543,14 @@ function AggregatedColumnsFormSection({
551543
replaceAggregates(config.aggregatedColumns ?? []);
552544
notifications.show({
553545
color: 'green',
546+
id: 'mv-infer-success',
554547
message:
555548
'Partially inferred materialized view configuration from view schema.',
556549
});
557550
} else {
558551
notifications.show({
559552
color: 'yellow',
553+
id: 'mv-infer-failure',
560554
message: 'Unable to infer materialized view configuration.',
561555
});
562556
}

packages/app/src/utils/__tests__/materializedViews.test.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,12 @@ describe('inferTimestampColumnGranularity', () => {
446446
{
447447
expected: '5 minute',
448448
asSelect:
449-
'SELECT toStartOfInterval(Timestamp, interval 5 minute) AS Timestamp, ServiceName, quantileState(0.9)(Duration) AS p90__Duration FROM default.otel_traces GROUP BY Timestamp, ServiceName',
449+
'SELECT toStartOfInterval(Timestamp, interval 5 minutes) AS Timestamp, ServiceName, quantileState(0.9)(Duration) AS p90__Duration FROM default.otel_traces GROUP BY Timestamp, ServiceName',
450+
},
451+
{
452+
expected: '30 minute',
453+
asSelect:
454+
'SELECT toStartOfInterval(Timestamp, toIntervalMinute(30)) AS Timestamp, ServiceName, quantileState(0.9)(Duration) AS p90__Duration FROM default.otel_traces GROUP BY Timestamp, ServiceName',
450455
},
451456
])(
452457
'should handle a toStartOfInterval function with a dynamic interval: $expected',

packages/app/src/utils/materializedViews.ts

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@ import {
77
TableConnection,
88
TableMetadata,
99
} from '@hyperdx/common-utils/dist/core/metadata';
10-
import { splitAndTrimWithBracket } from '@hyperdx/common-utils/dist/core/utils';
10+
import {
11+
Granularity,
12+
splitAndTrimWithBracket,
13+
} from '@hyperdx/common-utils/dist/core/utils';
1114
import {
1215
InternalAggregateFunction,
1316
MaterializedViewConfiguration,
@@ -25,6 +28,36 @@ export const MV_AGGREGATE_FUNCTIONS = [
2528
'histogram',
2629
];
2730

31+
/**
32+
* To maximize the number of queries which are compatible with materialized views,
33+
* every granularity should be a multiple of every smaller granularity.
34+
*
35+
* Further, these should match the granularities supported by charts, defined
36+
* in convertDateRangeToGranularityString().
37+
* */
38+
export const MV_GRANULARITY_OPTIONS = [
39+
{ value: Granularity.FifteenSecond, label: '15 seconds' },
40+
{ value: Granularity.ThirtySecond, label: '30 seconds' },
41+
{ value: Granularity.OneMinute, label: '1 minute' },
42+
{ value: Granularity.FiveMinute, label: '5 minutes' },
43+
{ value: Granularity.FifteenMinute, label: '15 minutes' },
44+
{ value: Granularity.ThirtyMinute, label: '30 minutes' },
45+
{ value: Granularity.OneHour, label: '1 hour' },
46+
{ value: Granularity.TwoHour, label: '2 hours' },
47+
{ value: Granularity.SixHour, label: '6 hours' },
48+
{ value: Granularity.TwelveHour, label: '12 hours' },
49+
{ value: Granularity.OneDay, label: '1 day' },
50+
{ value: Granularity.TwoDay, label: '2 days' },
51+
{ value: Granularity.SevenDay, label: '7 days' },
52+
{ value: Granularity.ThirtyDay, label: '30 days' },
53+
];
54+
55+
const isGranularity = (value: string): value is Granularity => {
56+
return MV_GRANULARITY_OPTIONS.map(option => option.value as string).includes(
57+
value,
58+
);
59+
};
60+
2861
const MV_DDL_PATTERN = /MATERIALIZED VIEW [^\s]+\.[^\s]+ TO ([^\s]+)\.([^\s]+)/;
2962
function getViewTargetTable(meta: TableMetadata) {
3063
const match = meta.create_table_query.match(MV_DDL_PATTERN);
@@ -183,14 +216,20 @@ export function inferTimestampColumnGranularity(
183216
// Only accept specific granularities matching the ones defined above
184217
if (timestampExpression.includes(`toStartOfInterval(`)) {
185218
const intervalMatch = timestampExpression.match(
186-
/INTERVAL\s+(\d+)\s+(SECOND|MINUTE|HOUR|DAY)\)/i,
219+
/INTERVAL\s+(\d+)\s+(SECOND|MINUTE|HOUR|DAY)S?\)/i,
220+
);
221+
const intervalFunctionMatch = timestampExpression.match(
222+
/toInterval(Second|Minute|Hour|Day)\((\d+)\)/,
187223
);
188224
const granularity = intervalMatch
189225
? `${intervalMatch[1]} ${intervalMatch[2].toLowerCase()}`
190-
: '';
226+
: intervalFunctionMatch
227+
? `${intervalFunctionMatch[2]} ${intervalFunctionMatch[1].toLowerCase()}`
228+
: null;
191229
if (
192230
granularity &&
193-
Object.values(intervalToGranularityMap).includes(granularity)
231+
isGranularity(granularity) &&
232+
MV_GRANULARITY_OPTIONS.map(option => option.value).includes(granularity)
194233
) {
195234
return granularity;
196235
}

0 commit comments

Comments
 (0)