Files
ks-app-employment-service/utils/similarity_Job.js
史典卓 0216f6053a flat:AI+
2025-03-28 15:19:42 +08:00

347 lines
12 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// 使用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