86 lines
2.3 KiB
JavaScript
86 lines
2.3 KiB
JavaScript
// ═══════════════════════════════════════════════════════════════════════════
|
||
// Text Search - L2 事件文本检索(MiniSearch)
|
||
// 与向量检索互补,通过 RRF 融合
|
||
// ═══════════════════════════════════════════════════════════════════════════
|
||
|
||
import MiniSearch from '../../../libs/minisearch.mjs';
|
||
|
||
let idx = null;
|
||
let lastRevision = null;
|
||
|
||
/**
|
||
* 中文逐字 + 英数字串分词
|
||
*/
|
||
function tokenize(text) {
|
||
return String(text || '').match(/[\u4e00-\u9fff]|[a-zA-Z0-9]+/g) || [];
|
||
}
|
||
|
||
/**
|
||
* 去掉 summary 末尾的楼层标记
|
||
*/
|
||
function stripFloorTag(s) {
|
||
return String(s || '').replace(/\s*\(#\d+(?:-\d+)?\)\s*$/, '').trim();
|
||
}
|
||
|
||
/**
|
||
* 构建/更新事件文本索引
|
||
*/
|
||
export function ensureEventTextIndex(events, revision) {
|
||
if (!events?.length) {
|
||
idx = null;
|
||
lastRevision = null;
|
||
return;
|
||
}
|
||
|
||
if (idx && revision === lastRevision) return;
|
||
|
||
try {
|
||
idx = new MiniSearch({
|
||
fields: ['title', 'summary', 'participants'],
|
||
storeFields: ['id'],
|
||
tokenize,
|
||
});
|
||
|
||
idx.addAll(events.map(e => ({
|
||
id: e.id,
|
||
title: e.title || '',
|
||
summary: stripFloorTag(e.summary),
|
||
participants: (e.participants || []).join(' '),
|
||
})));
|
||
|
||
lastRevision = revision;
|
||
} catch (e) {
|
||
console.error('[text-search] Index build failed:', e);
|
||
idx = null;
|
||
lastRevision = null;
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 文本检索事件
|
||
*/
|
||
export function searchEventsByText(queryText, limit = 80) {
|
||
if (!idx || !queryText?.trim()) return [];
|
||
|
||
try {
|
||
const res = idx.search(queryText, {
|
||
limit,
|
||
boost: { title: 2, participants: 1.5, summary: 1 },
|
||
fuzzy: 0.2,
|
||
prefix: true,
|
||
});
|
||
return res.map((r, i) => ({ id: r.id, textRank: i + 1 }));
|
||
} catch (e) {
|
||
console.error('[text-search] Search failed:', e);
|
||
return [];
|
||
}
|
||
}
|
||
|
||
/**
|
||
* 清理索引
|
||
*/
|
||
export function clearEventTextIndex() {
|
||
idx = null;
|
||
lastRevision = null;
|
||
}
|