65 lines
3.3 KiB
JavaScript
65 lines
3.3 KiB
JavaScript
// 把 MongoDB knowledge 集合里已有的向量重建进 DashVector 索引。
|
|
//
|
|
// 何时用:①首次接入 DashVector(建集合 + 灌存量向量);②补齐入库时同步失败的块(标了 vectorPending 的);
|
|
// ③换过 embedding 维度后重灌(见下"换维度")。
|
|
//
|
|
// 幂等性:本脚本用 insert 语义,只【补齐缺失】的向量、灌成功后清 vectorPending 标记。它【不覆盖】已存在
|
|
// 同 _id 的向量(在线入库每块都是全新 _id,不会撞;故正常场景无需覆盖)。
|
|
// ⚠ 换维度 / 修复"已存在但内容错"的向量:insert 不覆盖,必须【新建集合】——把 .env 的 DASHVECTOR_COLLECTION
|
|
// 改成新名(或在阿里云控制台删掉旧集合)后再跑本脚本。ensureCollection 已会在维度不符时【大声报错】提示你。
|
|
//
|
|
// 用法(服务器后端目录内,.env 里已配好 DASHVECTOR_*): node scripts/reindex-vectors.js
|
|
// MongoDB 永远是真相源,本脚本只把真相源投影进向量索引;不改动 knowledge 任何数据(仅清 vectorPending 标记)。
|
|
import 'dotenv/config';
|
|
import { connectDb, getDb, closeDb } from '../src/db.js';
|
|
import { config } from '../src/config.js';
|
|
import { vectorEnabled, ensureCollection, vectorUpsert } from '../src/services/vectorStore.js';
|
|
|
|
async function run() {
|
|
if (!vectorEnabled()) {
|
|
console.error('❌ 向量库未启用。请在 .env 配 DASHVECTOR_ENDPOINT / DASHVECTOR_API_KEY(和可选 DASHVECTOR_COLLECTION),再重跑。');
|
|
process.exit(1);
|
|
}
|
|
console.log(`向量库: DashVector · collection=${config.vector.dashvector.collection} · dim=${config.vector.dashvector.dim}`);
|
|
|
|
console.log('① 确保集合存在且就绪(维度不符会在此报错)…');
|
|
const c = await ensureCollection();
|
|
console.log(c.existed ? ' 集合已存在,复用。' : c.notReady ? ' 集合已创建(尚未就绪,后续写入会自动重试)。' : ' 集合已创建、就绪。');
|
|
|
|
await connectDb();
|
|
const db = getDb();
|
|
const cursor = db.collection('knowledge')
|
|
.find({ embedding: { $type: 'array' } })
|
|
.project({ embedding: 1, twinId: 1, sourceType: 1 })
|
|
.addCursorFlag('noCursorTimeout', true) // 大集合 + 慢/限流的 DashVector:防两次 getMore 间的阻塞 upsert 超过游标空闲超时(10min)
|
|
.batchSize(500);
|
|
|
|
let batch = [];
|
|
let ids = [];
|
|
let total = 0;
|
|
const BATCH = 200;
|
|
const flush = async () => {
|
|
if (!batch.length) return;
|
|
await vectorUpsert(batch);
|
|
// 灌成功 → 清掉这些块入库时可能打上的 vectorPending 标记(它们已进索引)。
|
|
try { await db.collection('knowledge').updateMany({ _id: { $in: ids } }, { $unset: { vectorPending: '' } }); } catch { /* 清标失败无害 */ }
|
|
total += batch.length;
|
|
process.stdout.write(`\r 已重建 ${total} 块…`);
|
|
batch = []; ids = [];
|
|
};
|
|
|
|
console.log('② 遍历 knowledge 集合,灌入向量…');
|
|
for await (const d of cursor) {
|
|
if (!Array.isArray(d.embedding) || !d.embedding.length) continue;
|
|
batch.push({ id: String(d._id), embedding: d.embedding, twinId: String(d.twinId), sourceType: d.sourceType || 'text' });
|
|
ids.push(d._id);
|
|
if (batch.length >= BATCH) await flush();
|
|
}
|
|
await flush();
|
|
|
|
console.log(`\n✅ 完成。共重建 ${total} 块向量进 DashVector。`);
|
|
await closeDb();
|
|
}
|
|
|
|
run().catch((e) => { console.error('\n❌ 重建失败:', e.message); process.exit(1); });
|