mirror of
https://github.com/hellodigua/ChatLab.git
synced 2026-10-25 17:54:34 +08:00
fix(insight): bound graph look-ahead allocation
Clamp cluster look-ahead values at the shared core boundary so invalid inputs cannot create oversized candidate matrices. Add a regression test that keeps oversized values equivalent to the supported maximum.
This commit is contained in:
1 parent
4a3a72e736
commit
b7c38fb228
2 files changed
+28
-6
No files matched your search
@@ -213,6 +213,15 @@ describe('social analysis', () => {
|
||||
)
|
||||
})
|
||||
|
||||
it('caps oversized look-ahead values before allocating candidate indexes', () => {
|
||||
const messages = Array.from({ length: 12 }, (_, index) => ({ senderId: index + 1, ts: 100 + index }))
|
||||
|
||||
assert.deepEqual(
|
||||
accumulateCoOccurrencePairBatches([messages], { lookAhead: 100_000 }),
|
||||
accumulateCoOccurrencePairBatches([messages], { lookAhead: 10 })
|
||||
)
|
||||
})
|
||||
|
||||
it('keeps large streamed aggregation identical to the in-memory algorithm', () => {
|
||||
const senderPattern = [1, 1, 2, 3, 2, 4, 5]
|
||||
const messages = Array.from({ length: 100_005 }, (_, index) => ({
|
||||
|
||||
@@ -309,9 +309,22 @@ export interface SelectedCoOccurrencePairStats extends CoOccurrencePairStats {
|
||||
}
|
||||
|
||||
const DEFAULT_CLUSTER_OPTIONS = { lookAhead: 3, decaySeconds: 120, topEdges: 100 }
|
||||
const MAX_CLUSTER_LOOK_AHEAD = 10
|
||||
const DEFAULT_SELECTED_PROXIMITY_MAX_GAP_SECONDS = 1800
|
||||
const CO_OCCURRENCE_MESSAGE_BATCH_SIZE = 20_000
|
||||
|
||||
function resolveClusterOptions(options?: ClusterGraphOptions): Required<ClusterGraphOptions> {
|
||||
const requestedLookAhead = options?.lookAhead ?? DEFAULT_CLUSTER_OPTIONS.lookAhead
|
||||
const lookAhead = Number.isFinite(requestedLookAhead)
|
||||
? Math.min(MAX_CLUSTER_LOOK_AHEAD, Math.max(0, Math.ceil(requestedLookAhead)))
|
||||
: DEFAULT_CLUSTER_OPTIONS.lookAhead
|
||||
return {
|
||||
lookAhead,
|
||||
decaySeconds: options?.decaySeconds ?? DEFAULT_CLUSTER_OPTIONS.decaySeconds,
|
||||
topEdges: options?.topEdges ?? DEFAULT_CLUSTER_OPTIONS.topEdges,
|
||||
}
|
||||
}
|
||||
|
||||
function roundNum(value: number, digits = 4): number {
|
||||
const factor = 10 ** digits
|
||||
return Math.round(value * factor) / factor
|
||||
@@ -325,7 +338,7 @@ export function accumulateCoOccurrencePairs(
|
||||
messages: CoOccurrenceMessage[],
|
||||
options?: ClusterGraphOptions
|
||||
): CoOccurrencePairStats[] {
|
||||
const opts = { ...DEFAULT_CLUSTER_OPTIONS, ...options }
|
||||
const opts = resolveClusterOptions(options)
|
||||
const pairStatsBySource = new Map<number, Map<number, CoOccurrencePairStats>>()
|
||||
const pairs: CoOccurrencePairStats[] = []
|
||||
|
||||
@@ -398,8 +411,8 @@ function accumulateCoOccurrenceColumns(
|
||||
timestamps: Float64Array,
|
||||
options?: ClusterGraphOptions
|
||||
): CoOccurrencePairStats[] {
|
||||
const opts = { ...DEFAULT_CLUSTER_OPTIONS, ...options }
|
||||
const lookAhead = Math.max(0, Math.ceil(opts.lookAhead))
|
||||
const opts = resolveClusterOptions(options)
|
||||
const lookAhead = opts.lookAhead
|
||||
const candidateIndexes = buildDistinctSpeakerLookAhead(senderIds.length, (index) => senderIds[index], lookAhead)
|
||||
const pairStatsBySource = new Map<number, Map<number, CoOccurrencePairStats>>()
|
||||
const pairs: CoOccurrencePairStats[] = []
|
||||
@@ -459,8 +472,8 @@ export function accumulateSelectedCoOccurrencePairs(
|
||||
selectedPairs: Array<readonly [number, number]>,
|
||||
options?: ClusterGraphOptions & { maxAnchorsPerPair?: number; maxGapSeconds?: number }
|
||||
): SelectedCoOccurrencePairStats[] {
|
||||
const opts = { ...DEFAULT_CLUSTER_OPTIONS, ...options }
|
||||
const lookAhead = Math.max(0, Math.ceil(opts.lookAhead))
|
||||
const opts = resolveClusterOptions(options)
|
||||
const lookAhead = opts.lookAhead
|
||||
const maxAnchorsPerPair = Math.max(0, Math.floor(options?.maxAnchorsPerPair ?? 2))
|
||||
const maxGapSeconds = Math.max(0, options?.maxGapSeconds ?? DEFAULT_SELECTED_PROXIMITY_MAX_GAP_SECONDS)
|
||||
const selectedKeys = new Set(selectedPairs.map(([left, right]) => clusterPairKey(left, right)))
|
||||
@@ -615,7 +628,7 @@ export function getClusterGraph(
|
||||
filter?: TimeFilter,
|
||||
options?: ClusterGraphOptions
|
||||
): ClusterGraphData {
|
||||
const opts = { ...DEFAULT_CLUSTER_OPTIONS, ...options }
|
||||
const opts = resolveClusterOptions(options)
|
||||
const emptyResult: ClusterGraphData = {
|
||||
nodes: [],
|
||||
links: [],
|
||||
|
||||
Reference in new issue
Block a user