删除数据清洗相关代码

This commit is contained in:
zk
2026-06-02 17:08:47 +08:00
parent b9d8c2724a
commit e0cb4493e3
12 changed files with 5 additions and 1300 deletions
-202
View File
@@ -1,202 +0,0 @@
---
inclusion: manual
---
# 数据清洗方案
## 总体架构
```
爬虫(公司网络) → app_job_data(原始数据)
Java定时任务读取(多线程)
三次AI调用:结构化 → 专业匹配 → 技能提取
写入业务表(bg_company + bg_job + 关联表 + bg_skill_tag)
公司信息不完整的 → 调AI补充
```
所有清洗逻辑放在 `manager` 模块,通过 `@Scheduled` 定时任务触发。
---
## 一、岗位清洗触发逻辑
### 1.1 状态管理
`app_job_data.clean_status`
- 0=待清洗:新爬到的数据,默认值
- 1=清洗中:定时任务已锁定,正在处理
- 2=已入库:清洗成功,已写入 bg_job
- 3=已丢弃:AI判定为无效数据
### 1.2 两个定时任务
#### 任务A:岗位清洗(每5分钟)
1. 事务内 `SELECT FOR UPDATE` + `UPDATE clean_status=1` 批量锁定
2. 丢入线程池,多线程并发处理
3. 每条独立更新状态
#### 任务B:僵尸恢复(每30分钟)
将超时10分钟仍在清洗中的数据重置为待清洗。
---
## 二、岗位清洗逻辑(三次AI调用)
### 2.1 前置校验
- `description` 为空或长度 < 20 → 标记丢弃,跳过
### 2.2 参考数据缓存(DictCacheService
启动时加载:
- `bg_job_category` 叶子节点(level=3),格式 `id:name(一级/二级)`
- `bg_industry` 叶子节点(level=2),格式 `id:name(一级)`
- `bg_major_category` 叶子节点(level=3),格式 `id:name(一级/二级)`
- `bg_china_regions_code` 省市级,供城市名匹配
### 2.3 第一次AI:提取岗位结构化信息
#### 输入
- 原始字段:job_title、salary、location、company、experience、education、description
- 参考列表:岗位分类、行业
#### 返回JSON
```json
{
"valid": true,
"title": "Java高级开发工程师",
"salary": "15-25K",
"education": 2,
"minExperience": 3,
"employmentType": 0,
"categoryId": 12,
"requiredIndustryId": 5,
"description": "岗位职责...",
"requirement": "任职要求...",
"bonus": "加分项...",
"tags": ["数据分析", "产品策略"],
"skillTags": ["Java", "Spring Boot"],
"companyShortName": "字节跳动",
"cities": ["北京", "上海"]
}
```
#### Java处理流程
1. valid=false → 丢弃
2. source_id 去重检查
3. 公司处理(查或创建 bg_company
4. 地区匹配(cities → region_code
5. 写入 bg_job + bg_job_region_relation + 更新 clean_status=2
### 2.4 第二次AI:专业匹配
岗位入库后,单独调用AI匹配专业要求。
#### 输入
- 岗位标题、职责、要求
- 三级专业分类列表(845条,格式 `id:name(一级/二级)`
#### 返回JSON
```json
{
"requiredMajorIds": [101, 203],
"majorSensitivity": 1
}
```
#### 规则
- requiredMajorIds:从专业列表中选最相关的,最多3个,无明确要求则空数组
- majorSensitivity0=不限 1=优先 2=强制
- majorSensitivity=0 时,requiredMajorIds 应为空数组
- 结果更新到 bg_job 的 required_major_ids 和 major_sensitivity 字段
### 2.5 第三次AI:技能提取
自由提取岗位核心技能,不再依赖预定义标签库。
#### 输入
- 岗位标题、职责、要求
#### 返回JSON
```json
["java", "spring boot", "mysql", "redis"]
```
#### prompt 规则
- 统一小写字母
- 尽量简短,使用业界通用缩写
- 提取范围:技术栈、专业领域知识、行业工具、专业资质能力
- 不提取纯软技能(沟通、协作、学习能力等)
- 无专业能力要求的岗位(销售、行政等)返回空数组
- 最多15个
#### 技能入库流程
1. 遍历AI返回的技能名,统一转小写
2. `INSERT IGNORE INTO bg_skill_tag`(依靠 name 唯一索引去重,ID 由 IdWorker 生成)
3. `SELECT id FROM bg_skill_tag WHERE name=?` 拿到ID
4. 写入 bg_job_skill_tag_relation
#### 并发安全
依靠数据库唯一索引保证,不加应用层锁。多线程同时插入相同技能名时,INSERT IGNORE 自动忽略重复。
### 2.6 容错设计
- 第二次、第三次AI调用失败不影响岗位入库
- 每次调用独立 try-catch,仅日志记录
---
## 三、公司数据触发逻辑
### 3.1 状态
`bg_company.status`:0=待完善 1=已完善 2=禁用 3=补充中 4=补充失败
### 3.2 定时任务
- 任务C:公司补充(每小时),SELECT FOR UPDATE 锁定 status=0 的数据
- 任务D:僵尸恢复(每小时,与C错开),重置超时10分钟的 status=3 数据
---
## 四、公司数据补充逻辑(AI补充)
### 4.1 流程
1. 拿 short_name 调AI
2. prompt 附带行业列表,AI直接返回 industryId
3. valid=false → status=4(补充失败)
4. regionCodeAI返回城市名,Java侧匹配
5. 回填 bg_company 各字段,status=1
### 4.2 AI返回JSON
```json
{
"valid": true,
"name": "北京字节跳动科技有限公司",
"city": "北京",
"companyType": "独角兽",
"industryId": 5,
"tags": ["短视频", "人工智能"],
"summary": "全球领先的内容平台和科技公司",
"description": "字节跳动成立于2012年...",
"foundedYear": "2012",
"address": "北京市海淀区...",
"scale": "10000人以上",
"website": "https://www.bytedance.com",
"financingStage": "已上市",
"latestValuation": "2200亿美元",
"news": ["新闻1", "新闻2", "新闻3"]
}
```
---
## 五、关键设计决策
| 决策点 | 结论 | 原因 |
|--------|------|------|
| 技能标签来源 | AI自由提取,自动入库 bg_skill_tag | 去掉预定义标签限制,覆盖面更广 |
| 技能并发去重 | INSERT IGNORE + 唯一索引 | 不加应用层锁,性能好 |
| 专业匹配 | 单独一次AI调用 | 专业列表845条,和第一次prompt合并会超token |
| AI调用次数 | 三次(结构化 + 专业 + 技能) | 各维度独立,容错互不影响 |
| 公司数据来源 | AI补充,不用工商API | 公司简称查API不精确,AI覆盖率高 |