This commit is contained in:
张成
2026-04-08 16:39:27 +08:00
parent 048c40d802
commit f2a8e61016
8 changed files with 597 additions and 66 deletions

View File

@@ -9,7 +9,7 @@ const db = require('../../dbProxy');
*/
class JobFilterEngine {
/**
* 过滤职位列表(薪资 → 关键词 → 活跃度 → 去重)
* 过滤职位列表(薪资 → 标题须含词 → 关键词 → 活跃度 → 去重)
* @param {Array} jobs - 职位列表
* @param {object} config - 过滤配置
* @param {object} resumeInfo - 简历信息(未使用,兼容签名)
@@ -30,31 +30,39 @@ class JobFilterEngine {
console.log(`[jobFilterEngine] 步骤1-薪资过滤: 输入${beforeSalary} 输出${filtered.length} 剔除${salaryRemoved} (范围: ${config.min_salary ?? 0}-${config.max_salary ?? 0}K)`);
}
// 2. 关键词过滤
// 2. 职位标题须包含job_types.titleIncludeKeywords仅 jobTitle/jobName/name与 commonSkills 无关)
const beforeTitleKw = filtered.length;
filtered = this.filterByTitleIncludeKeywords(filtered, config);
const titleKwRemoved = beforeTitleKw - filtered.length;
if (titleKwRemoved > 0) {
console.log(`[jobFilterEngine] 步骤2-标题须含: 输入${beforeTitleKw} 输出${filtered.length} 剔除${titleKwRemoved} (须同时含: ${(config.title_include_keywords || []).join(' · ') || '无'})`);
}
// 3. 关键词过滤(排除词 + filter_keywords匹配标题与行业等
const beforeKeywords = filtered.length;
filtered = this.filterByKeywords(filtered, config);
const keywordsRemoved = beforeKeywords - filtered.length;
if (keywordsRemoved > 0) {
console.log(`[jobFilterEngine] 步骤2-关键词过滤: 输入${beforeKeywords} 输出${filtered.length} 剔除${keywordsRemoved} (排除: ${(config.exclude_keywords || []).join(',') || '无'} 包含: ${(config.filter_keywords || []).join(',') || '无'})`);
console.log(`[jobFilterEngine] 步骤3-关键词过滤: 输入${beforeKeywords} 输出${filtered.length} 剔除${keywordsRemoved} (排除: ${(config.exclude_keywords || []).join(',') || '无'} 包含: ${(config.filter_keywords || []).join(',') || '无'})`);
}
// 3. 公司活跃度过滤
// 4. 公司活跃度过滤
if (config.filter_inactive_companies) {
const beforeActivity = filtered.length;
filtered = await this.filterByCompanyActivity(filtered, config.company_active_days || 7);
const activityRemoved = beforeActivity - filtered.length;
if (activityRemoved > 0) {
console.log(`[jobFilterEngine] 步骤3-公司活跃度过滤: 输入${beforeActivity} 输出${filtered.length} 剔除${activityRemoved}`);
console.log(`[jobFilterEngine] 步骤4-公司活跃度过滤: 输入${beforeActivity} 输出${filtered.length} 剔除${activityRemoved}`);
}
}
// 4. 去重(同一公司、同一职位名称)
// 5. 去重(同一公司、同一职位名称)
if (config.deduplicate) {
const beforeDedup = filtered.length;
filtered = this.deduplicateJobs(filtered);
const dedupRemoved = beforeDedup - filtered.length;
if (dedupRemoved > 0) {
console.log(`[jobFilterEngine] 步骤4-去重: 输入${beforeDedup} 输出${filtered.length} 剔除${dedupRemoved}`);
console.log(`[jobFilterEngine] 步骤5-去重: 输入${beforeDedup} 输出${filtered.length} 剔除${dedupRemoved}`);
}
}
@@ -134,6 +142,29 @@ class JobFilterEngine {
});
}
/**
* 职位标题须包含配置中的每个子串AND 关系),不扫描描述/公司名/commonSkills
* @param {Array} jobs
* @param {object} config
* @returns {Array}
*/
filterByTitleIncludeKeywords(jobs, config) {
const kws = config.title_include_keywords;
if (!Array.isArray(kws) || kws.length === 0) {
return jobs;
}
return jobs.filter((job) => {
const title = `${job.jobTitle || job.jobName || job.name || ''}`.toLowerCase();
return kws.every((kw) => {
const k = String(kw || '').toLowerCase().trim();
if (!k) {
return true;
}
return title.includes(k);
});
});
}
/**
* 按关键词过滤
* @param {Array} jobs - 职位列表