53 lines
2.7 KiB
TypeScript
53 lines
2.7 KiB
TypeScript
|
|
/**
|
||
|
|
* @module tests/integration/vector-recall
|
||
|
|
* @description Correctness guard for open-core semantic search on REAL
|
||
|
|
* embeddings (the production path): distinct documents embedded by Brainy's
|
||
|
|
* built-in model, queried by their own text, must return themselves as the top
|
||
|
|
* hit. This confirms the JS HNSW + cosine path retrieves correct neighbours on
|
||
|
|
* real embedding geometry.
|
||
|
|
*
|
||
|
|
* Why real embeddings and not a synthetic corpus: HNSW navigation depends on the
|
||
|
|
* smooth, locally-structured manifold that real embeddings occupy. Synthetic
|
||
|
|
* vectors (uniform-random, one-hot, or tight clusters) are near-orthogonal under
|
||
|
|
* cosine — concentration of measure leaves no gradient for greedy descent, so
|
||
|
|
* recall collapses regardless of the engine. That is a property of the data, not
|
||
|
|
* the index (verified: an exact query for the graph entry point returns it at
|
||
|
|
* cosine 1.0). The A/B's headline recall@10 column is therefore measured on
|
||
|
|
* SIFT/BIGANN (real data, canonical ground truth), identically for both legs.
|
||
|
|
*/
|
||
|
|
import { describe, it, expect, afterEach } from 'vitest'
|
||
|
|
import { Brainy } from '../../src/brainy.js'
|
||
|
|
import { NounType } from '../../src/types/graphTypes.js'
|
||
|
|
|
||
|
|
const TOPICS = [
|
||
|
|
'quantum physics particles', 'french cuisine recipes', 'basketball playoff games',
|
||
|
|
'jazz music history', 'volcanic rock formation', 'machine learning models',
|
||
|
|
'medieval castle architecture', 'tropical fish species', 'solar panel efficiency',
|
||
|
|
'ancient roman empire', 'coffee bean roasting', 'mountain climbing gear',
|
||
|
|
'classical piano sonatas', 'desert wildlife survival', 'space telescope images',
|
||
|
|
'wine fermentation process', 'bicycle frame materials', 'honeybee colony behavior',
|
||
|
|
'glacier ice formation', 'origami paper folding'
|
||
|
|
]
|
||
|
|
|
||
|
|
describe('open-core semantic search correctness (real embeddings)', () => {
|
||
|
|
const brains: Brainy[] = []
|
||
|
|
afterEach(async () => { for (const b of brains.splice(0)) await b.close() })
|
||
|
|
|
||
|
|
it('an exact-text query returns its own document as the top hit', async () => {
|
||
|
|
const brain = new Brainy({ storage: { type: 'memory' }, requireSubtype: false, silent: true })
|
||
|
|
await brain.init()
|
||
|
|
brains.push(brain)
|
||
|
|
for (let i = 0; i < TOPICS.length; i++) {
|
||
|
|
await brain.add({ data: TOPICS[i], type: NounType.Document, metadata: { idx: i } })
|
||
|
|
}
|
||
|
|
let hits = 0
|
||
|
|
for (let i = 0; i < TOPICS.length; i++) {
|
||
|
|
const got = await brain.find({ query: TOPICS[i], limit: 1 })
|
||
|
|
if ((got[0]?.metadata as { idx: number })?.idx === i) hits++
|
||
|
|
}
|
||
|
|
// Near-perfect; a couple of genuine semantic near-neighbours (e.g. glacier
|
||
|
|
// vs volcanic "rock/ice formation") may swap — allow a small margin.
|
||
|
|
expect(hits).toBeGreaterThanOrEqual(TOPICS.length - 3)
|
||
|
|
}, 240000)
|
||
|
|
})
|