mirror of
https://github.com/prometheus/prometheus.git
synced 2024-11-09 23:24:05 -08:00
Merge pull request #14913 from prometheus/explain-view-set-ops
Some checks are pending
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Build Prometheus for common architectures (0) (push) Waiting to run
CI / Build Prometheus for common architectures (1) (push) Waiting to run
CI / Build Prometheus for common architectures (2) (push) Waiting to run
CI / Build Prometheus for all architectures (0) (push) Waiting to run
CI / Build Prometheus for all architectures (1) (push) Waiting to run
CI / Build Prometheus for all architectures (10) (push) Waiting to run
CI / Build Prometheus for all architectures (11) (push) Waiting to run
CI / Build Prometheus for all architectures (2) (push) Waiting to run
CI / Build Prometheus for all architectures (3) (push) Waiting to run
CI / Build Prometheus for all architectures (4) (push) Waiting to run
CI / Build Prometheus for all architectures (5) (push) Waiting to run
CI / Build Prometheus for all architectures (6) (push) Waiting to run
CI / Build Prometheus for all architectures (7) (push) Waiting to run
CI / Build Prometheus for all architectures (8) (push) Waiting to run
CI / Build Prometheus for all architectures (9) (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
Some checks are pending
buf.build / lint and publish (push) Waiting to run
CI / Go tests (push) Waiting to run
CI / More Go tests (push) Waiting to run
CI / Go tests with previous Go version (push) Waiting to run
CI / UI tests (push) Waiting to run
CI / Go tests on Windows (push) Waiting to run
CI / Mixins tests (push) Waiting to run
CI / Build Prometheus for common architectures (0) (push) Waiting to run
CI / Build Prometheus for common architectures (1) (push) Waiting to run
CI / Build Prometheus for common architectures (2) (push) Waiting to run
CI / Build Prometheus for all architectures (0) (push) Waiting to run
CI / Build Prometheus for all architectures (1) (push) Waiting to run
CI / Build Prometheus for all architectures (10) (push) Waiting to run
CI / Build Prometheus for all architectures (11) (push) Waiting to run
CI / Build Prometheus for all architectures (2) (push) Waiting to run
CI / Build Prometheus for all architectures (3) (push) Waiting to run
CI / Build Prometheus for all architectures (4) (push) Waiting to run
CI / Build Prometheus for all architectures (5) (push) Waiting to run
CI / Build Prometheus for all architectures (6) (push) Waiting to run
CI / Build Prometheus for all architectures (7) (push) Waiting to run
CI / Build Prometheus for all architectures (8) (push) Waiting to run
CI / Build Prometheus for all architectures (9) (push) Waiting to run
CI / Report status of build Prometheus for all architectures (push) Blocked by required conditions
CI / Check generated parser (push) Waiting to run
CI / golangci-lint (push) Waiting to run
CI / fuzzing (push) Waiting to run
CI / codeql (push) Waiting to run
CI / Publish main branch artifacts (push) Blocked by required conditions
CI / Publish release artefacts (push) Blocked by required conditions
CI / Publish UI on npm Registry (push) Blocked by required conditions
Scorecards supply-chain security / Scorecards analysis (push) Waiting to run
PromQL explain view: Support set operators
This commit is contained in:
commit
6acd3dee53
|
@ -361,309 +361,296 @@ const VectorVectorBinaryExprExplainView: FC<
|
|||
<>
|
||||
<Text size="sm">{explanationText(node)}</Text>
|
||||
|
||||
{!isSetOperator(node.op) && (
|
||||
<>
|
||||
<Group my="lg" justify="flex-end" gap="xl">
|
||||
{/* <Switch
|
||||
label="Break long lines"
|
||||
checked={allowLineBreaks}
|
||||
onChange={(event) =>
|
||||
setAllowLineBreaks(event.currentTarget.checked)
|
||||
}
|
||||
/> */}
|
||||
<Switch
|
||||
label="Show sample values"
|
||||
checked={showSampleValues}
|
||||
onChange={(event) =>
|
||||
setShowSampleValues(event.currentTarget.checked)
|
||||
}
|
||||
/>
|
||||
</Group>
|
||||
<Group my="lg" justify="flex-end" gap="xl">
|
||||
<Switch
|
||||
label="Show sample values"
|
||||
checked={showSampleValues}
|
||||
onChange={(event) => setShowSampleValues(event.currentTarget.checked)}
|
||||
/>
|
||||
</Group>
|
||||
|
||||
{numGroups > Object.keys(matchGroups).length && (
|
||||
<Alert color="yellow" mb="md" icon={<IconAlertTriangle />}>
|
||||
Too many match groups to display, only showing{" "}
|
||||
{Object.keys(matchGroups).length} out of {numGroups} groups.
|
||||
<br />
|
||||
<br />
|
||||
<Anchor fz="sm" onClick={() => setMaxGroups(undefined)}>
|
||||
Show all groups
|
||||
</Anchor>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{errCount > 0 && (
|
||||
<Alert color="yellow" mb="md" icon={<IconAlertTriangle />}>
|
||||
Found matching issues in {errCount} match group
|
||||
{errCount > 1 ? "s" : ""}. See below for per-group error details.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Table fz="xs" withRowBorders={false}>
|
||||
<Table.Tbody>
|
||||
{Object.values(matchGroups).map((mg, mgIdx) => {
|
||||
const {
|
||||
groupLabels,
|
||||
lhs,
|
||||
lhsCount,
|
||||
rhs,
|
||||
rhsCount,
|
||||
result,
|
||||
error,
|
||||
} = mg;
|
||||
|
||||
const matchGroupTitleRow = (color: string) => (
|
||||
<Table.Tr ta="center">
|
||||
<Table.Td
|
||||
colSpan={2}
|
||||
style={{ backgroundColor: `${color}25` }}
|
||||
>
|
||||
<SeriesName labels={groupLabels} format={true} />
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
);
|
||||
|
||||
const matchGroupTable = (
|
||||
series: InstantSample[],
|
||||
seriesCount: number,
|
||||
color: string,
|
||||
colorOffset?: number
|
||||
) => (
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 3,
|
||||
border: "2px solid",
|
||||
borderColor:
|
||||
series.length === 0
|
||||
? "light-dark(var(--mantine-color-gray-4), var(--mantine-color-gray-7))"
|
||||
: color,
|
||||
}}
|
||||
>
|
||||
<Table fz="xs" withRowBorders={false} verticalSpacing={5}>
|
||||
<Table.Tbody>
|
||||
{series.length === 0 ? (
|
||||
<Table.Tr>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-5))"
|
||||
py="md"
|
||||
fw="bold"
|
||||
>
|
||||
no matching series
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
) : (
|
||||
<>
|
||||
{matchGroupTitleRow(color)}
|
||||
{series.map((s, sIdx) => {
|
||||
if (s.value === undefined) {
|
||||
// TODO: Figure out how to handle native histograms.
|
||||
throw new Error(
|
||||
"Native histograms are not supported yet"
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Table.Tr key={sIdx}>
|
||||
<Table.Td>
|
||||
<Group wrap="nowrap" gap={7} align="center">
|
||||
{seriesSwatch(
|
||||
colorForIndex(sIdx, colorOffset)
|
||||
)}
|
||||
|
||||
<SeriesName
|
||||
labels={noMatchLabels(
|
||||
s.metric,
|
||||
matching.on,
|
||||
matching.labels
|
||||
)}
|
||||
format={true}
|
||||
/>
|
||||
</Group>
|
||||
</Table.Td>
|
||||
{showSampleValues && (
|
||||
<Table.Td ta="right">{s.value[1]}</Table.Td>
|
||||
)}
|
||||
</Table.Tr>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
{seriesCount > series.length && (
|
||||
<Table.Tr>
|
||||
<Table.Td ta="center" py="md" fw="bold" c="gray.6">
|
||||
{seriesCount - series.length} more series omitted
|
||||
–
|
||||
<Anchor
|
||||
size="xs"
|
||||
onClick={() => setMaxSeriesPerGroup(undefined)}
|
||||
>
|
||||
Show all series
|
||||
</Anchor>
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
)}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const noLHSMatches = lhs.length === 0;
|
||||
const noRHSMatches = rhs.length === 0;
|
||||
|
||||
const groupColor = colorPool[mgIdx % colorPool.length];
|
||||
|
||||
const lhsTable = matchGroupTable(lhs, lhsCount, groupColor);
|
||||
const rhsTable = matchGroupTable(
|
||||
rhs,
|
||||
rhsCount,
|
||||
groupColor,
|
||||
rhsColorOffset
|
||||
);
|
||||
|
||||
const resultTable = (
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 3,
|
||||
border: `2px solid`,
|
||||
borderColor:
|
||||
noLHSMatches || noRHSMatches || error !== null
|
||||
? "light-dark(var(--mantine-color-gray-4), var(--mantine-color-gray-7))"
|
||||
: groupColor,
|
||||
}}
|
||||
>
|
||||
<Table fz="xs" withRowBorders={false} verticalSpacing={5}>
|
||||
<Table.Tbody>
|
||||
{noLHSMatches || noRHSMatches ? (
|
||||
<Table.Tr>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-5))"
|
||||
py="md"
|
||||
fw="bold"
|
||||
>
|
||||
dropped
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
) : error !== null ? (
|
||||
<Table.Tr>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-5))"
|
||||
py="md"
|
||||
fw="bold"
|
||||
>
|
||||
error, result omitted
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
) : (
|
||||
<>
|
||||
{result.map(({ sample, manySideIdx }, resIdx) => {
|
||||
if (sample.value === undefined) {
|
||||
// TODO: Figure out how to handle native histograms.
|
||||
throw new Error(
|
||||
"Native histograms are not supported yet"
|
||||
);
|
||||
}
|
||||
|
||||
const filtered =
|
||||
sample.value[1] === filteredSampleValue;
|
||||
const [lIdx, rIdx] =
|
||||
matching.card ===
|
||||
vectorMatchCardinality.oneToMany
|
||||
? [0, manySideIdx]
|
||||
: [manySideIdx, 0];
|
||||
|
||||
return (
|
||||
<Table.Tr key={resIdx}>
|
||||
<Table.Td
|
||||
style={{ opacity: filtered ? 0.5 : 1 }}
|
||||
title={
|
||||
filtered
|
||||
? "Series has been filtered by comparison operator"
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Group
|
||||
wrap="nowrap"
|
||||
gap="xs"
|
||||
align="flex-start"
|
||||
>
|
||||
<Group wrap="nowrap" gap={0}>
|
||||
{seriesSwatch(colorForIndex(lIdx))}
|
||||
<span style={{ color: "#aaa" }}>–</span>
|
||||
{seriesSwatch(
|
||||
colorForIndex(rIdx, rhsColorOffset)
|
||||
)}
|
||||
</Group>
|
||||
|
||||
<SeriesName
|
||||
labels={sample.metric}
|
||||
format={true}
|
||||
/>
|
||||
</Group>
|
||||
</Table.Td>
|
||||
{showSampleValues && (
|
||||
<Table.Td ta="right">
|
||||
{filtered ? (
|
||||
<span style={{ color: "grey" }}>
|
||||
filtered
|
||||
</span>
|
||||
) : (
|
||||
<span>{sample.value[1]}</span>
|
||||
)}
|
||||
</Table.Td>
|
||||
)}
|
||||
</Table.Tr>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment key={mgIdx}>
|
||||
{mgIdx !== 0 && <tr style={{ height: 30 }}></tr>}
|
||||
<Table.Tr>
|
||||
<Table.Td colSpan={5}>
|
||||
{error && (
|
||||
<Alert
|
||||
color="red"
|
||||
mb="md"
|
||||
title="Error in match group below"
|
||||
icon={<IconAlertTriangle />}
|
||||
>
|
||||
{explainError(node, mg, error)}
|
||||
</Alert>
|
||||
)}
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
<Table.Tr>
|
||||
<Table.Td valign="middle" p={0}>
|
||||
{lhsTable}
|
||||
</Table.Td>
|
||||
<Table.Td ta="center">
|
||||
{node.op}
|
||||
{node.bool && " bool"}
|
||||
</Table.Td>
|
||||
<Table.Td valign="middle" p={0}>
|
||||
{rhsTable}
|
||||
</Table.Td>
|
||||
<Table.Td ta="center">=</Table.Td>
|
||||
<Table.Td valign="middle" p={0}>
|
||||
{resultTable}
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</>
|
||||
{numGroups > Object.keys(matchGroups).length && (
|
||||
<Alert color="yellow" mb="md" icon={<IconAlertTriangle />}>
|
||||
Too many match groups to display, only showing{" "}
|
||||
{Object.keys(matchGroups).length} out of {numGroups} groups.
|
||||
<br />
|
||||
<br />
|
||||
<Anchor fz="sm" onClick={() => setMaxGroups(undefined)}>
|
||||
Show all groups
|
||||
</Anchor>
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
{errCount > 0 && (
|
||||
<Alert color="yellow" mb="md" icon={<IconAlertTriangle />}>
|
||||
Found matching issues in {errCount} match group
|
||||
{errCount > 1 ? "s" : ""}. See below for per-group error details.
|
||||
</Alert>
|
||||
)}
|
||||
|
||||
<Table fz="xs" withRowBorders={false}>
|
||||
<Table.Tbody>
|
||||
{Object.values(matchGroups).map((mg, mgIdx) => {
|
||||
const { groupLabels, lhs, lhsCount, rhs, rhsCount, result, error } =
|
||||
mg;
|
||||
|
||||
const matchGroupTitleRow = (color: string) => (
|
||||
<Table.Tr ta="center">
|
||||
<Table.Td colSpan={2} style={{ backgroundColor: `${color}25` }}>
|
||||
<SeriesName labels={groupLabels} format={true} />
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
);
|
||||
|
||||
const matchGroupTable = (
|
||||
series: InstantSample[],
|
||||
seriesCount: number,
|
||||
color: string,
|
||||
colorOffset?: number
|
||||
) => (
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 3,
|
||||
border: "2px solid",
|
||||
borderColor:
|
||||
seriesCount === 0
|
||||
? "light-dark(var(--mantine-color-gray-4), var(--mantine-color-gray-7))"
|
||||
: color,
|
||||
}}
|
||||
>
|
||||
<Table fz="xs" withRowBorders={false} verticalSpacing={5}>
|
||||
<Table.Tbody>
|
||||
{seriesCount === 0 ? (
|
||||
<Table.Tr>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-5))"
|
||||
py="md"
|
||||
fw="bold"
|
||||
>
|
||||
no matching series
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
) : (
|
||||
<>
|
||||
{matchGroupTitleRow(color)}
|
||||
{series.map((s, sIdx) => {
|
||||
if (s.value === undefined) {
|
||||
// TODO: Figure out how to handle native histograms.
|
||||
throw new Error(
|
||||
"Native histograms are not supported yet"
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<Table.Tr key={sIdx}>
|
||||
<Table.Td>
|
||||
<Group wrap="nowrap" gap={7} align="center">
|
||||
{seriesSwatch(
|
||||
colorForIndex(sIdx, colorOffset)
|
||||
)}
|
||||
|
||||
<SeriesName
|
||||
labels={noMatchLabels(
|
||||
s.metric,
|
||||
matching.on,
|
||||
matching.labels
|
||||
)}
|
||||
format={true}
|
||||
/>
|
||||
</Group>
|
||||
</Table.Td>
|
||||
{showSampleValues && (
|
||||
<Table.Td ta="right">{s.value[1]}</Table.Td>
|
||||
)}
|
||||
</Table.Tr>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
{seriesCount > series.length && (
|
||||
<Table.Tr>
|
||||
<Table.Td ta="center" py="md" fw="bold" c="gray.6">
|
||||
{seriesCount - series.length} more series omitted
|
||||
–
|
||||
<Anchor
|
||||
size="xs"
|
||||
onClick={() => setMaxSeriesPerGroup(undefined)}
|
||||
>
|
||||
Show all series
|
||||
</Anchor>
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
)}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</Box>
|
||||
);
|
||||
|
||||
const groupColor = colorPool[mgIdx % colorPool.length];
|
||||
|
||||
const lhsTable = matchGroupTable(lhs, lhsCount, groupColor);
|
||||
const rhsTable = matchGroupTable(
|
||||
rhs,
|
||||
rhsCount,
|
||||
groupColor,
|
||||
rhsColorOffset
|
||||
);
|
||||
|
||||
const resultTable = (
|
||||
<Box
|
||||
style={{
|
||||
borderRadius: 3,
|
||||
border: `2px solid`,
|
||||
borderColor:
|
||||
result.length === 0 || error !== null
|
||||
? "light-dark(var(--mantine-color-gray-4), var(--mantine-color-gray-7))"
|
||||
: groupColor,
|
||||
}}
|
||||
>
|
||||
<Table fz="xs" withRowBorders={false} verticalSpacing={5}>
|
||||
<Table.Tbody>
|
||||
{error !== null ? (
|
||||
<Table.Tr>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-5))"
|
||||
py="md"
|
||||
fw="bold"
|
||||
>
|
||||
error, result omitted
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
) : result.length === 0 ? (
|
||||
<Table.Tr>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-5))"
|
||||
py="md"
|
||||
fw="bold"
|
||||
>
|
||||
dropped
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
) : error !== null ? (
|
||||
<Table.Tr>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
c="light-dark(var(--mantine-color-gray-7), var(--mantine-color-gray-5))"
|
||||
py="md"
|
||||
fw="bold"
|
||||
>
|
||||
error, result omitted
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
) : (
|
||||
<>
|
||||
{result.map(({ sample, manySideIdx }, resIdx) => {
|
||||
if (sample.value === undefined) {
|
||||
// TODO: Figure out how to handle native histograms.
|
||||
throw new Error(
|
||||
"Native histograms are not supported yet"
|
||||
);
|
||||
}
|
||||
|
||||
const filtered =
|
||||
sample.value[1] === filteredSampleValue;
|
||||
const [lIdx, rIdx] =
|
||||
matching.card === vectorMatchCardinality.oneToMany
|
||||
? [0, manySideIdx]
|
||||
: [manySideIdx, 0];
|
||||
|
||||
return (
|
||||
<Table.Tr key={resIdx}>
|
||||
<Table.Td
|
||||
style={{ opacity: filtered ? 0.5 : 1 }}
|
||||
title={
|
||||
filtered
|
||||
? "Series has been filtered by comparison operator"
|
||||
: undefined
|
||||
}
|
||||
>
|
||||
<Group
|
||||
wrap="nowrap"
|
||||
gap="xs"
|
||||
align="flex-start"
|
||||
>
|
||||
<Group wrap="nowrap" gap={0}>
|
||||
{seriesSwatch(colorForIndex(lIdx))}
|
||||
<span style={{ color: "#aaa" }}>–</span>
|
||||
{seriesSwatch(
|
||||
colorForIndex(rIdx, rhsColorOffset)
|
||||
)}
|
||||
</Group>
|
||||
|
||||
<SeriesName
|
||||
labels={sample.metric}
|
||||
format={true}
|
||||
/>
|
||||
</Group>
|
||||
</Table.Td>
|
||||
{showSampleValues && (
|
||||
<Table.Td ta="right">
|
||||
{filtered ? (
|
||||
<span style={{ color: "grey" }}>
|
||||
filtered
|
||||
</span>
|
||||
) : (
|
||||
<span>{sample.value[1]}</span>
|
||||
)}
|
||||
</Table.Td>
|
||||
)}
|
||||
</Table.Tr>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
)}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</Box>
|
||||
);
|
||||
|
||||
return (
|
||||
<React.Fragment key={mgIdx}>
|
||||
{mgIdx !== 0 && <tr style={{ height: 30 }}></tr>}
|
||||
<Table.Tr>
|
||||
<Table.Td colSpan={5}>
|
||||
{error && (
|
||||
<Alert
|
||||
color="red"
|
||||
mb="md"
|
||||
title="Error in match group below"
|
||||
icon={<IconAlertTriangle />}
|
||||
>
|
||||
{explainError(node, mg, error)}
|
||||
</Alert>
|
||||
)}
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
<Table.Tr>
|
||||
<Table.Td valign="middle" p={0}>
|
||||
{lhsTable}
|
||||
</Table.Td>
|
||||
<Table.Td
|
||||
ta="center"
|
||||
fw={isSetOperator(node.op) ? "bold" : undefined}
|
||||
>
|
||||
{node.op}
|
||||
{node.bool && " bool"}
|
||||
</Table.Td>
|
||||
<Table.Td valign="middle" p={0}>
|
||||
{rhsTable}
|
||||
</Table.Td>
|
||||
<Table.Td ta="center">=</Table.Td>
|
||||
<Table.Td valign="middle" p={0}>
|
||||
{resultTable}
|
||||
</Table.Td>
|
||||
</Table.Tr>
|
||||
</React.Fragment>
|
||||
);
|
||||
})}
|
||||
</Table.Tbody>
|
||||
</Table>
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -73,6 +73,7 @@ const testMetricC: InstantSample[] = [
|
|||
|
||||
const testCases: TestCase[] = [
|
||||
{
|
||||
// metric_a - metric_b
|
||||
desc: "one-to-one matching on all labels",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -238,6 +239,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a - on(label1, label2) metric_b
|
||||
desc: "one-to-one matching on explicit labels",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -403,6 +405,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a - ignoring(same) metric_b
|
||||
desc: "one-to-one matching ignoring explicit labels",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -568,6 +571,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_b - metric_c
|
||||
desc: "many-to-one matching with no matching labels specified (empty output)",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -689,6 +693,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_b - on(label1) metric_c
|
||||
desc: "many-to-one matching with matching labels specified, but no group_left (error)",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -778,6 +783,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_b - on(label1) group_left metric_c
|
||||
desc: "many-to-one matching with matching labels specified and group_left",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -891,6 +897,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_c - on(label1) group_right metric_b
|
||||
desc: "one-to-many matching with matching labels specified and group_right",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -1004,6 +1011,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_c - on(label1) group_left metric_b
|
||||
desc: "one-to-many matching with matching labels specified but incorrect group_left (error)",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -1091,6 +1099,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a - on(label1) metric_b
|
||||
desc: "insufficient matching labels leading to many-to-many matching for intended one-to-one match (error)",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -1206,6 +1215,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a < metric_b
|
||||
desc: "filter op keeping all series",
|
||||
op: binaryOperatorType.lss,
|
||||
matching: {
|
||||
|
@ -1391,6 +1401,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a >= metric_b
|
||||
desc: "filter op dropping all series",
|
||||
op: binaryOperatorType.gte,
|
||||
matching: {
|
||||
|
@ -1576,6 +1587,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a >= bool metric_b
|
||||
desc: "filter op dropping all series, but with bool",
|
||||
op: binaryOperatorType.gte,
|
||||
bool: true,
|
||||
|
@ -1742,6 +1754,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a < bool metric_b
|
||||
desc: "filter op keeping all series, but with bool",
|
||||
op: binaryOperatorType.lss,
|
||||
bool: true,
|
||||
|
@ -1908,6 +1921,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_a - metric_b
|
||||
desc: "exceeding the match group limit",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -2000,6 +2014,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_c - on(label1) group_left metric_b
|
||||
desc: "exceeding the per-group series limit",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -2082,6 +2097,7 @@ const testCases: TestCase[] = [
|
|||
},
|
||||
},
|
||||
{
|
||||
// metric_c - on(label1) group_left metric_b
|
||||
desc: "exceeding both group limit and per-group series limit",
|
||||
op: binaryOperatorType.sub,
|
||||
matching: {
|
||||
|
@ -2131,6 +2147,732 @@ const testCases: TestCase[] = [
|
|||
numGroups: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
// metric_a and metric b
|
||||
desc: "and operator with no matching labels and matching groups",
|
||||
op: binaryOperatorType.and,
|
||||
matching: {
|
||||
card: vectorMatchCardinality.manyToMany,
|
||||
on: false,
|
||||
include: [],
|
||||
labels: [],
|
||||
},
|
||||
lhs: testMetricA,
|
||||
rhs: testMetricB,
|
||||
result: {
|
||||
groups: {
|
||||
[fnv1a(["a", "x", "same"])]: {
|
||||
groupLabels: { label1: "a", label2: "x", same: "same" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "10"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["a", "y", "same"])]: {
|
||||
groupLabels: { label1: "a", label2: "y", same: "same" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "20"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["b", "x", "same"])]: {
|
||||
groupLabels: { label1: "b", label2: "x", same: "same" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "30"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["b", "y", "same"])]: {
|
||||
groupLabels: { label1: "b", label2: "y", same: "same" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "4"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "40"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "4"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
},
|
||||
numGroups: 4,
|
||||
},
|
||||
},
|
||||
{
|
||||
// metric_a[0...2] and on(label1) metric_b[1...3]
|
||||
desc: "and operator with matching label and series on each side",
|
||||
op: binaryOperatorType.and,
|
||||
matching: {
|
||||
card: vectorMatchCardinality.manyToMany,
|
||||
on: true,
|
||||
include: [],
|
||||
labels: ["label1"],
|
||||
},
|
||||
lhs: testMetricA.slice(0, 3),
|
||||
rhs: testMetricB.slice(1, 4),
|
||||
result: {
|
||||
groups: {
|
||||
[fnv1a(["a"])]: {
|
||||
groupLabels: { label1: "a" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
],
|
||||
lhsCount: 2,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "20"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
manySideIdx: 1,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["b"])]: {
|
||||
groupLabels: { label1: "b" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "30"],
|
||||
},
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "40"],
|
||||
},
|
||||
],
|
||||
rhsCount: 2,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
},
|
||||
numGroups: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
// metric_a[0...2] unless on(label1) metric_b[1...3]
|
||||
desc: "unless operator with matching label and series on each side",
|
||||
op: binaryOperatorType.unless,
|
||||
matching: {
|
||||
card: vectorMatchCardinality.manyToMany,
|
||||
on: true,
|
||||
include: [],
|
||||
labels: ["label1"],
|
||||
},
|
||||
lhs: testMetricA.slice(0, 3),
|
||||
rhs: testMetricB.slice(1, 4),
|
||||
result: {
|
||||
groups: {
|
||||
[fnv1a(["a"])]: {
|
||||
groupLabels: { label1: "a" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
],
|
||||
lhsCount: 2,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "20"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["b"])]: {
|
||||
groupLabels: { label1: "b" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "30"],
|
||||
},
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "40"],
|
||||
},
|
||||
],
|
||||
rhsCount: 2,
|
||||
result: [],
|
||||
error: null,
|
||||
},
|
||||
},
|
||||
numGroups: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
// metric_a[0...2] or on(label1) metric_b[1...3]
|
||||
desc: "or operator with matching label and series on each side",
|
||||
op: binaryOperatorType.or,
|
||||
matching: {
|
||||
card: vectorMatchCardinality.manyToMany,
|
||||
on: true,
|
||||
include: [],
|
||||
labels: ["label1"],
|
||||
},
|
||||
lhs: testMetricA.slice(0, 3),
|
||||
rhs: testMetricB.slice(1, 4),
|
||||
result: {
|
||||
groups: {
|
||||
[fnv1a(["a"])]: {
|
||||
groupLabels: { label1: "a" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
],
|
||||
lhsCount: 2,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "20"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
manySideIdx: 1,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["b"])]: {
|
||||
groupLabels: { label1: "b" },
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "30"],
|
||||
},
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "40"],
|
||||
},
|
||||
],
|
||||
rhsCount: 2,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
},
|
||||
numGroups: 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
// metric_a[0...2] or metric_b[1...3]
|
||||
desc: "or operator with only partial overlap",
|
||||
op: binaryOperatorType.or,
|
||||
matching: {
|
||||
card: vectorMatchCardinality.manyToMany,
|
||||
on: false,
|
||||
include: [],
|
||||
labels: [],
|
||||
},
|
||||
lhs: testMetricA.slice(0, 3),
|
||||
rhs: testMetricB.slice(1, 4),
|
||||
result: {
|
||||
groups: {
|
||||
[fnv1a(["a", "x", "same"])]: {
|
||||
groupLabels: {
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [],
|
||||
rhsCount: 0,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "1"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["a", "y", "same"])]: {
|
||||
groupLabels: {
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "20"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "a",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "2"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["b", "x", "same"])]: {
|
||||
groupLabels: {
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
lhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
],
|
||||
lhsCount: 1,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "30"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_a",
|
||||
label1: "b",
|
||||
label2: "x",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "3"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
[fnv1a(["b", "y", "same"])]: {
|
||||
groupLabels: {
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
lhs: [],
|
||||
lhsCount: 0,
|
||||
rhs: [
|
||||
{
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "40"],
|
||||
},
|
||||
],
|
||||
rhsCount: 1,
|
||||
result: [
|
||||
{
|
||||
sample: {
|
||||
metric: {
|
||||
__name__: "metric_b",
|
||||
label1: "b",
|
||||
label2: "y",
|
||||
same: "same",
|
||||
},
|
||||
value: [0, "40"],
|
||||
},
|
||||
manySideIdx: 0,
|
||||
},
|
||||
],
|
||||
error: null,
|
||||
},
|
||||
},
|
||||
numGroups: 4,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
describe("binOp", () => {
|
||||
|
|
|
@ -340,25 +340,35 @@ export const computeVectorVectorBinOp = (
|
|||
|
||||
// Annotate the match groups with errors (if any) and populate the results.
|
||||
Object.values(groups).forEach((mg) => {
|
||||
// Do not populate results for set operators.
|
||||
if (isSetOperator(op)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (matching.card === vectorMatchCardinality.oneToOne) {
|
||||
if (mg.lhs.length > 1 && mg.rhs.length > 1) {
|
||||
mg.error = { type: MatchErrorType.multipleMatchesOnBothSides };
|
||||
} else if (mg.lhs.length > 1 || mg.rhs.length > 1) {
|
||||
mg.error = {
|
||||
type: MatchErrorType.multipleMatchesForOneToOneMatching,
|
||||
dupeSide: mg.lhs.length > 1 ? "left" : "right",
|
||||
};
|
||||
}
|
||||
} else if (mg.rhs.length > 1) {
|
||||
// Check for dupes on the "one" side in one-to-many or many-to-one matching.
|
||||
mg.error = {
|
||||
type: MatchErrorType.multipleMatchesOnOneSide,
|
||||
};
|
||||
switch (matching.card) {
|
||||
case vectorMatchCardinality.oneToOne:
|
||||
if (mg.lhs.length > 1 && mg.rhs.length > 1) {
|
||||
mg.error = { type: MatchErrorType.multipleMatchesOnBothSides };
|
||||
} else if (mg.lhs.length > 1 || mg.rhs.length > 1) {
|
||||
mg.error = {
|
||||
type: MatchErrorType.multipleMatchesForOneToOneMatching,
|
||||
dupeSide: mg.lhs.length > 1 ? "left" : "right",
|
||||
};
|
||||
}
|
||||
break;
|
||||
case vectorMatchCardinality.oneToMany:
|
||||
case vectorMatchCardinality.manyToOne:
|
||||
if (mg.rhs.length > 1) {
|
||||
mg.error = {
|
||||
type: MatchErrorType.multipleMatchesOnOneSide,
|
||||
};
|
||||
}
|
||||
break;
|
||||
case vectorMatchCardinality.manyToMany:
|
||||
// Should be a set operator - these don't have errors that aren't caught during parsing.
|
||||
if (!isSetOperator(op)) {
|
||||
throw new Error(
|
||||
"unexpected many-to-many matching for non-set operator"
|
||||
);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new Error("unknown vector matching cardinality");
|
||||
}
|
||||
|
||||
if (mg.error) {
|
||||
|
@ -368,42 +378,79 @@ export const computeVectorVectorBinOp = (
|
|||
return;
|
||||
}
|
||||
|
||||
// Calculate the results for this match group.
|
||||
mg.rhs.forEach((rs) => {
|
||||
if (isSetOperator(op)) {
|
||||
// Add LHS samples to the result, depending on specific operator condition and RHS length.
|
||||
mg.lhs.forEach((ls, lIdx) => {
|
||||
if (!ls.value || !rs.value) {
|
||||
// TODO: Implement native histogram support.
|
||||
throw new Error("native histogram support not implemented yet");
|
||||
if (
|
||||
(op === binaryOperatorType.and && mg.rhs.length > 0) ||
|
||||
(op === binaryOperatorType.unless && mg.rhs.length === 0) ||
|
||||
op === binaryOperatorType.or
|
||||
) {
|
||||
mg.result.push({
|
||||
sample: {
|
||||
metric: ls.metric,
|
||||
value: ls.value,
|
||||
},
|
||||
manySideIdx: lIdx,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
const [vl, vr] =
|
||||
matching.card !== vectorMatchCardinality.oneToMany
|
||||
? [ls.value[1], rs.value[1]]
|
||||
: [rs.value[1], ls.value[1]];
|
||||
let { value, keep } = vectorElemBinop(
|
||||
op,
|
||||
parsePrometheusFloat(vl),
|
||||
parsePrometheusFloat(vr)
|
||||
);
|
||||
// For OR, also add all RHS samples to the result if the LHS for the group is empty.
|
||||
if (op === binaryOperatorType.or) {
|
||||
mg.rhs.forEach((rs, rIdx) => {
|
||||
if (mg.lhs.length === 0) {
|
||||
mg.result.push({
|
||||
sample: {
|
||||
metric: rs.metric,
|
||||
value: rs.value,
|
||||
},
|
||||
manySideIdx: rIdx,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Calculate the results for this match group.
|
||||
mg.rhs.forEach((rs) => {
|
||||
mg.lhs.forEach((ls, lIdx) => {
|
||||
if (!ls.value || !rs.value) {
|
||||
// TODO: Implement native histogram support.
|
||||
throw new Error("native histogram support not implemented yet");
|
||||
}
|
||||
|
||||
const metric = resultMetric(ls.metric, rs.metric, op, matching);
|
||||
if (bool) {
|
||||
value = keep ? 1.0 : 0.0;
|
||||
delete metric.__name__;
|
||||
}
|
||||
const [vl, vr] =
|
||||
matching.card !== vectorMatchCardinality.oneToMany
|
||||
? [ls.value[1], rs.value[1]]
|
||||
: [rs.value[1], ls.value[1]];
|
||||
|
||||
mg.result.push({
|
||||
sample: {
|
||||
metric: metric,
|
||||
value: [
|
||||
ls.value[0],
|
||||
keep || bool ? formatPrometheusFloat(value) : filteredSampleValue,
|
||||
],
|
||||
},
|
||||
manySideIdx: lIdx,
|
||||
let { value, keep } = vectorElemBinop(
|
||||
op,
|
||||
parsePrometheusFloat(vl),
|
||||
parsePrometheusFloat(vr)
|
||||
);
|
||||
|
||||
const metric = resultMetric(ls.metric, rs.metric, op, matching);
|
||||
if (bool) {
|
||||
value = keep ? 1.0 : 0.0;
|
||||
delete metric.__name__;
|
||||
}
|
||||
|
||||
mg.result.push({
|
||||
sample: {
|
||||
metric: metric,
|
||||
value: [
|
||||
ls.value[0],
|
||||
keep || bool
|
||||
? formatPrometheusFloat(value)
|
||||
: filteredSampleValue,
|
||||
],
|
||||
},
|
||||
manySideIdx: lIdx,
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// If we originally swapped the LHS and RHS, swap them back to the original order.
|
||||
|
|
Loading…
Reference in a new issue