perf(scoring): optimized retrieval engine with caching and IDF smoothing v2.69.0
This commit is contained in:
@@ -28,16 +28,43 @@ const STOP_WORDS_KO = new Set([
|
||||
'대한', '대해', '통해', '따라', '위해', '대로', '만큼'
|
||||
]);
|
||||
|
||||
// ─── Internal Cache for Tokenization ───
|
||||
const TOKEN_CACHE = new Map<string, string[]>();
|
||||
const MAX_CACHE_SIZE = 1000;
|
||||
|
||||
/**
|
||||
* 한국어/영어 혼합 텍스트를 토큰으로 분리합니다.
|
||||
* 한국어/영어 혼합 텍스트를 정규화하고 토큰으로 분리합니다.
|
||||
* (Performance Optimization: 내부 캐시 적용)
|
||||
*/
|
||||
export function tokenize(text: string): string[] {
|
||||
return text
|
||||
if (!text) return [];
|
||||
|
||||
// 캐시 확인
|
||||
if (TOKEN_CACHE.has(text)) {
|
||||
return TOKEN_CACHE.get(text)!;
|
||||
}
|
||||
|
||||
// 1. Pre-normalization: 특수문자 정제 및 표준화
|
||||
const normalized = text
|
||||
.toLowerCase()
|
||||
.replace(/[\u200B-\u200D\uFEFF]/g, '') // Zero-width spaces 제거
|
||||
.replace(/[^\w\s가-힣_.-]/g, ' ') // 허용된 문자 외에는 공백 처리
|
||||
.trim();
|
||||
|
||||
// 2. Tokenization: 정제된 텍스트 분리
|
||||
const tokens = normalized
|
||||
.split(/[^a-z0-9가-힣_.-]+/g)
|
||||
.map((t) => t.trim())
|
||||
.filter((t) => t.length >= 2)
|
||||
.filter((t) => !STOP_WORDS_EN.has(t) && !STOP_WORDS_KO.has(t));
|
||||
|
||||
// 캐시 저장 (메모리 관리: 임계값 초과 시 비우기)
|
||||
if (TOKEN_CACHE.size >= MAX_CACHE_SIZE) {
|
||||
TOKEN_CACHE.clear();
|
||||
}
|
||||
TOKEN_CACHE.set(text, tokens);
|
||||
|
||||
return tokens;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -90,13 +117,24 @@ function termFrequency(term: string, documentTokens: string[]): number {
|
||||
|
||||
/**
|
||||
* IDF (Inverse Document Frequency): 전체 문서 대비 희소도
|
||||
* (Stability Enhancement: Smoothing 적용 및 최소 문서 수 대응)
|
||||
*/
|
||||
function inverseDocumentFrequency(
|
||||
term: string,
|
||||
allDocumentTokenSets: Array<Set<string>>
|
||||
): number {
|
||||
const N = allDocumentTokenSets.length;
|
||||
if (N === 0) return 1.0;
|
||||
|
||||
const containing = allDocumentTokenSets.filter((doc) => doc.has(term)).length;
|
||||
return Math.log((allDocumentTokenSets.length + 1) / (containing + 1)) + 1;
|
||||
|
||||
// N이 매우 작을 때(예: 5개 이하) 스코어 편향 방지를 위한 최소 분모 보정
|
||||
const smoothN = N < 5 ? N + 5 : N;
|
||||
const smoothContaining = containing;
|
||||
|
||||
// Standard Smooth IDF: log((N+1) / (containing+1)) + 1
|
||||
// containing이 0일 경우에도 안전하게 동작하도록 설계
|
||||
return Math.log((smoothN + 1) / (smoothContaining + 1)) + 1;
|
||||
}
|
||||
|
||||
export interface ScoredDocument {
|
||||
|
||||
Reference in New Issue
Block a user