Files
FastGPT/test/integrationTest/vectorDB/testSuites.ts
Archer 64f70a41c1 feat: vector integrationTest;feat: ob quantization (#6366)
* feat(vectordb): add OceanBase HNSW quantization (HNSW_SQ/HNSW_BQ) (#6348)

Support OceanBase vector index quantization via VECTOR_VQ_LEVEL:
- 32 (default): hnsw + inner_product
- 8: hnsw_sq + inner_product (2-3x memory savings)
- 1: hnsw_bq + cosine (~15x memory savings)

HNSW_BQ requires cosine distance per OceanBase docs.
Tested on OceanBase 4.3.5.5 (BP5).

Closes #6202

* feat: add test inclusion for vectorDB tests in vitest configuration (#6358)

* feat: add test inclusion for vectorDB tests in vitest configuration

* refactor: update vectorDB README and setup for environment configuration

- Enhanced README to clarify the use of factory pattern for vectorDB integration tests.
- Updated instructions for setting up environment variables from a local file.
- Removed obsolete PG integration test file and adjusted test execution instructions.
- Improved structure explanation for shared test data and factory functions.

* perf: integrationTest

* feat: vector integration

---------

Co-authored-by: ZHANG Yixin <hi.yixinz@gmail.com>
Co-authored-by: Jingchao <alswlx@gmail.com>
2026-02-02 18:48:25 +08:00

160 lines
4.9 KiB
TypeScript

import { beforeAll, describe, expect, test } from 'vitest';
import type { VectorControllerType } from '@fastgpt/service/common/vectorDB/type';
import { createTestIds, QUERY_VECTOR, TEST_COLLECTION_IDS, TEST_VECTORS } from './testData';
const insertTestVectors = async (
vectorCtrl: VectorControllerType,
teamId: string,
datasetId: string
) => {
const insertIds: string[] = [];
await Promise.all(
TEST_VECTORS.map(async (vector, index) => {
const { insertIds: ids } = await vectorCtrl.insert({
teamId,
datasetId,
collectionId: TEST_COLLECTION_IDS[index],
vectors: [vector]
});
insertIds.push(ids[0]);
})
);
await new Promise((resolve) => setTimeout(resolve, 500));
return insertIds;
};
const cleanupTestVectors = async (
vectorCtrl: VectorControllerType,
teamId: string,
datasetId: string
) => {
try {
await vectorCtrl.delete({
teamId,
datasetIds: [datasetId]
});
} catch (error) {
// Ignore cleanup errors
}
};
export const createVectorDBTestSuite = (vectorCtrl: VectorControllerType) => {
describe.sequential('vectorDB integration', () => {
beforeAll(async () => {
await vectorCtrl.init();
});
test('insert and count', async () => {
const { teamId, datasetId } = createTestIds();
const insertIds = await insertTestVectors(vectorCtrl, teamId, datasetId);
expect(insertIds).toHaveLength(TEST_VECTORS.length);
const count = await vectorCtrl.getVectorCount({ teamId, datasetId });
expect(count).toBe(TEST_VECTORS.length);
const collectionCount = await vectorCtrl.getVectorCount({
teamId,
datasetId,
collectionId: TEST_COLLECTION_IDS[0]
});
expect(collectionCount).toBe(1);
await cleanupTestVectors(vectorCtrl, teamId, datasetId);
});
test('embRecall returns results', async () => {
const { teamId, datasetId } = createTestIds();
await insertTestVectors(vectorCtrl, teamId, datasetId);
const { results } = await vectorCtrl.embRecall({
teamId,
datasetIds: [datasetId],
vector: QUERY_VECTOR,
limit: 3,
forbidCollectionIdList: []
});
expect(results.length).toBeGreaterThan(0);
expect(results.every((item) => TEST_COLLECTION_IDS.includes(item.collectionId))).toBe(true);
await cleanupTestVectors(vectorCtrl, teamId, datasetId);
});
test('embRecall respects forbidCollectionIdList', async () => {
const { teamId, datasetId } = createTestIds();
await insertTestVectors(vectorCtrl, teamId, datasetId);
const { results } = await vectorCtrl.embRecall({
teamId,
datasetIds: [datasetId],
vector: QUERY_VECTOR,
limit: 10,
forbidCollectionIdList: [TEST_COLLECTION_IDS[0]]
});
expect(results.length).toBeGreaterThan(0);
expect(results.every((item) => item.collectionId !== TEST_COLLECTION_IDS[0])).toBe(true);
await cleanupTestVectors(vectorCtrl, teamId, datasetId);
});
test('embRecall respects filterCollectionIdList', async () => {
const { teamId, datasetId } = createTestIds();
await insertTestVectors(vectorCtrl, teamId, datasetId);
const { results } = await vectorCtrl.embRecall({
teamId,
datasetIds: [datasetId],
vector: QUERY_VECTOR,
limit: 10,
forbidCollectionIdList: [],
filterCollectionIdList: [TEST_COLLECTION_IDS[1]]
});
expect(results.length).toBeGreaterThan(0);
expect(results.every((item) => item.collectionId === TEST_COLLECTION_IDS[1])).toBe(true);
await cleanupTestVectors(vectorCtrl, teamId, datasetId);
});
test('getVectorDataByTime returns data', async () => {
const { teamId, datasetId } = createTestIds();
const insertIds = await insertTestVectors(vectorCtrl, teamId, datasetId);
await new Promise((resolve) => setTimeout(resolve, 500));
const start = new Date(0);
const end = new Date(Date.now() + 600_000);
const data = await vectorCtrl.getVectorDataByTime(start, end);
const matchedIds = data
.filter((item) => item.teamId === teamId && item.datasetId === datasetId)
.map((item) => item.id);
expect(matchedIds.length).toBeGreaterThan(0);
expect(matchedIds).toEqual(expect.arrayContaining(insertIds));
await cleanupTestVectors(vectorCtrl, teamId, datasetId);
});
test('delete by idList removes vectors', async () => {
const { teamId, datasetId } = createTestIds();
const insertIds = await insertTestVectors(vectorCtrl, teamId, datasetId);
await vectorCtrl.delete({
teamId,
idList: insertIds.slice(0, 2)
});
const count = await vectorCtrl.getVectorCount({ teamId, datasetId });
expect(count).toBe(TEST_VECTORS.length - 2);
await cleanupTestVectors(vectorCtrl, teamId, datasetId);
});
});
};