mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-10 08:05:14 +02:00
52 lines
1.5 KiB
TypeScript
52 lines
1.5 KiB
TypeScript
import { describe, expect, it } from 'vitest';
|
|
import { compareFusedSearchCandidates, DEFAULT_SEARCH_LANE_WEIGHTS, rrfContribution } from './rrf.js';
|
|
import type { FusedSearchCandidate } from './types.js';
|
|
|
|
describe('RRF scoring', () => {
|
|
it('uses the shared lane weights from the hybrid search spec', () => {
|
|
expect(DEFAULT_SEARCH_LANE_WEIGHTS).toEqual({
|
|
semantic: 2,
|
|
dictionary: 2,
|
|
lexical: 1.5,
|
|
token: 0.75,
|
|
});
|
|
});
|
|
|
|
it('calculates a weighted RRF contribution with k=60 by default', () => {
|
|
expect(rrfContribution(2, 1)).toBeCloseTo(2 / 61, 12);
|
|
expect(rrfContribution(1.5, 2)).toBeCloseTo(1.5 / 62, 12);
|
|
});
|
|
|
|
it('sorts fused candidates by score, lane count, and stable id', () => {
|
|
const first: FusedSearchCandidate = {
|
|
id: 'orders',
|
|
score: 0.05,
|
|
matchReasons: ['lexical'],
|
|
ranksByLane: { lexical: 1 },
|
|
rawScoresByLane: {},
|
|
evidenceByLane: {},
|
|
};
|
|
const second: FusedSearchCandidate = {
|
|
id: 'customers',
|
|
score: 0.05,
|
|
matchReasons: ['lexical', 'semantic'],
|
|
ranksByLane: { lexical: 2, semantic: 1 },
|
|
rawScoresByLane: {},
|
|
evidenceByLane: {},
|
|
};
|
|
const third: FusedSearchCandidate = {
|
|
id: 'accounts',
|
|
score: 0.04,
|
|
matchReasons: ['semantic'],
|
|
ranksByLane: { semantic: 1 },
|
|
rawScoresByLane: {},
|
|
evidenceByLane: {},
|
|
};
|
|
|
|
expect([first, second, third].sort(compareFusedSearchCandidates).map((candidate) => candidate.id)).toEqual([
|
|
'customers',
|
|
'orders',
|
|
'accounts',
|
|
]);
|
|
});
|
|
});
|