圖譜與神經(jīng)網(wǎng)絡(luò)的簡(jiǎn)歷推薦系統(tǒng)畢業(yè)設(shè)計(jì)實(shí)戰(zhàn))
簡(jiǎn)介這份資源是面向高校計(jì)算機(jī)相關(guān)專(zhuān)業(yè)學(xué)生的Python畢業(yè)設(shè)計(jì)完整項(xiàng)目主題為基于知識(shí)圖譜與人工神經(jīng)網(wǎng)絡(luò)的簡(jiǎn)歷推薦系統(tǒng)適合作為畢設(shè)、期末大作業(yè)或課程設(shè)計(jì)的高分參考方案。項(xiàng)目將知識(shí)圖譜構(gòu)建與深度神經(jīng)網(wǎng)絡(luò)模型相結(jié)合實(shí)現(xiàn)簡(jiǎn)歷解析、崗位匹配與智能推薦等核心功能代碼注釋詳盡新手也能快速理解整體邏輯。壓縮包共66個(gè)文件約10.7MB涵蓋19個(gè)Python源碼文件、8個(gè)HTML頁(yè)面、6個(gè)CSS與6個(gè)JavaScript前端資源以及模型權(quán)重、詞向量語(yǔ)料、SQLite數(shù)據(jù)庫(kù)和說(shuō)明文檔等前后端結(jié)構(gòu)完整部署后即可運(yùn)行。目前已有113人學(xué)習(xí)下載。項(xiàng)目經(jīng)過(guò)嚴(yán)格調(diào)試附帶文檔說(shuō)明與數(shù)據(jù)樣本讀者可據(jù)此掌握知識(shí)圖譜構(gòu)建、DNN模型訓(xùn)練、簡(jiǎn)歷文本解析與推薦流程并直接用于畢業(yè)設(shè)計(jì)答辯或二次開(kāi)發(fā)具有較高的實(shí)際應(yīng)用與參考價(jià)值。1. 簡(jiǎn)歷推薦系統(tǒng)為什么值得做成畢業(yè)設(shè)計(jì)從投遞匹配到知識(shí)圖譜的落地價(jià)值招聘平臺(tái)每天沉淀的簡(jiǎn)歷和崗位描述本質(zhì)上是兩堆非結(jié)構(gòu)化文本。求職者抱怨投了 200 份沒(méi)回音HR 抱怨篩了 300 份沒(méi)一個(gè)合適問(wèn)題不在數(shù)量而在匹配環(huán)節(jié)缺少語(yǔ)義理解。一個(gè)只靠關(guān)鍵詞if Python in resume的推薦邏輯會(huì)把熟悉 Python 數(shù)據(jù)分析和用 Python 做過(guò)量化交易策略代碼當(dāng)成同一類(lèi)人也會(huì)把知識(shí)圖譜構(gòu)建經(jīng)驗(yàn)和知識(shí)圖譜標(biāo)注混為一談。這正是基于知識(shí)圖譜與人工神經(jīng)網(wǎng)絡(luò)的簡(jiǎn)歷推薦系統(tǒng)要解決的核心問(wèn)題用圖譜把技能、項(xiàng)目、崗位之間的關(guān)聯(lián)顯式建模再用神經(jīng)網(wǎng)絡(luò)學(xué)習(xí)人崗之間的非線性匹配關(guān)系。這個(gè)題目適合計(jì)算機(jī)、軟件工程、電子信息工程方向的畢業(yè)設(shè)計(jì)因?yàn)樗瑫r(shí)覆蓋了數(shù)據(jù)清洗、圖結(jié)構(gòu)建模、深度學(xué)習(xí)訓(xùn)練和 Web 服務(wù)四個(gè)可展示的模塊答辯時(shí)既有算法深度又有工程完整度。下面按數(shù)據(jù)怎么變成圖 → 神經(jīng)網(wǎng)絡(luò)怎么學(xué) → 系統(tǒng)怎么跑起來(lái) → 哪里會(huì)翻車(chē)的順序把一套可復(fù)現(xiàn)的方案講清楚。2. 從簡(jiǎn)歷文本到知識(shí)圖譜實(shí)體抽取與三元組構(gòu)建的完整鏈路知識(shí)圖譜不是把簡(jiǎn)歷丟進(jìn)數(shù)據(jù)庫(kù)就完事了它的核心是實(shí)體—關(guān)系—實(shí)體的三元組結(jié)構(gòu)。簡(jiǎn)歷里的實(shí)體包括技能Python、知識(shí)圖譜、學(xué)歷本科、碩士、崗位算法工程師、項(xiàng)目經(jīng)歷關(guān)系包括掌握要求屬于參與過(guò)。這一章把從原始簡(jiǎn)歷到可查詢圖譜的每一步拆開(kāi)講。2.1 簡(jiǎn)歷數(shù)據(jù)的結(jié)構(gòu)化清洗與字段對(duì)齊真實(shí)簡(jiǎn)歷格式極其混亂PDF、Word、純文本都有字段命名也不統(tǒng)一。第一步不是上模型而是把非結(jié)構(gòu)化文本壓成統(tǒng)一 schema。常見(jiàn)做法是用pdfplumber抽文本再用正則切分教育經(jīng)歷/項(xiàng)目經(jīng)歷/技能等段落。import re import pdfplumber # 簡(jiǎn)歷段落關(guān)鍵詞用于切分不同區(qū)塊 SECTION_KEYS [教育經(jīng)歷, 項(xiàng)目經(jīng)歷, 技能, 實(shí)習(xí)經(jīng)歷, 自我評(píng)價(jià)] def extract_text(pdf_path): 從 PDF 簡(jiǎn)歷中抽取純文本按行拼接 text with pdfplumber.open(pdf_path) as pdf: for page in pdf.pages: page_text page.extract_text() or text page_text \n return text def split_sections(text): 按關(guān)鍵詞把簡(jiǎn)歷切成字典key 是段落名value 是內(nèi)容 pattern |.join(SECTION_KEYS) parts re.split(f({pattern}), text) sections {} for i in range(1, len(parts) - 1, 2): sections[parts[i]] parts[i 1].strip() return sections if __name__ __main__: raw extract_text(resume_sample.pdf) sec split_sections(raw) print(sec.keys()) # 查看切出了哪些段落這段代碼的邏輯是先用pdfplumber把 PDF 轉(zhuǎn)成文本流再用正則按段落關(guān)鍵詞做切分。參數(shù)上SECTION_KEYS需要根據(jù)你拿到的簡(jiǎn)歷模板調(diào)整中文簡(jiǎn)歷常見(jiàn)的就是這幾個(gè)如果簡(jiǎn)歷是英文的要換成Education/Projects/Skills。切分后每個(gè)段落單獨(dú)處理避免技能詞和項(xiàng)目描述混在一起導(dǎo)致后續(xù)實(shí)體抽取串味。提示清洗階段一定要保留原始文本和清洗后文本的映射關(guān)系后面圖譜出錯(cuò)時(shí)能回溯到是哪份簡(jiǎn)歷的哪個(gè)字段出了問(wèn)題這是排查問(wèn)題的后悔藥。2.2 技能實(shí)體抽取規(guī)則詞典 輕量模型的組合策略技能實(shí)體是圖譜里最關(guān)鍵的節(jié)點(diǎn)。純規(guī)則詞典覆蓋不全純模型又需要標(biāo)注數(shù)據(jù)畢業(yè)設(shè)計(jì)階段最穩(wěn)的組合是詞典打底 模型補(bǔ)漏。先維護(hù)一份技能詞典再用jieba分詞和詞性標(biāo)注把候選詞撈出來(lái)。import jieba.posseg as pseg # 技能詞典實(shí)際項(xiàng)目中會(huì)從崗位 JD 里統(tǒng)計(jì)高頻詞擴(kuò)充 SKILL_DICT {Python, 知識(shí)圖譜, 神經(jīng)網(wǎng)絡(luò), SQL, 機(jī)器學(xué)習(xí), 數(shù)據(jù)分析} def extract_skills(text): 從文本中抽取技能實(shí)體詞典命中優(yōu)先名詞短語(yǔ)作為候選 jieba.load_userdict(list(SKILL_DICT)) # 把技能詞加入分詞詞典 hits, candidates set(), set() for word, flag in pseg.cut(text): if word in SKILL_DICT: hits.add(word) elif flag in (n, nz, eng) and len(word) 1: candidates.add(word) return hits, candidates text 熟悉 Python 和知識(shí)圖譜構(gòu)建參與過(guò)機(jī)器學(xué)習(xí)項(xiàng)目 hits, cands extract_skills(text) print(命中:, hits) # 詞典直接命中的技能 print(候選:, cands) # 需要人工或模型二次確認(rèn)的候選邏輯說(shuō)明jieba.load_userdict把技能詞強(qiáng)制加入分詞詞典保證知識(shí)圖譜不會(huì)被切成知識(shí)和圖譜。命中集合是可信技能候選集合是名詞和英文詞后續(xù)可以用一個(gè)簡(jiǎn)單的分類(lèi)模型或人工規(guī)則過(guò)濾。參數(shù)上flag過(guò)濾條件n/nz/eng覆蓋了普通名詞、專(zhuān)有名詞和英文詞如果你發(fā)現(xiàn)候選里噪音太多可以加長(zhǎng)度閾值或詞頻閾值。2.3 三元組構(gòu)建與 Neo4j 入庫(kù)實(shí)體抽出來(lái)后要變成三元組。簡(jiǎn)歷場(chǎng)景里典型的三元組是(求職者)-[掌握]-(技能)、(崗位)-[要求]-(技能)、(求職者)-[參與]-(項(xiàng)目)。用py2neo寫(xiě)入 Neo4j 是最常見(jiàn)的做法。from py2neo import Graph, Node, Relationship graph Graph(bolt://localhost:7687, auth(neo4j, your_password)) def build_triples(resume_id, skills, job_skills): 構(gòu)建求職者-技能、崗位-技能兩類(lèi)三元組并入庫(kù) person Node(Person, idresume_id) graph.merge(person, Person, id) # merge 避免重復(fù)節(jié)點(diǎn) for s in skills: skill_node Node(Skill, names) graph.merge(skill_node, Skill, name) graph.merge(Relationship(person, 掌握, skill_node)) for s in job_skills: skill_node Node(Skill, names) graph.merge(skill_node, Skill, name) job_node Node(Job, name算法工程師) graph.merge(job_node, Job, name) graph.merge(Relationship(job_node, 要求, skill_node)) build_triples(R001, {Python, 知識(shí)圖譜}, {Python, 神經(jīng)網(wǎng)絡(luò)})這里用merge而不是create是因?yàn)橥患寄軙?huì)被多個(gè)求職者引用merge保證節(jié)點(diǎn)唯一。參數(shù)上auth里的密碼要和 Neo4j 服務(wù)端配置一致Relationship的關(guān)系名用中文在展示時(shí)直觀但如果后續(xù)要用 Cypher 做復(fù)雜查詢建議統(tǒng)一成英文關(guān)系名如MASTER、REQUIRE避免編碼問(wèn)題。圖譜建好后可以用一句 Cypher 驗(yàn)證連通性MATCH (p:Person)-[:掌握]-(s:Skill)-[:要求]-(j:Job) RETURN p.id, s.name, j.name這條查詢返回的是求職者掌握的技能正好被某崗位要求的匹配路徑也是后續(xù)推薦召回的基礎(chǔ)。如果返回為空先檢查技能名是否大小寫(xiě)不一致這是最常見(jiàn)的翻車(chē)點(diǎn)。3. 人工神經(jīng)網(wǎng)絡(luò)怎么做人崗匹配特征工程與模型訓(xùn)練圖譜解決了關(guān)聯(lián)顯式化但匹配強(qiáng)度需要神經(jīng)網(wǎng)絡(luò)來(lái)學(xué)。這一章講清楚輸入特征怎么構(gòu)造、網(wǎng)絡(luò)結(jié)構(gòu)怎么選、訓(xùn)練時(shí)看什么指標(biāo)。3.1 把圖譜特征轉(zhuǎn)成神經(jīng)網(wǎng)絡(luò)輸入向量神經(jīng)網(wǎng)絡(luò)吃的是數(shù)值向量所以要把圖譜里的關(guān)系轉(zhuǎn)成特征。常見(jiàn)做法是構(gòu)造一個(gè)人—崗特征向量維度包括技能重合度、圖譜路徑數(shù)、學(xué)歷匹配、項(xiàng)目相似度。import numpy as np def build_feature_vector(person_skills, job_skills, graph): 構(gòu)造人崗匹配特征向量 person_set, job_set set(person_skills), set(job_skills) # 特征1技能 Jaccard 相似度 jaccard len(person_set job_set) / len(person_set | job_set 1e-6) # 特征2圖譜中兩跳可達(dá)路徑數(shù) query MATCH (p:Person {id:$pid})-[:掌握]-(s:Skill)-[:要求]-(j:Job {name:$jid}) RETURN count(s) AS overlap overlap graph.run(query, pidR001, jid算法工程師).evaluate() # 特征3技能數(shù)量差 diff abs(len(person_set) - len(job_set)) return np.array([jaccard, overlap, diff], dtypenp.float32) vec build_feature_vector([Python, 知識(shí)圖譜], [Python, 神經(jīng)網(wǎng)絡(luò)], graph) print(vec)邏輯說(shuō)明jaccard衡量技能集合的整體重合度overlap是圖譜里實(shí)際存在的匹配路徑數(shù)diff反映技能數(shù)量差距。這三個(gè)特征拼成向量后送入網(wǎng)絡(luò)。參數(shù)上1e-6是防止除零overlap查詢里的$pid、$jid是參數(shù)化查詢避免字符串拼接注入。3.2 用 PyTorch 搭一個(gè)可訓(xùn)練的人崗匹配網(wǎng)絡(luò)網(wǎng)絡(luò)結(jié)構(gòu)不需要太深畢業(yè)設(shè)計(jì)階段一個(gè)三層全連接就夠用重點(diǎn)是能跑通訓(xùn)練和驗(yàn)證流程。import torch import torch.nn as nn class MatchNet(nn.Module): def __init__(self, input_dim3, hidden16): super().__init__() self.net nn.Sequential( nn.Linear(input_dim, hidden), nn.ReLU(), nn.Linear(hidden, hidden), nn.ReLU(), nn.Linear(hidden, 1), nn.Sigmoid() # 輸出 0~1 的匹配概率 ) def forward(self, x): return self.net(x) model MatchNet() optimizer torch.optim.Adam(model.parameters(), lr1e-3) criterion nn.BCELoss() # 二分類(lèi)匹配/不匹配 # 模擬一批訓(xùn)練數(shù)據(jù)特征 標(biāo)簽 X torch.tensor([[0.8, 3, 1], [0.2, 0, 5], [0.6, 2, 2]], dtypetorch.float32) y torch.tensor([[1.0], [0.0], [1.0]], dtypetorch.float32) for epoch in range(200): pred model(X) loss criterion(pred, y) optimizer.zero_grad() loss.backward() optimizer.step() if epoch % 50 0: print(fepoch {epoch}, loss {loss.item():.4f})邏輯說(shuō)明輸入維度 3 對(duì)應(yīng)上一節(jié)的特征向量隱藏層 16 是經(jīng)驗(yàn)值數(shù)據(jù)量小的時(shí)候不要設(shè)太大否則過(guò)擬合。Sigmoid把輸出壓到 0~1 當(dāng)作匹配概率BCELoss是二分類(lèi)標(biāo)準(zhǔn)損失。參數(shù)上lr1e-3是 Adam 的常用起點(diǎn)如果 loss 震蕩就降到1e-4epoch數(shù)量根據(jù)數(shù)據(jù)規(guī)模調(diào)整畢業(yè)設(shè)計(jì)數(shù)據(jù)量通常幾百到幾千條200 輪足夠觀察收斂趨勢(shì)。注意標(biāo)簽數(shù)據(jù)是畢業(yè)設(shè)計(jì)里最容易被忽略的環(huán)節(jié)。如果沒(méi)有真實(shí)投遞反饋可以用技能重合度超過(guò)閾值即視為匹配來(lái)生成弱標(biāo)簽但要在論文里說(shuō)明這是弱監(jiān)督不能宣稱(chēng)是真實(shí)業(yè)務(wù)標(biāo)簽。3.3 訓(xùn)練過(guò)程要看哪些指標(biāo)怎么判斷模型沒(méi)白訓(xùn)只看 loss 下降是不夠的人崗匹配是排序問(wèn)題要看 Top-K 命中率。做法是把測(cè)試集里每個(gè)求職者的崗位按預(yù)測(cè)概率排序看真實(shí)匹配崗位是否落在前 K 個(gè)。def top_k_hit(model, features, labels, k3): 計(jì)算 Top-K 命中率 model.eval() with torch.no_grad(): scores model(features).squeeze() # 按分?jǐn)?shù)降序取前 k 個(gè)索引 topk_idx torch.topk(scores, k).indices hit labels[topk_idx].sum().item() return hit / k hit_rate top_k_hit(model, X, y, k2) print(fTop-2 命中率: {hit_rate:.2f})邏輯說(shuō)明model.eval()關(guān)閉 dropout 等訓(xùn)練態(tài)行為torch.no_grad()省顯存。topk取分?jǐn)?shù)最高的 K 個(gè)統(tǒng)計(jì)其中有多少是真實(shí)匹配。參數(shù)上K 的選擇取決于業(yè)務(wù)場(chǎng)景推薦列表一般看 Top-5 或 Top-10如果命中率低于隨機(jī)水平說(shuō)明特征沒(méi)區(qū)分度要回到第 2 章檢查圖譜質(zhì)量。4. 系統(tǒng)集成與本地跑通從圖譜服務(wù)到推薦接口算法跑通不等于系統(tǒng)能用。這一章把 Neo4j、PyTorch 模型和 Web 接口串起來(lái)給出一套能在本地復(fù)現(xiàn)的最小系統(tǒng)。4.1 環(huán)境依賴(lài)與目錄結(jié)構(gòu)先把依賴(lài)固定下來(lái)避免在我電腦上能跑的玄學(xué)問(wèn)題。建議用虛擬環(huán)境隔離。python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install pdfplumber jieba py2neo torch flask numpy目錄結(jié)構(gòu)建議按職責(zé)分層答辯時(shí)也好講resume_rec/ ├── data/ # 原始簡(jiǎn)歷和清洗后數(shù)據(jù) ├── graph/ # 圖譜構(gòu)建腳本 │ ├── extract.py │ └── build_graph.py ├── model/ # 神經(jīng)網(wǎng)絡(luò)定義與訓(xùn)練 │ ├── net.py │ └── train.py ├── service/ # Flask 接口 │ └── app.py └── requirements.txt4.2 用 Flask 暴露推薦接口接口只做一件事收到求職者 ID返回排序后的崗位列表。from flask import Flask, jsonify, request from py2neo import Graph import torch from model.net import MatchNet app Flask(__name__) graph Graph(bolt://localhost:7687, auth(neo4j, your_password)) model MatchNet() model.load_state_dict(torch.load(model/match_net.pth)) model.eval() app.route(/recommend, methods[GET]) def recommend(): pid request.args.get(pid) # 從圖譜取該求職者的技能 skills graph.run( MATCH (p:Person {id:$pid})-[:掌握]-(s:Skill) RETURN s.name, pidpid ).data() skill_names [s[s.name] for s in skills] # 這里簡(jiǎn)化處理用技能數(shù)量構(gòu)造特征實(shí)際應(yīng)查崗位庫(kù)逐個(gè)打分 feat torch.tensor([[len(skill_names) / 10, len(skill_names), 0]], dtypetorch.float32) score model(feat).item() return jsonify({pid: pid, skills: skill_names, match_score: round(score, 4)}) if __name__ __main__: app.run(host0.0.0.0, port5000)邏輯說(shuō)明接口從圖譜查技能構(gòu)造特征后過(guò)模型得到分?jǐn)?shù)。參數(shù)上host0.0.0.0讓局域網(wǎng)可訪問(wèn)方便答辯演示port5000是 Flask 默認(rèn)端口。實(shí)際系統(tǒng)里應(yīng)該遍歷崗位庫(kù)逐個(gè)打分再排序這里為了最小可運(yùn)行做了簡(jiǎn)化擴(kuò)展時(shí)把崗位查詢放進(jìn)循環(huán)即可。4.3 端到端驗(yàn)證一條命令確認(rèn)系統(tǒng)通了啟動(dòng) Neo4j 和 Flask 后用 curl 驗(yàn)證接口curl http://localhost:5000/recommend?pidR001返回 JSON 里能看到技能列表和匹配分?jǐn)?shù)說(shuō)明圖譜查詢、模型推理、接口響應(yīng)三個(gè)環(huán)節(jié)都通了。如果返回空技能列表先查 Neo4j 里Person節(jié)點(diǎn)的id屬性是否和請(qǐng)求參數(shù)一致如果分?jǐn)?shù)異常檢查模型加載的權(quán)重文件是否和當(dāng)前網(wǎng)絡(luò)結(jié)構(gòu)匹配。5. 避坑與排查簡(jiǎn)歷推薦系統(tǒng)最容易翻車(chē)的 5 個(gè)地方這一章是我踩過(guò)的坑每條按現(xiàn)象 → 原因 → 解決寫(xiě)照著排查能省不少時(shí)間?,F(xiàn)象一圖譜里技能節(jié)點(diǎn)爆炸同一個(gè)技能出現(xiàn)幾十個(gè)重復(fù)節(jié)點(diǎn)。原因是大小寫(xiě)和空格沒(méi)統(tǒng)一PythonpythonPython 被當(dāng)成三個(gè)實(shí)體。解決方式是在入庫(kù)前做標(biāo)準(zhǔn)化統(tǒng)一轉(zhuǎn)小寫(xiě)、去首尾空格、全角轉(zhuǎn)半角再merge入庫(kù)。現(xiàn)象二模型訓(xùn)練 loss 一直不降準(zhǔn)確率跟隨機(jī)猜差不多。原因通常是特征沒(méi)歸一化技能數(shù)量差這個(gè)特征取值范圍是 0~20而 Jaccard 是 0~1量綱差距讓網(wǎng)絡(luò)學(xué)不動(dòng)。解決方式是對(duì)每個(gè)特征做 min-max 歸一化或者用BatchNorm層?,F(xiàn)象三Neo4j 查詢?cè)絹?lái)越慢推薦接口響應(yīng)超過(guò) 3 秒。原因是沒(méi)建索引每次查詢都在全圖掃描。解決方式是對(duì)Person.id、Skill.name、Job.name建唯一約束和索引CREATE CONSTRAINT FOR (p:Person) REQUIRE p.id IS UNIQUE; CREATE INDEX FOR (s:Skill) ON (s.name);現(xiàn)象四簡(jiǎn)歷 PDF 解析出來(lái)全是亂碼或空行。原因是部分 PDF 是掃描件或用了特殊編碼。解決方式是先判斷文本抽取長(zhǎng)度低于閾值就標(biāo)記為需 OCR 處理不要硬塞進(jìn)圖譜污染數(shù)據(jù)?,F(xiàn)象五答辯演示時(shí)接口報(bào)錯(cuò)本地卻正常。原因是 Neo4j 密碼或端口寫(xiě)死在代碼里換環(huán)境就失效。解決方式是把連接信息抽到配置文件或環(huán)境變量演示前用os.getenv讀取并做一次連通性自檢。6. 進(jìn)階技巧用圖譜路徑特征提升推薦可解釋性到這一步系統(tǒng)能跑了但畢業(yè)設(shè)計(jì)想拿高分還得解決一個(gè)痛點(diǎn)神經(jīng)網(wǎng)絡(luò)是黑匣子答辯老師問(wèn)為什么推薦這個(gè)崗位時(shí)不能只說(shuō)模型算出來(lái)的。知識(shí)圖譜的最大優(yōu)勢(shì)就是可解釋性把圖譜路徑作為推薦理由輸出既提升說(shuō)服力又體現(xiàn)圖譜價(jià)值。具體做法是在推薦接口里加一段路徑查詢返回求職者—技能—崗位的匹配鏈路def explain_recommendation(pid, job_name): 返回人崗匹配的可解釋路徑 query MATCH path (p:Person {id:$pid})-[:掌握]-(s:Skill)-[:要求]-(j:Job {name:$jid}) RETURN [node IN nodes(path) | coalesce(node.name, node.id)] AS chain LIMIT 5 result graph.run(query, pidpid, jidjob_name).data() return [r[chain] for r in result] chains explain_recommendation(R001, 算法工程師) print(chains) # 例如 [[R001, Python, 算法工程師], [R001, 知識(shí)圖譜, 算法工程師]]這段 Cypher 返回的是路徑上所有節(jié)點(diǎn)的名稱(chēng)序列前端可以渲染成你因?yàn)檎莆?Python 和知識(shí)圖譜匹配到算法工程師崗位。參數(shù)上LIMIT 5控制返回路徑數(shù)量避免路徑太多刷屏coalesce(node.name, node.id)兼容技能節(jié)點(diǎn)有name、求職者節(jié)點(diǎn)有id的情況。再進(jìn)一步可以把路徑長(zhǎng)度和路徑數(shù)量作為特征回灌到神經(jīng)網(wǎng)絡(luò)讓模型在學(xué)匹配分?jǐn)?shù)的同時(shí)利用圖結(jié)構(gòu)信息。常見(jiàn)做法是統(tǒng)計(jì) 1 跳、2 跳、3 跳路徑的數(shù)量拼成向量追加到第 3 章的特征向量里。這樣模型既有數(shù)值特征又有結(jié)構(gòu)特征Top-K 命中率通常能提升幾個(gè)百分點(diǎn)。路徑長(zhǎng)度含義對(duì)推薦的貢獻(xiàn)1 跳求職者直接掌握技能強(qiáng)信號(hào)直接匹配2 跳求職者技能被崗位要求核心匹配路徑3 跳技能通過(guò)中間技能關(guān)聯(lián)弱信號(hào)用于擴(kuò)展召回驗(yàn)證可解釋性是否有效可以做一個(gè)簡(jiǎn)單對(duì)比隨機(jī)抽 20 個(gè)推薦結(jié)果人工判斷路徑理由是否合理合理率超過(guò) 80% 就說(shuō)明圖譜質(zhì)量過(guò)關(guān)。如果合理率低回到第 2 章檢查實(shí)體抽取的準(zhǔn)確率尤其是技能詞典的覆蓋度。我自己的習(xí)慣是每改一次圖譜構(gòu)建邏輯就重新跑一遍這 20 條抽樣把合理率記在實(shí)驗(yàn)日志里。這個(gè)習(xí)慣幫我抓出過(guò)好幾次技能詞典把熟悉也當(dāng)成技能的低級(jí)錯(cuò)誤。圖譜和神經(jīng)網(wǎng)絡(luò)結(jié)合的系統(tǒng)坑往往不在模型本身而在數(shù)據(jù)進(jìn)入模型之前的那幾步。希望幫到你。本文還有配套的精品資源點(diǎn)擊獲取