添加公司信息处理逻辑
This commit is contained in:
+99
-44
@@ -26,7 +26,7 @@ inclusion: manual
|
||||
1. ✅ 岗位清洗触发逻辑
|
||||
2. ✅ 岗位清洗逻辑
|
||||
3. ✅ 公司数据触发逻辑
|
||||
4. ⬜ 公司数据补充逻辑(待定API后补充)
|
||||
4. ✅ 公司数据补充逻辑(AI补充)
|
||||
|
||||
---
|
||||
|
||||
@@ -53,7 +53,7 @@ CREATE INDEX idx_clean_status ON app_job_data (clean_status);
|
||||
|
||||
#### 任务A:岗位清洗任务(高频,每5分钟)
|
||||
|
||||
1. 批量锁定:`UPDATE app_job_data SET clean_status=1 WHERE clean_status=0 AND is_valid=1 LIMIT N`(原子操作,防止多线程重复捞取)
|
||||
1. 批量锁定(事务内 `SELECT ... FOR UPDATE` + `UPDATE`):先在事务内对 `clean_status=0 AND is_valid=1` 的行加行锁并查出数据,再更新 `clean_status=1`,事务提交后释放锁。行锁保证并发安全,其他线程会阻塞直到事务提交
|
||||
2. 将锁定的数据丢入线程池,多线程并发调用 AI API 清洗
|
||||
3. 每条处理完毕后,单独更新 `clean_status` 为 2(已入库)或 3(已丢弃)
|
||||
4. 单条写入事务:bg_job 入库 + clean_status 更新放在同一个短事务中,保证一致性
|
||||
@@ -221,25 +221,29 @@ CREATE TABLE bg_job_skill_tag_relation (
|
||||
|
||||
### 3.1 状态扩展
|
||||
|
||||
`bg_company.status` 扩展为4个值:
|
||||
`bg_company.status` 扩展为5个值:
|
||||
- 0=待完善:岗位清洗时自动创建的公司,只有 short_name
|
||||
- 1=已完善:工商API补充完成
|
||||
- 1=已完善:AI补充完成
|
||||
- 2=禁用:人工标记禁用
|
||||
- 3=补充中:定时任务已锁定,正在调用工商API
|
||||
- 3=补充中:定时任务已锁定,正在调用AI
|
||||
- 4=补充失败:AI明确不认识该公司,不再自动重试
|
||||
|
||||
### 3.2 两个定时任务(与岗位清洗同一套模式)
|
||||
|
||||
#### 任务C:公司数据补充任务(低频,每小时)
|
||||
|
||||
1. 批量锁定(原子操作):
|
||||
1. 批量锁定(事务内 `SELECT ... FOR UPDATE` + `UPDATE`):
|
||||
```sql
|
||||
UPDATE bg_company SET status=3, update_time=NOW() WHERE status=0 LIMIT N
|
||||
-- 事务内执行,行锁保证并发安全
|
||||
SELECT * FROM bg_company WHERE status=0 LIMIT N FOR UPDATE;
|
||||
UPDATE bg_company SET status=3, update_time=NOW() WHERE id IN (...);
|
||||
```
|
||||
⚠️ 锁定时必须同时更新 `update_time`,因为 `bg_company` 的 `update_time` 不像 `app_job_data.updated_at` 那样由数据库自动维护,需要 Java 侧手动设值。如果不更新,后续僵尸恢复任务无法正确判断超时。
|
||||
|
||||
2. 将锁定的数据丢入线程池,多线程并发调用工商API
|
||||
2. 将锁定的数据丢入线程池,多线程并发调用AI补充
|
||||
3. 每条处理完毕后,回填公司信息,更新 `status=1`(已完善)
|
||||
4. 工商API查不到或返回异常 → 保持 `status=3`,由僵尸恢复任务重置
|
||||
4. AI明确不认识该公司(valid=false)→ 更新 `status=4`(补充失败)
|
||||
5. AI调用异常或解析失败 → 保持 `status=3`,由僵尸恢复任务重置
|
||||
|
||||
#### 任务D:公司僵尸恢复任务(低频,每小时,与任务C错开)
|
||||
|
||||
@@ -257,7 +261,7 @@ UPDATE bg_company SET status=0 WHERE status=3 AND update_time < NOW() - INTERVAL
|
||||
|--------|----------|----------|
|
||||
| 状态字段 | app_job_data.clean_status | bg_company.status |
|
||||
| 锁定值 | 1=清洗中 | 3=补充中 |
|
||||
| 完成值 | 2=已入库 / 3=已丢弃 | 1=已完善 |
|
||||
| 完成值 | 2=已入库 / 3=已丢弃 | 1=已完善 / 4=补充失败 |
|
||||
| 时间字段 | updated_at(数据库自动) | update_time(Java手动设值) |
|
||||
| 锁定时是否需手动更新时间 | 不需要 | **需要**,否则僵尸恢复无法判断超时 |
|
||||
| 触发频率 | 每5分钟 | 每小时 |
|
||||
@@ -267,47 +271,98 @@ UPDATE bg_company SET status=0 WHERE status=3 AND update_time < NOW() - INTERVAL
|
||||
|
||||
| 决策点 | 结论 | 原因 |
|
||||
|--------|------|------|
|
||||
| 是否与岗位清洗同步触发 | 否,独立定时任务 | 外部API不同,频率不同,失败场景不同 |
|
||||
| 触发模式 | 复用岗位清洗的"原子锁定+僵尸恢复"模式 | 统一架构,代码可复用 |
|
||||
| 是否与岗位清洗同步触发 | 否,独立定时任务 | AI调用场景不同,频率不同 |
|
||||
| 触发模式 | 复用岗位清洗的"SELECT FOR UPDATE + 僵尸恢复"模式 | 统一架构,行锁保证并发安全 |
|
||||
| 锁定时是否更新时间 | 是 | bg_company.update_time 非数据库自动维护,不更新则僵尸恢复失效 |
|
||||
| 补充频率 | 每小时 | 公司数据量少,工商API可能有频率限制 |
|
||||
| 补充频率 | 每小时 | 公司数据量少,AI调用成本可控 |
|
||||
|
||||
---
|
||||
|
||||
## 四、公司数据补充逻辑(待定API后补充)
|
||||
## 四、公司数据补充逻辑(AI补充)
|
||||
|
||||
### 4.1 补充流程概要
|
||||
### 4.1 方案说明
|
||||
|
||||
1. 用 `short_name`(公司简称)调用工商API搜索
|
||||
2. API返回匹配的企业列表,取最匹配的一条
|
||||
3. 回填 `bg_company` 各字段,更新 `status=1`
|
||||
原计划使用工商API(天眼查等)查询公司信息,但考虑到:
|
||||
- 公司简称不能很好地查询到精确数据
|
||||
- 用AI生成完整企业名字再查API,准确性也无法保证
|
||||
- 我们的公司数据来源于招聘平台,基本都是有一定规模的企业,AI训练数据覆盖率高
|
||||
|
||||
### 4.2 需要回填的字段
|
||||
因此改为直接使用AI补充公司数据,一次调用返回全部字段。
|
||||
|
||||
| bg_company 字段 | 来源 | 说明 |
|
||||
|-----------------|------|------|
|
||||
| name | 工商API | 公司全称 |
|
||||
| logoUrl | 待定 | 工商API可能不提供,需另外来源 |
|
||||
| regionCode | 工商API(注册地址) | 匹配 bg_china_regions_code |
|
||||
| companyType | 工商API | 上市企业、独角兽、国企等 |
|
||||
| industryId | 工商API(行业分类) | 匹配 bg_industry |
|
||||
| tags | 工商API / AI | 公司标签,JSON数组 |
|
||||
| summary | 工商API / AI | 公司简要介绍 |
|
||||
| description | 工商API | 公司详细描述 |
|
||||
| foundedYear | 工商API | 成立时间 |
|
||||
| address | 工商API | 注册地址 |
|
||||
| scale | 工商API | 企业规模(人数) |
|
||||
| website | 工商API | 官网地址 |
|
||||
| financingStage | 工商API / 其他来源 | 融资状态 |
|
||||
| latestValuation | 工商API / 其他来源 | 最新估值 |
|
||||
| news | 新闻API(待定) | 新闻动态,JSON数组 |
|
||||
### 4.2 补充流程
|
||||
|
||||
### 4.3 待定事项
|
||||
1. 拿 `short_name`(公司简称),拼 prompt 调 AI
|
||||
2. prompt 中附带行业列表(`DictCacheService.getIndustryText()`),让 AI 直接返回 `industryId`
|
||||
3. AI 返回结构化 JSON,包含 `valid` 字段判断是否认识该公司
|
||||
4. `valid=false` → 更新 `status=4`(补充失败),结束
|
||||
5. `regionCode`:AI 返回城市名,Java 侧 `DictCacheService.matchRegionCode` 匹配
|
||||
6. 解析 JSON,回填 `bg_company` 各字段
|
||||
7. 更新 `status=1`(已完善)
|
||||
|
||||
- [ ] 选定工商信息API(天眼查、企查查、爱企查等)
|
||||
- [ ] 确认API返回字段与 bg_company 的映射关系
|
||||
- [ ] 新闻动态数据来源(工商API是否包含,还是需要单独的新闻API)
|
||||
- [ ] logoUrl 来源(工商API是否提供)
|
||||
- [ ] 匹配到多条结果时的处理策略
|
||||
- [ ] 查不到结果时的处理策略(保持待完善 or 标记为其他状态)
|
||||
- [ ] API调用频率限制和成本评估
|
||||
### 4.3 AI 返回 JSON 结构
|
||||
|
||||
```json
|
||||
{
|
||||
"valid": true,
|
||||
"name": "北京字节跳动科技有限公司",
|
||||
"city": "北京",
|
||||
"companyType": "独角兽",
|
||||
"industryId": 5,
|
||||
"tags": ["短视频", "人工智能", "社交平台"],
|
||||
"summary": "全球领先的内容平台和科技公司,旗下拥有抖音、今日头条等产品",
|
||||
"description": "字节跳动成立于2012年,是一家以技术驱动的全球化互联网公司...",
|
||||
"foundedYear": "2012",
|
||||
"address": "北京市海淀区北三环西路27号",
|
||||
"scale": "10000人以上",
|
||||
"website": "https://www.bytedance.com",
|
||||
"financingStage": "已上市",
|
||||
"latestValuation": "2200亿美元",
|
||||
"news": [
|
||||
"字节跳动2024年营收突破1200亿美元创历史新高",
|
||||
"TikTok全球月活用户突破15亿大关",
|
||||
"字节跳动加大AI大模型研发投入布局人工智能赛道"
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 4.4 各字段补充规则
|
||||
|
||||
| bg_company 字段 | AI返回字段 | 规则 |
|
||||
|-----------------|-----------|------|
|
||||
| name | name | 公司全称,AI不确定则null |
|
||||
| logoUrl | — | AI无法提供,留空 |
|
||||
| regionCode | city | AI返回城市名,Java侧matchRegionCode匹配 |
|
||||
| companyType | companyType | 上市企业、独角兽、国企、民营企业、外资企业等 |
|
||||
| industryId | industryId | 从行业列表中选,不确定则null |
|
||||
| tags | tags | 公司标签,JSON数组,最多5个 |
|
||||
| summary | summary | 一句话简介,100字以内 |
|
||||
| description | description | 公司详细描述,500字以内 |
|
||||
| foundedYear | foundedYear | 成立年份,如"2012" |
|
||||
| address | address | 注册/总部地址 |
|
||||
| scale | scale | 企业规模,如"1000-5000人"、"10000人以上" |
|
||||
| website | website | 官网地址 |
|
||||
| financingStage | financingStage | 融资状态,如"A轮"、"已上市"、"不需要融资" |
|
||||
| latestValuation | latestValuation | 最新估值,AI知道就给,不知道null |
|
||||
| news | news | 3条相关新闻,每条50字以内,JSON数组 |
|
||||
|
||||
### 4.5 prompt 规则
|
||||
|
||||
- AI 不认识该公司 → `valid=false`,其他字段不需要返回
|
||||
- 不确定的字段返回 null,不要编造
|
||||
- `industryId` 必须从给定行业列表中选择
|
||||
- `news` 最多3条,每条50字以内,基于AI知识库中最新的信息
|
||||
- `tags` 最多5个,体现公司核心业务特征
|
||||
- 字符串值中不允许出现Tab、换行等控制字符
|
||||
- 只返回JSON,不要其他内容
|
||||
|
||||
### 4.6 设计决策记录
|
||||
|
||||
| 决策点 | 结论 | 原因 |
|
||||
|--------|------|------|
|
||||
| 数据来源 | AI补充,不用工商API | 公司简称查API不精确,AI对招聘平台企业覆盖率高 |
|
||||
| AI不认识的公司 | status=4(补充失败),不再自动重试 | 避免无限重试浪费AI调用 |
|
||||
| logoUrl | 留空 | AI无法提供图片URL |
|
||||
| news 时效性 | 不要求实时,取AI知识库内最新的3条 | 求职场景不需要实时新闻 |
|
||||
| latestValuation | AI知道就给,不知道null | 大部分招聘企业AI有数据 |
|
||||
| regionCode 匹配方式 | AI返回城市名,Java侧匹配 | 复用已有的matchRegionCode逻辑 |
|
||||
| industryId 匹配方式 | prompt带行业列表,AI直接返回ID | 复用已有的行业列表文本 |
|
||||
|
||||
@@ -100,7 +100,7 @@ offerpie/back-end
|
||||
│ │ ├─ UserJobDislike.java # 用户不感兴趣记录表(bg_user_job_dislike)
|
||||
│ │ └─ AppJobData.java # 爬虫岗位原始数据表(app_job_data)
|
||||
│ └─ vo/ # ViewObject(OssUrlVo 等)
|
||||
└─ service/ # 业务 Service(OssService、SmsService、DictCacheService、JobCleanService、JobCleanTransactionService 等)
|
||||
└─ service/ # 业务 Service(OssService、SmsService、DictCacheService、JobCleanService、JobCleanTransactionService、CompanyCleanService、CompanyCleanTransactionService 等)
|
||||
```
|
||||
> **设计理念** – 业务实体和 Mapper 位于 `manager`,B 端和 C 端共享;C 端特有的注解、切面、权限服务、路由菜单服务位于 `client-api`,避免 B 端误用;`common` 提供统一的技术支撑。
|
||||
|
||||
|
||||
Reference in New Issue
Block a user