11
This commit is contained in:
@@ -5,7 +5,7 @@ const db = require('../../dbProxy');
|
||||
/**
|
||||
* 职位过滤引擎(schedule 自动投递用)
|
||||
* 本文件集中:过滤(薪资/关键词/活跃度/去重)+ 评分(权重分+关键词奖励)+ 按分数阈值筛。
|
||||
* 自动投递只需调 filterAndScoreJobsForDeliver 一个方法。
|
||||
* 自动投递调用 filterAndScoreJobsForDeliver,返回 { scored, skipReasonByJobId }。
|
||||
*/
|
||||
class JobFilterEngine {
|
||||
getJobKey(job) {
|
||||
@@ -89,24 +89,82 @@ class JobFilterEngine {
|
||||
return filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* 单条职位:判断 filterJobs 中哪一步未通过(用于写入 job_postings.deliver_failed_reason)
|
||||
*/
|
||||
async get_single_job_filter_fail_reason(job, config) {
|
||||
const j = job;
|
||||
const after_salary = this.filterBySalary([j], config);
|
||||
if (after_salary.length === 0) {
|
||||
return `薪资不在设定范围(${config.min_salary ?? 0}-${config.max_salary ?? 0}K)`;
|
||||
}
|
||||
const after_title = this.filterByTitleIncludeKeywords(after_salary, config);
|
||||
if (after_title.length === 0) {
|
||||
const kws = (config.title_include_keywords || []).join('、') || '无';
|
||||
return `职位标题须包含以下关键词之一:${kws}`;
|
||||
}
|
||||
const after_kw = this.filterByKeywords(after_title, config);
|
||||
if (after_kw.length === 0) {
|
||||
const match_text = `${j.jobTitle || ''}`;
|
||||
const match_result = KeywordMatcher.match(match_text, {
|
||||
excludeKeywords: Array.isArray(config.exclude_keywords) ? config.exclude_keywords : [],
|
||||
filterKeywords: Array.isArray(config.filter_keywords) ? config.filter_keywords : [],
|
||||
bonusKeywords: []
|
||||
});
|
||||
if (match_result && match_result.details && match_result.details.exclude && match_result.details.exclude.matched) {
|
||||
const hit_keywords = match_result.details.exclude.keywords || [];
|
||||
if (hit_keywords.length) {
|
||||
return `命中排除关键词: ${hit_keywords.join('、')}`;
|
||||
}
|
||||
}
|
||||
if (match_result && match_result.details && match_result.details.filter && !match_result.details.filter.matched) {
|
||||
const needed = Array.isArray(config.filter_keywords) ? config.filter_keywords : [];
|
||||
if (needed.length) {
|
||||
return `未命中包含关键词: ${needed.join('、')}`;
|
||||
}
|
||||
}
|
||||
return '命中排除关键词或未满足包含词规则';
|
||||
}
|
||||
if (config.filter_inactive_companies) {
|
||||
const after_act = await this.filterByCompanyActivity(after_kw, config.company_active_days || 7);
|
||||
if (after_act.length === 0) {
|
||||
return '公司活跃度不满足配置';
|
||||
}
|
||||
}
|
||||
if (config.deduplicate) {
|
||||
const after_dedup = this.deduplicateJobs(after_kw);
|
||||
if (after_dedup.length === 0) {
|
||||
return '与列表内职位重复(公司+岗位名)';
|
||||
}
|
||||
}
|
||||
return '未通过职位过滤';
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动投递用:过滤 + 评分 + 按 60 分阈值筛,一次调用完成(便于阅读与维护)
|
||||
* @returns {{ scored: Array, skipReasonByJobId: Record<number|string, string> }}
|
||||
*/
|
||||
async filterAndScoreJobsForDeliver(jobs, filterConfig, resume, accountConfig, jobTypeConfig, recentCompanies) {
|
||||
const scored = [];
|
||||
const skipReasonByJobId = {};
|
||||
const jobDesc = (j) => `${j.companyName || '?'} / ${j.jobTitle || '?'}`;
|
||||
const { jobFilterService } = require('../../job/services');
|
||||
|
||||
console.log(`[jobFilterEngine] filterAndScoreJobsForDeliver 开始,待处理: ${jobs.length}`);
|
||||
|
||||
for (const job of jobs) {
|
||||
const job_id = job.id;
|
||||
if (job.companyName && recentCompanies.has(job.companyName)) {
|
||||
const msg = '近期已在配置天数内投递过该公司';
|
||||
if (job_id != null) skipReasonByJobId[job_id] = msg;
|
||||
console.log(`[jobFilterEngine] 已投递公司 剔除: ${jobDesc(job)}`);
|
||||
continue;
|
||||
}
|
||||
|
||||
const filtered = await this.filterJobs([job], filterConfig, resume);
|
||||
if (filtered.length === 0) {
|
||||
const reason = await this.get_single_job_filter_fail_reason(job, filterConfig);
|
||||
if (job_id != null) skipReasonByJobId[job_id] = reason;
|
||||
console.log(`[jobFilterEngine] 过滤条件不通过 剔除: ${jobDesc(job)}`);
|
||||
continue;
|
||||
}
|
||||
@@ -126,6 +184,8 @@ class JobFilterEngine {
|
||||
const finalScore = scoreResult.totalScore + keywordBonus.score;
|
||||
|
||||
if (finalScore < 60) {
|
||||
const msg = `评分不足(总分${finalScore.toFixed(1)},需>=60)`;
|
||||
if (job_id != null) skipReasonByJobId[job_id] = msg;
|
||||
console.log(`[jobFilterEngine] 评分不足(>=60) 剔除: ${jobDesc(job)} 总分=${finalScore.toFixed(1)}`);
|
||||
continue;
|
||||
}
|
||||
@@ -139,7 +199,7 @@ class JobFilterEngine {
|
||||
|
||||
scored.sort((a, b) => b.matchScore - a.matchScore);
|
||||
console.log(`[jobFilterEngine] filterAndScoreJobsForDeliver 结束: 原始${jobs.length} 通过${scored.length}`);
|
||||
return scored;
|
||||
return { scored, skipReasonByJobId };
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user