Files
ks-app-employment-service/utils/similarity_Job.js

347 lines
12 KiB
JavaScript
Raw Permalink Normal View History

2025-03-28 15:19:42 +08:00
// 使用Intl.Segmenter对中文文本进行分词
function segmentText(text) {
const segmenter = new Intl.Segmenter('zh-Hans', {
granularity: 'word'
}); // 使用中文简体语言
const segments = [];
for (let segment of segmenter.segment(text.toLowerCase())) { // 转为小写后进行分词
segments.push(segment.segment);
}
return segments;
}
// 语气 停用次
const stopWords = ['的', '了', '啊', '哦', '/', '、', ' ', '', '-', '', '', '(', ')', '+', "=", "~", "!", "<", ">", "?",
"[", "]", "{", "}"
]
function cleanKeywords(arr) {
return arr.filter(word => word && !stopWords.includes(word))
}
function calculateMatchScore(source, target) {
const sourceSet = new Set(cleanKeywords(source))
const targetSet = new Set(cleanKeywords(target))
let matchCount = 0
for (let word of sourceSet) {
if (targetSet.has(word)) {
matchCount++
}
}
// 匹配度 = source中匹配到的词 / source总词数
return matchCount / sourceSet.size
}
class CsimilarityJobs {
config = {
thresholdVal: 0.69,
titleSimilarityWeight: 0.4,
salaryMatchWeight: 0.2,
areaMatchWeight: 0.2,
educationMatchWeight: 0.2,
experiencenMatchWeight: 0.1
}
userTitle = ['Java', 'C', '全栈工程师'];
userSalaryMin = 10000;
userSalaryMax = 15000;
userArea = 0; // 用户指定的区域(例如:市南区)
userEducation = 4; // 用户学历假设4为本科
userExperience = 2; // 用户工作经验
jobTitle = '';
jobMinSalary = 10000
jobMaxSalary = 15000
jobLocationAreaCode = 0
jobEducation = 4
jobExperience = 2
jobCategory = ''
// 系统
log = false
constructor() {}
setUserInfo(resume) {
this.userTitle = resume.jobTitle
this.userSalaryMax = Number(resume.salaryMax)
this.userSalaryMin = Number(resume.salaryMin)
this.userArea = Number(resume.area)
this.userEducation = resume.education
this.userExperience = this.getUserExperience(Number(resume.age))
}
setJobInfo(jobInfo) {
this.jobTitle = jobInfo.jobTitle;
this.jobMinSalary = jobInfo.minSalary
this.jobMaxSalary = jobInfo.maxSalary
this.jobLocationAreaCode = jobInfo.jobLocationAreaCode
this.jobEducation = jobInfo.education
this.jobExperience = jobInfo.experience
this.jobCategory = jobInfo.jobCategory
}
calculationMatchingDegreeJob(resume) {
// 计算职位标题相似度
// const titleSimilarity = stringSimilarity.compareTwoStrings(this.userTitle, job.jobTitle);
let jobT = null
if (this.jobCategory) {
jobT = this.calculateBestJobCategoryMatch(resume.jobTitle || resume.jobTitleString || [], this
.jobCategory);
} else {
jobT = this.calculateBestJobMatch(resume.jobTitle || resume.jobTitleString || [], this.jobTitle);
}
const {
bestMatchJobTitle,
maxSimilarity
} = jobT
// 计算薪资匹配度
const salaryMatch = this.calculateSalaryMatch(Number(resume.salaryMin), Number(resume.salaryMax),
this
.jobMinSalary, this.jobMaxSalary);
// 计算区域匹配度
const areaMatch = this.calculateAreaMatch(Number(resume.area), this.jobLocationAreaCode);
// 计算学历匹配度
const educationMatch = this.calculateEducationMatch(resume.education, this.jobEducation);
// 计算工作经验匹配度
// const experiencenMatch = this.calculateExperienceMatch2(this.userExperience, job.experience);
// 综合匹配度 = 0.4 * 职位相似度 + 0.2 * 薪资匹配度 + 0.1 * 区域匹配度 + 0.2 * 学历匹配度 + 0.1 * 工作经验匹配度
const overallMatch = this.config.titleSimilarityWeight * maxSimilarity +
this.config.salaryMatchWeight * salaryMatch + this.config.areaMatchWeight * areaMatch +
this.config.educationMatchWeight * educationMatch
// console.log(`Job ${job.jobTitle}工作经验匹配度: ${experiencenMatch}`);
if (this.log) {
console.log(
`Job ${job.jobTitle} 标题相似度 ${maxSimilarity} 薪资匹配度: ${salaryMatch}学历匹配度: ${educationMatch} 区域匹配度: ${areaMatch} 综合匹配度: ${overallMatch.toFixed(2)}`
);
}
// 设置阈值进行岗位匹配判断
const threshold = this.config.thresholdVal;
return {
overallMatch: (overallMatch.toFixed(2) * 100) + '%',
data: resume,
maxSimilarity,
salaryMatch,
educationMatch,
areaMatch
}
}
calculationMatchingDegree(job) {
// 计算职位标题相似度
// console.log(this.userTitle, job.jobTitle)
// const titleSimilarity = stringSimilarity.compareTwoStrings(this.userTitle, job.jobTitle);
let jobT = null
if (job.jobCategory) {
jobT = this.calculateBestJobCategoryMatch(this.userTitle, job.jobCategory);
} else {
jobT = this.calculateBestJobMatch(this.userTitle, job.jobTitle);
}
const {
bestMatchJobTitle,
maxSimilarity
} = jobT
// 计算薪资匹配度
const salaryMatch = this.calculateSalaryMatch(this.userSalaryMin, this.userSalaryMax, job.minSalary,
job
.maxSalary);
// 计算区域匹配度
const areaMatch = this.calculateAreaMatch(this.userArea, job.jobLocationAreaCode);
// 计算学历匹配度
const educationMatch = this.calculateEducationMatch(this.userEducation, job.education);
// 计算工作经验匹配度
// const experiencenMatch = this.calculateExperienceMatch2(this.userExperience, job.experience);
// 综合匹配度 = 0.4 * 职位相似度 + 0.2 * 薪资匹配度 + 0.1 * 区域匹配度 + 0.2 * 学历匹配度 + 0.1 * 工作经验匹配度
const overallMatch = this.config.titleSimilarityWeight * maxSimilarity +
this.config.salaryMatchWeight * salaryMatch + this.config.areaMatchWeight * areaMatch +
this.config.educationMatchWeight * educationMatch
// console.log(`Job ${job.jobTitle}工作经验匹配度: ${experiencenMatch}`);
if (this.log) {
console.log(
`Job ${job.jobTitle} 标题相似度 ${maxSimilarity} 薪资匹配度: ${salaryMatch}学历匹配度: ${educationMatch} 区域匹配度: ${areaMatch} 综合匹配度: ${overallMatch.toFixed(2)}`
);
}
// 设置阈值进行岗位匹配判断
const threshold = this.config.thresholdVal;
if (overallMatch > threshold) {
return {
overallMatch: (overallMatch.toFixed(2) * 100) + '%',
data: job,
maxSimilarity,
salaryMatch,
educationMatch,
areaMatch
}
}
}
// 根据用户年龄推算工作经验年限区间
getUserExperience(age) {
if (age = 0) { // 30以下
return {
min: 0,
max: 5
};
} else if (age <= 1) { // 40以下
return {
min: 5,
max: 10
};
} else if (age <= 2) { // 50以下
return {
min: 10,
max: 20
};
} else { // 50以上
return {
min: 20,
max: 40
};
}
}
// 计算经验匹配度
calculateExperienceMatch2(userExperience, jobExperience) {
const jobExperienceRange = this.mapJobExperience(jobExperience);
if (userExperience.min <= jobExperienceRange.max && userExperience.max >= jobExperienceRange.min) {
return 1;
}
if (
(userExperience.min <= jobExperienceRange.max && userExperience.max > jobExperienceRange.min) ||
(userExperience.max >= jobExperienceRange.min && userExperience.min < jobExperienceRange.max)
) {
return 0.5; // 部分匹配
}
return 0; // 不匹配
}
// 映射岗位经验要求到工作经验年限区间
mapJobExperience(jobExperience) {
const experienceMapping = {
"1": {
min: 0,
max: 0
},
"2": {
min: 0,
max: 1
},
"3": {
min: 0,
max: 1
},
"4": {
min: 1,
max: 3
},
"5": {
min: 3,
max: 5
},
"6": {
min: 5,
max: 10
},
"7": {
min: 10,
max: 20
},
"8": {
min: 0,
max: 40
}
};
return experienceMapping[jobExperience];
}
// 计算工作经验匹配度
calculateExperiencenMatch(userExperience, jobExperience) {
if (userExperience === jobExperience) {
return 1;
} else if (userExperience > jobExperience) {
return 0.75;
} else {
return 0;
}
}
calculateSalaryMatch(userMin, userMax, jobMin, jobMax) {
const isMinMatch = userMin >= jobMin && userMin <= jobMax;
const isMaxMatch = userMax >= jobMin && userMax <= jobMax;
if (isMinMatch || isMaxMatch) {
return 1;
}
const minDifference = Math.abs(userMin - jobMin);
const maxDifference = Math.abs(userMax - jobMax);
if (minDifference > 3000 && maxDifference > 3000) {
return 0;
}
return 0.5; // 部分匹配
}
// 计算区域匹配度
calculateAreaMatch(userArea, jobArea) {
return userArea === jobArea ? 1 : 0.5;
}
calculateBestJobCategoryMatch(userJobTitles, jobTitle) {
let maxSimilarity = 0;
let bestMatchJobTitle = '';
for (let i = 0; i < userJobTitles.length; i++) {
let userTitle = userJobTitles[i];
if (userTitle === jobTitle) {
maxSimilarity = 1;
bestMatchJobTitle = userTitle;
break
}
}
return {
bestMatchJobTitle,
maxSimilarity
};
}
// 计算职位匹配度
calculateBestJobMatch(userJobTitles, jobTitle) {
let maxSimilarity = 0;
let bestMatchJobTitle = '';
userJobTitles.forEach((userTitle) => {
const userSegments = segmentText(userTitle);
const jobSegments = segmentText(jobTitle);
// 比较分词的交集,计算匹配度
// const intersection = userSegments.filter(segment => jobSegments.includes(segment));
// const similarity = intersection.length / userSegments.length; // 计算匹配度
// 计算匹配度
const similarity = calculateMatchScore(userSegments, jobSegments)
// 记录匹配度最高的职位
if (similarity > maxSimilarity) {
maxSimilarity = similarity;
bestMatchJobTitle = userTitle;
}
});
return {
bestMatchJobTitle,
maxSimilarity
};
}
// 计算学历匹配度
calculateEducationMatch(userEducation, jobEducation) {
if (userEducation === jobEducation) {
return 1;
} else if (userEducation > jobEducation) {
return 1;
} else {
return 0;
}
}
}
const similarityJobs = new CsimilarityJobs()
export default similarityJobs