候选岗位补核心职责(赛题定义五要素齐备);全岗位补2024-2026Q3近期演化信号并收敛未来窗口;MinHash升至256哈希修复边沿误杀;审核台展示职责/场景

This commit is contained in:
RoyirinRosmontis
2026-08-19 15:33:52 +08:00
parent 73709094c2
commit d2be567668
5 changed files with 165 additions and 46 deletions
+1 -1
View File
@@ -13,7 +13,7 @@ from app.models import JDRecord
logger = logging.getLogger(__name__)
NUM_HASHES = 128 # MinHash 哈希函数个数(>=64,越高估计越稳)
NUM_HASHES = 256 # MinHash 哈希函数个数(越高估计越稳;128 时边沿样本偏差可达 ±0.1 误杀植入簇)
SHINGLE_N = 5 # 字符 5-gram shingles
LSH_BANDS = 16 # 16 bands × 8 rows(严格分带,抑制模板化文本误配)
_PRIME = (1 << 61) - 1 # 梅森素数,用于 (a*x+b) mod p 哈希族
+20 -3
View File
@@ -23,6 +23,7 @@ MIN_COMPANIES = 5 # 独立企业数(防单一企业造词)
MIN_GROWTH = 1.5 # 近期增长率(最近一年 JD 数 / 前一年,≥50% 增长)
MIN_DISTINCTNESS = 0.4 # 与既有岗位差异度:1 - 与最近既有岗位质心的余弦相似度
MERGE_SIM = 0.50 # 凝聚合并的质心余弦相似度阈值
RESP_MIN_RATIO = 0.25 # 候选职责入选阈值:簇内 ≥25%(且 ≥2 条)JD 提及,取频次 Top 5
# ---------- TF-IDF(字符 2/3-gram) ----------
@@ -158,21 +159,37 @@ def discover_new_jobs(
if distinctness < min_distinctness:
logger.info("簇与既有岗位差异度不足(%.2f < %.2f),不列为新岗位", distinctness, min_distinctness)
continue
# 簇内最常见的抽取标题作为候选岗位名;技能取簇内高频
# 簇内最常见的抽取标题作为候选岗位名;技能/职责/场景取簇内高频
titles = Counter(extractions[r.jid].job_title for r in group)
title = titles.most_common(1)[0][0]
req = Counter(s for r in group for s in extractions[r.jid].required_skills)
pref = Counter(s for r in group for s in extractions[r.jid].preferred_skills)
duty = Counter(d for r in group for d in extractions[r.jid].responsibilities)
scen = Counter(s for r in group for s in extractions[r.jid].scenarios)
ind = Counter(r.industry for r in group if r.industry)
n = len(group)
industries = [s for s, _ in ind.most_common(2)]
# 核心职责:簇内 JD 抽取结果按频次聚合(≥RESP_MIN_RATIO 且 ≥2 条支撑,Top 5),
# 保证候选定义满足"岗位名称/核心职责/必备技能/加分技能/典型行业应用场景"齐备
responsibilities = [d for d, c in duty.most_common(5) if c >= max(2, n * RESP_MIN_RATIO)]
required = [s for s, c in req.most_common() if c >= n * 0.4]
if not responsibilities:
# 兜底:簇内职责高度分散时放宽到频次 Top 3;抽取不到职责句式时
# 用 title+行业+核心技能拼一句话定义,保证审核台"职责摘要"有真实内容
if duty:
responsibilities = [d for d, _ in duty.most_common(3)]
else:
focus = "、".join(required[:2]) or title
responsibilities = [
f"面向{'/'.join(industries) or '新兴'}行业,承担{title}相关的{focus}设计、开发与交付工作"]
candidates.append(JobDefinition(
job_id=f"cand_{title}",
title=title,
category="新岗位候选",
industries=[s for s, _ in ind.most_common(2)],
required_skills=[s for s, c in req.most_common() if c >= n * 0.4],
industries=industries,
required_skills=required,
preferred_skills=[s for s, c in pref.most_common() if c >= n * 0.25],
responsibilities=responsibilities,
scenarios=[s for s, _ in scen.most_common(5)],
status="pending",
source_count=n,