Field discovery and value autocomplete both truncate to a fixed number of results with no ORDER BY. On a high-cardinality source the survivors are an arbitrary subset, the UI gives no sign anything was dropped, and the one team setting that looks like it controls this doesn't reach either path.
We hit this on a source with ~6,150 distinct LogAttributes keys. Roughly 5,150 of them are invisible in the filter sidebar and there is no way to raise the ceiling.
Keys: capped at 1000, and Filter Keys Fetch Limit doesn't apply
getAllFields calls getMapKeys without maxKeys, so DEFAULT_MAX_KEYS = 1000 always wins:
The team setting exists (TeamQueryConfigSection.tsx:320, "Filter Keys Fetch Limit") but is only read in useMultipleGetKeyValues, where it slices the already-truncated key array: useMetadata.tsx:372-373, applied at useMetadata.tsx:411. Raising it above 1000 changes nothing; lowering it below 1000 only trims what discovery already returned. Confirmed on the wire — discovery queries carry LIMIT 1000 regardless of the setting.
Keys: the text-index path has no ORDER BY
getMapKeys returns from the first non-empty path of four. On ClickHouse 26.4 with a text index on mapKeys(LogAttributes), the text-index path wins and the KV rollup is never consulted:
Compare the rollup path, which does order by frequency: metadata.ts:846-853 — ORDER BY sum(count) DESC. Adding a text index therefore makes field discovery worse: you trade a frequency-ranked list for an arbitrary one.
Values: capped at a hardcoded 20, also unordered
The SQL is groupUniqArray(limit)(…) throughout, with no ordering: 2570-2571, 2605, 1428, 1257, 1334.
"Load More" raises one key to 10,000 (hooks.ts:36), but it's a manual per-key click. The initial 20 that decides whether the value you're looking for is on screen at all has no setting behind it.
This is already documented in the codebase
metadata.ts:2652-2669 explains why getMetricNames avoids getKeyValues:
groupUniqArray(limit)(MetricName) "keeps an arbitrary subset once a table has more than limit distinct names — the survivors follow hash order, not name order, and shift as the data and part layout change. On a high-cardinality source (a full Prometheus scrape) that silently hid metrics such as up, with no way to search for what had been dropped."
And useMetadata.tsx:526 tells callers to "Prefer this over useGetKeyValues({ keys: ['MetricName'] }), which samples an arbitrary subset via groupUniqArray".
The fix applied there is exactly what's missing everywhere else: a deterministic ORDER BY, LIMIT limit + 1, and a truncated flag so the caller knows the list was cut. A truncated field already exists in the shared type at metadata.ts:77.
What we'd like
A cap is reasonable. Being unable to raise it, and not being told it applied, is not.
- Pass
maxKeys from filterKeysFetchLimit through getAllFields into getMapKeys, so the existing setting actually controls key discovery.
- Add a team setting for max values per key, replacing the hardcoded
20 in useMetadata.tsx:412 and INITIAL_LOAD_LIMIT.
- Add
ORDER BY to the truncating queries — frequency for keys (as the rollup path already does), something deterministic for values — so the subset is at least stable and useful.
- Surface truncation in the UI, reusing the
limit + 1 / truncated pattern from getMetricNames.
Environment
- HyperDX 2.37.0, ClickHouse Cloud 26.4
otel_logs with text indexes on mapKeys(LogAttributes), mapKeys(ResourceAttributes), mapKeys(ScopeAttributes)
- ~6,150 distinct
LogAttributes keys per 15-minute window
Field discovery and value autocomplete both truncate to a fixed number of results with no
ORDER BY. On a high-cardinality source the survivors are an arbitrary subset, the UI gives no sign anything was dropped, and the one team setting that looks like it controls this doesn't reach either path.We hit this on a source with ~6,150 distinct
LogAttributeskeys. Roughly 5,150 of them are invisible in the filter sidebar and there is no way to raise the ceiling.Keys: capped at 1000, and
Filter Keys Fetch Limitdoesn't applygetAllFieldscallsgetMapKeyswithoutmaxKeys, soDEFAULT_MAX_KEYS = 1000always wins:metadata.ts:1536— the call, nomaxKeysargumentmetadata.ts:57—const DEFAULT_MAX_KEYS = 1000;metadata.ts:693—maxKeys = DEFAULT_MAX_KEYSThe team setting exists (
TeamQueryConfigSection.tsx:320, "Filter Keys Fetch Limit") but is only read inuseMultipleGetKeyValues, where it slices the already-truncated key array:useMetadata.tsx:372-373, applied atuseMetadata.tsx:411. Raising it above 1000 changes nothing; lowering it below 1000 only trims what discovery already returned. Confirmed on the wire — discovery queries carryLIMIT 1000regardless of the setting.Keys: the text-index path has no
ORDER BYgetMapKeysreturns from the first non-empty path of four. On ClickHouse 26.4 with atextindex onmapKeys(LogAttributes), the text-index path wins and the KV rollup is never consulted:metadata.ts:754-759—SELECT token AS key … GROUP BY key HAVING key != '' LIMIT maxKeys, noORDER BYmetadata.ts:788-793— same for the kv-token indexCompare the rollup path, which does order by frequency:
metadata.ts:846-853—ORDER BY sum(count) DESC. Adding a text index therefore makes field discovery worse: you trade a frequency-ranked list for an arbitrary one.Values: capped at a hardcoded 20, also unordered
metadata.ts:2267—getAllKeyValues({ maxValuesPerKey = 20 })metadata.ts:2494—getKeyValues({ limit = 20 })metadata.ts:2779—getKeyValuesWithMVs({ limit = 20 })useMetadata.tsx:412—maxValuesPerKey: 20, hardcodedDBSearchPageFilters/hooks.ts:33—INITIAL_LOAD_LIMIT = 20, passed at line 197The SQL is
groupUniqArray(limit)(…)throughout, with no ordering: 2570-2571, 2605, 1428, 1257, 1334."Load More" raises one key to 10,000 (hooks.ts:36), but it's a manual per-key click. The initial 20 that decides whether the value you're looking for is on screen at all has no setting behind it.
This is already documented in the codebase
metadata.ts:2652-2669explains whygetMetricNamesavoidsgetKeyValues:And
useMetadata.tsx:526tells callers to "Prefer this overuseGetKeyValues({ keys: ['MetricName'] }), which samples an arbitrary subset viagroupUniqArray".The fix applied there is exactly what's missing everywhere else: a deterministic
ORDER BY,LIMIT limit + 1, and atruncatedflag so the caller knows the list was cut. Atruncatedfield already exists in the shared type atmetadata.ts:77.What we'd like
A cap is reasonable. Being unable to raise it, and not being told it applied, is not.
maxKeysfromfilterKeysFetchLimitthroughgetAllFieldsintogetMapKeys, so the existing setting actually controls key discovery.20inuseMetadata.tsx:412andINITIAL_LOAD_LIMIT.ORDER BYto the truncating queries — frequency for keys (as the rollup path already does), something deterministic for values — so the subset is at least stable and useful.limit + 1/truncatedpattern fromgetMetricNames.Environment
otel_logswithtextindexes onmapKeys(LogAttributes),mapKeys(ResourceAttributes),mapKeys(ScopeAttributes)LogAttributeskeys per 15-minute window