Skip to content

Commit a89b324

Browse files
authored
feat: fetch key limit now applies per map (#3392)
## Summary The fetch key limit now applies per map. Previously, the behavior was a bit random. If you find 100 LogAttributes, often times the ResourceAttributes wouldn't display in the filters at all, and values would not be fetched for any ResourceAttribute columns. Now, for a fetch key limit of n, there will be n keys attempting to fetch values instead of 100 total across all maps. ### References - Linear Issue: Closes HDX-5752
1 parent e3f24b9 commit a89b324

4 files changed

Lines changed: 95 additions & 4 deletions

File tree

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
---
2+
'@hyperdx/app': patch
3+
---
4+
5+
fix: the search page filter key limit (Filter Keys Fetch Limit, default 100)
6+
now applies to each Map column, so keys from `LogAttributes` no longer crowd out
7+
`ResourceAttributes` and other Map columns

‎packages/app/src/components/TeamSettings/TeamQueryConfigSection.tsx‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -319,7 +319,7 @@ export default function TeamQueryConfigSection() {
319319
<ClickhouseSettingForm
320320
settingKey="filterKeysFetchLimit"
321321
label="Filter Keys Fetch Limit"
322-
tooltip="The number of filter keys to fetch when clicking 'More filters' on the search page"
322+
tooltip="The number of filter keys to fetch per map column (e.g. LogAttributes, ResourceAttributes) on the search page"
323323
type="number"
324324
defaultValue={DEFAULT_FILTER_KEYS_FETCH_LIMIT}
325325
placeholder={`default = ${DEFAULT_FILTER_KEYS_FETCH_LIMIT}`}

‎packages/app/src/hooks/__tests__/useMetadata.test.tsx‎

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import {
88
Metadata,
99
MetadataCache,
1010
} from '@hyperdx/common-utils/dist/core/metadata';
11+
import { FilterState } from '@hyperdx/common-utils/dist/filters';
1112
import { BuilderChartConfigWithDateRange } from '@hyperdx/common-utils/dist/types';
1213
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
1314
import { renderHook, waitFor } from '@testing-library/react';
@@ -508,6 +509,64 @@ describe('useGetKeyValues', () => {
508509
},
509510
);
510511

512+
it('applies the filter key limit to each Map column separately', async () => {
513+
queryClient.setQueryData(['me'], { team: { filterKeysFetchLimit: 2 } });
514+
const getKeyValuesWithMVs = jest
515+
.spyOn(mockMetadata, 'getKeyValuesWithMVs')
516+
.mockResolvedValue([]);
517+
const conditionFor = (key: string): FilterState => ({
518+
[key]: { included: new Set(['v']), excluded: new Set() },
519+
});
520+
const allKeys = [
521+
"LogAttributes['a']",
522+
"LogAttributes['b']",
523+
"LogAttributes['c']",
524+
"`Resource-Attributes`['x']",
525+
'ServiceName',
526+
'SeverityText',
527+
'SpanName',
528+
];
529+
const keptKeys = [
530+
"LogAttributes['a']",
531+
"LogAttributes['b']",
532+
"`Resource-Attributes`['x']",
533+
'ServiceName',
534+
'SeverityText',
535+
];
536+
537+
const { result } = renderHook(
538+
() =>
539+
useGetKeyValues({
540+
chartConfig: createMockChartConfig(),
541+
keys: allKeys,
542+
keyConditions: allKeys.map(conditionFor),
543+
}),
544+
{ wrapper },
545+
);
546+
547+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
548+
expect(getKeyValuesWithMVs).toHaveBeenCalledWith(
549+
expect.objectContaining({
550+
keys: keptKeys,
551+
keyConditions: keptKeys.map(conditionFor),
552+
}),
553+
);
554+
});
555+
556+
it('passes no keyConditions when none are given', async () => {
557+
const getKeyValuesWithMVs = jest
558+
.spyOn(mockMetadata, 'getKeyValuesWithMVs')
559+
.mockResolvedValue([]);
560+
561+
const { result } = renderHook(
562+
() => useGetKeyValues({ chartConfig: createMockChartConfig(), keys }),
563+
{ wrapper },
564+
);
565+
566+
await waitFor(() => expect(result.current.isSuccess).toBe(true));
567+
expect(getKeyValuesWithMVs.mock.calls[0][0].keyConditions).toBeUndefined();
568+
});
569+
511570
it("retries a failed 'exact' mode lookup per the client's defaults", async () => {
512571
queryClient.setDefaultOptions({ queries: { retry: 1, retryDelay: 0 } });
513572
mockLookups.exact(new Error('transient'), [

‎packages/app/src/hooks/useMetadata.tsx‎

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import {
99
import {
1010
Field,
1111
MetricNames,
12+
parseKeyPath,
1213
TableConnection,
1314
TableMetadata,
1415
} from '@hyperdx/common-utils/dist/core/metadata';
@@ -521,6 +522,30 @@ export function useMultipleGetKeyValues(
521522
if (keys.length === 0) return;
522523
const usableMVsOverride =
523524
chartConfigsArr.length === 1 ? metadataMVsOverride : undefined;
525+
// The limit applies per Map column, so one wide Map (e.g. LogAttributes)
526+
// can't crowd out the others. Top-level columns share a single limit.
527+
const { limitedKeys, limitedKeyConditions } = keys.reduce<{
528+
countByColumn: Map<string, number>;
529+
limitedKeys: string[];
530+
limitedKeyConditions?: (FilterState | undefined)[];
531+
}>(
532+
(acc, key, i) => {
533+
const path = parseKeyPath(key);
534+
const column = path.length > 1 ? path[0] : '';
535+
const count = acc.countByColumn.get(column) ?? 0;
536+
acc.countByColumn.set(column, count + 1);
537+
if (count < maxKeys) {
538+
acc.limitedKeys.push(key);
539+
acc.limitedKeyConditions?.push(keyConditions?.[i]);
540+
}
541+
return acc;
542+
},
543+
{
544+
countByColumn: new Map(),
545+
limitedKeys: [],
546+
limitedKeyConditions: keyConditions ? [] : undefined,
547+
},
548+
);
524549

525550
const lookups = chartConfigsArr.map(chartConfig => {
526551
const source = chartConfig.source
@@ -539,8 +564,8 @@ export function useMultipleGetKeyValues(
539564
lookups.map(({ chartConfig, source }) =>
540565
metadata.getKeyValuesWithMVs({
541566
chartConfig,
542-
keys: keys.slice(0, maxKeys),
543-
keyConditions: keyConditions?.slice(0, maxKeys),
567+
keys: limitedKeys,
568+
keyConditions: limitedKeyConditions,
544569
limit,
545570
disableRowLimit,
546571
source,
@@ -559,7 +584,7 @@ export function useMultipleGetKeyValues(
559584
metadata.streamAllKeyValues({
560585
databaseName: chartConfig.from.databaseName,
561586
tableName: chartConfig.from.tableName,
562-
keyExpressions: keys.slice(0, maxKeys),
587+
keyExpressions: limitedKeys,
563588
maxValuesPerKey: limit,
564589
connectionId: chartConfig.connection,
565590
metadataMVs,

0 commit comments

Comments
 (0)