This commit is contained in:
张成
2026-02-28 13:51:17 +08:00
parent 58c9d64e55
commit 0483d6d023
7 changed files with 76 additions and 234 deletions

View File

@@ -63,7 +63,11 @@ class ConfigManager {
page_count: 3, // 搜索页数
keywords: [], // 搜索关键词
exclude_keywords: [], // 排除关键词
time_range: null // 时间范围
time_range: null, // 时间范围
city: '', // 城市
salary_range: '', // 薪资范围
experience: '', // 经验
education: '' // 学历
};
return this.parseConfig(searchConfig, defaultConfig);

View File

@@ -3,18 +3,19 @@ const KeywordMatcher = require('../utils/keywordMatcher');
const db = require('../../dbProxy');
/**
* 职位过滤引擎
* 综合处理职位的过滤、评分和排序
* 职位过滤引擎schedule 自动投递用)
* 本文件集中:过滤(薪资/关键词/活跃度/去重)+ 评分(权重分+关键词奖励)+ 按分数阈值筛。
* 自动投递只需调 filterAndScoreJobsForDeliver 一个方法。
*/
class JobFilterEngine {
/**
* 过滤职位列表
* 过滤职位列表(薪资 → 关键词 → 活跃度 → 去重)
* @param {Array} jobs - 职位列表
* @param {object} config - 过滤配置
* @param {object} resumeInfo - 简历信息
* @param {object} resumeInfo - 简历信息(未使用,兼容签名)
* @returns {Promise<Array>} 过滤后的职位列表
*/
async filterJobs(jobs, config, resumeInfo = {}) {
async filterJobs(jobs, config) {
if (!jobs || jobs.length === 0) {
return [];
}
@@ -61,6 +62,59 @@ class JobFilterEngine {
return filtered;
}
/**
* 自动投递用:过滤 + 评分 + 按 60 分阈值筛,一次调用完成(便于阅读与维护)
*/
async filterAndScoreJobsForDeliver(jobs, filterConfig, resume, accountConfig, jobTypeConfig, recentCompanies) {
const scored = [];
const jobDesc = (j) => `${j.companyName || '?'} / ${j.jobTitle || '?'}`;
const { jobFilterService } = require('../../job/services');
console.log(`[jobFilterEngine] filterAndScoreJobsForDeliver 开始,待处理: ${jobs.length}`);
for (const job of jobs) {
if (job.companyName && recentCompanies.has(job.companyName)) {
console.log(`[jobFilterEngine] 已投递公司 剔除: ${jobDesc(job)}`);
continue;
}
const filtered = await this.filterJobs([job], filterConfig, resume);
if (filtered.length === 0) {
console.log(`[jobFilterEngine] 过滤条件不通过 剔除: ${jobDesc(job)}`);
continue;
}
const scoreResult = jobFilterService.calculateJobScoreWithWeights(
job,
resume,
accountConfig,
jobTypeConfig,
accountConfig.is_salary_priority || []
);
const keywordBonus = KeywordMatcher.calculateBonus(
`${job.jobTitle || ''} ${job.companyName || ''} ${job.jobDescription || ''}`,
filterConfig.filter_keywords || [],
{ baseScore: 5, maxBonus: 20 }
);
const finalScore = scoreResult.totalScore + keywordBonus.score;
if (finalScore < 60) {
console.log(`[jobFilterEngine] 评分不足(>=60) 剔除: ${jobDesc(job)} 总分=${finalScore.toFixed(1)}`);
continue;
}
scored.push({
...job,
matchScore: finalScore,
scoreDetails: { ...scoreResult.scores, keywordBonus: keywordBonus.score }
});
}
scored.sort((a, b) => b.matchScore - a.matchScore);
console.log(`[jobFilterEngine] filterAndScoreJobsForDeliver 结束: 原始${jobs.length} 通过${scored.length}`);
return scored;
}
/**
* 按薪资过滤
* @param {Array} jobs - 职位列表
@@ -99,14 +153,6 @@ class JobFilterEngine {
return KeywordMatcher.filterJobs(jobs, {
excludeKeywords: exclude_keywords,
filterKeywords: filter_keywords
}, (job) => {
// 组合职位名称、描述、技能要求等
return [
job.name || job.jobName || '',
job.description || job.jobDescription || '',
job.skills || '',
job.welfare || ''
].join(' ');
});
}
@@ -376,39 +422,6 @@ class JobFilterEngine {
return sorted;
}
/**
* 综合处理:过滤 + 评分 + 排序
* @param {Array} jobs - 职位列表
* @param {object} config - 过滤配置
* @param {object} resumeInfo - 简历信息
* @param {object} options - 选项
* @returns {Promise<Array>} 处理后的职位列表
*/
async process(jobs, config, resumeInfo = {}, options = {}) {
const {
maxCount = 10, // 最大返回数量
sortBy = 'score' // 排序方式
} = options;
// 1. 过滤
let filtered = await this.filterJobs(jobs, config, resumeInfo);
console.log(`[职位过滤] 原始: ${jobs.length} 个,过滤后: ${filtered.length}`);
// 2. 评分
const scored = this.scoreJobs(filtered, resumeInfo, config);
// 3. 排序
const sorted = this.sortJobs(scored, sortBy);
// 4. 截取
const result = sorted.slice(0, maxCount);
console.log(`[职位过滤] 最终返回: ${result.length} 个职位`);
return result;
}
}
// 导出单例