Files
work_dhd_back_end/doc/快速匹配实现原理.md
2026-01-06 11:23:52 +08:00

244 lines
7.0 KiB
Markdown
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.

# 快速匹配实现原理分析
## 为什么其他机构能"秒级"返回匹配结果?
### 核心原理:数据库层面快速过滤 + 只计算符合条件的岗位
## 实现方式对比
### ❌ 当前方案(慢的原因)
```
1. 接收1万个岗位的完整数据JSON数组
2. 在内存中遍历所有岗位
3. 对每个岗位进行完整匹配计算
4. 排序返回
```
**问题**
- 需要传输1万个岗位的完整数据几十MB
- 需要计算所有岗位(即使明显不符合)
- 无法利用数据库索引优化
### ✅ 优化方案(快速实现)
```
1. 岗位数据存储在数据库中
2. 使用SQL WHERE条件快速过滤
3. 只对通过初步筛选的岗位进行详细计算
4. 排序返回
```
**优势**
- 利用数据库索引,查询速度极快(毫秒级)
- 大幅减少需要计算的岗位数量从1万降到几百
- 只传输少量数据
## 具体实现步骤
### 第一步:数据库表结构设计
```sql
-- 岗位表
CREATE TABLE positions (
id INT PRIMARY KEY,
-- 基础信息
position_name VARCHAR(255),
company_name VARCHAR(255),
-- 硬性条件(建立索引)
education_require VARCHAR(50), -- 学历要求:本科、硕士等
degree_require VARCHAR(50), -- 学位要求:学士、硕士等
age_min INT, -- 最小年龄
age_max INT, -- 最大年龄
gender_require VARCHAR(10), -- 性别要求:男、女、不限制
major_require TEXT, -- 专业要求
-- 其他信息
position_require JSON, -- 完整要求JSON格式
created_at TIMESTAMP
);
-- 建立索引
CREATE INDEX idx_education ON positions(education_require);
CREATE INDEX idx_age ON positions(age_min, age_max);
CREATE INDEX idx_gender ON positions(gender_require);
```
### 第二步快速过滤SQL查询
```php
// 根据简历信息,快速过滤岗位
$resume = [
'birth_date' => '1995-03-01', // 计算年龄30岁
'gender' => '男',
'education_level' => '硕士研究生',
'degree' => '硕士',
'major' => '计算机科学与技术'
];
// 计算年龄
$age = calculateAge($resume['birth_date']); // 30岁
// SQL快速过滤利用索引毫秒级响应
$positions = DB::table('positions')
->where(function($query) use ($resume, $age) {
// 学历要求:简历学历 >= 岗位要求
$query->whereIn('education_require', [
'本科', '本科及以上', '硕士', '硕士及以上'
]);
// 年龄要求:在范围内
$query->where('age_min', '<=', $age)
->where('age_max', '>=', $age);
// 性别要求:不限制 或 匹配
$query->where(function($q) use ($resume) {
$q->where('gender_require', '不限制')
->orWhere('gender_require', $resume['gender']);
});
// 专业要求:模糊匹配(或使用专业分类表)
$query->where('major_require', 'like', '%计算机%')
->orWhere('major_require', 'like', '%软件%');
})
->get(); // 可能从1万个筛选到200个
// 只对这200个岗位进行详细匹配计算
foreach ($positions as $position) {
$score = calculateMatchScore($position, $resume);
}
```
### 第三步:性能对比
| 方案 | 需要计算的岗位数 | 计算时间 | 数据库查询时间 |
|------|----------------|---------|---------------|
| **当前方案** | 10,000个 | 10-50秒 | 0秒无数据库 |
| **优化方案** | 200个过滤后 | 0.2-1秒 | 0.01-0.1秒 |
**总时间对比**
- 当前方案10-50秒
- 优化方案0.21-1.1秒(**快50-200倍**
## 关键技术点
### 1. 数据库索引优化
```sql
-- 对常用查询字段建立索引
CREATE INDEX idx_education_age ON positions(education_require, age_min, age_max);
CREATE INDEX idx_gender ON positions(gender_require);
```
### 2. 数据预处理
```php
// 岗位入库时,解析并存储结构化数据
$position = [
'position_require' => [
'学历要求' => '本科及以上',
'年龄要求' => '18周岁以上、35周岁以下',
// ...
]
];
// 解析并存储到独立字段
$position['education_require'] = '本科'; // 标准化
$position['age_min'] = 18;
$position['age_max'] = 35;
```
### 3. 专业匹配优化
```sql
-- 方案A使用专业分类表
CREATE TABLE major_categories (
major_name VARCHAR(100),
category VARCHAR(100),
INDEX idx_category(category)
);
-- 方案B使用全文索引
ALTER TABLE positions ADD FULLTEXT INDEX idx_major(major_require);
```
### 4. 缓存机制
```php
// 缓存常见简历的匹配结果
$cacheKey = "match:resume:{$resumeId}";
$result = Redis::get($cacheKey);
if (!$result) {
// 计算并缓存
$result = calculateMatch($positions, $resume);
Redis::setex($cacheKey, 3600, $result); // 缓存1小时
}
```
## 完整实现流程
```php
public function fastBatchMatch($resume, $page = 1, $pageSize = 20) {
// 1. 解析简历信息
$age = calculateAge($resume['birth_date']);
$education = parseEducation($resume['education']);
// 2. 数据库快速过滤(毫秒级)
$filteredPositions = DB::table('positions')
->where('education_require', '<=', $education['level'])
->where('age_min', '<=', $age)
->where('age_max', '>=', $age)
->where(function($q) use ($resume) {
$q->where('gender_require', '不限制')
->orWhere('gender_require', $resume['gender']);
})
->get(); // 从1万筛选到几百个
// 3. 只计算通过初步筛选的岗位(秒级)
$results = [];
foreach ($filteredPositions as $position) {
$score = $this->calculateMatchScore($position, $resume);
$results[] = [
'position_id' => $position->id,
'match_score' => $score,
'position' => $position
];
}
// 4. 排序+分页
usort($results, fn($a, $b) => $b['match_score'] - $a['match_score']);
$paginated = array_slice($results, ($page - 1) * $pageSize, $pageSize);
return [
'list' => $paginated,
'total' => count($results),
'page' => $page,
'page_size' => $pageSize
];
}
```
## 总结
**其他机构能快速返回的关键**
1.**岗位存储在数据库**不是JSON数组
2.**使用SQL WHERE快速过滤**(利用索引,毫秒级)
3.**只计算通过初步筛选的岗位**从1万降到几百
4.**数据预处理**(结构化存储硬性条件)
5.**索引优化**(对常用查询字段建索引)
**性能提升**
- 数据库过滤1万个 → 200个减少98%
- 计算时间50秒 → 1秒快50倍
- **总响应时间从50秒降到1秒以内**
## 实施建议
1. **如果岗位数据在数据库**直接使用SQL过滤
2. **如果岗位数据是JSON**:考虑导入数据库或建立索引
3. **如果无法改数据库**使用内存索引如Elasticsearch或预计算