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

7.0 KiB
Raw Blame History

快速匹配实现原理分析

为什么其他机构能"秒级"返回匹配结果?

核心原理:数据库层面快速过滤 + 只计算符合条件的岗位

实现方式对比

当前方案(慢的原因)

1. 接收1万个岗位的完整数据JSON数组
2. 在内存中遍历所有岗位
3. 对每个岗位进行完整匹配计算
4. 排序返回

问题

  • 需要传输1万个岗位的完整数据几十MB
  • 需要计算所有岗位(即使明显不符合)
  • 无法利用数据库索引优化

优化方案(快速实现)

1. 岗位数据存储在数据库中
2. 使用SQL WHERE条件快速过滤
3. 只对通过初步筛选的岗位进行详细计算
4. 排序返回

优势

  • 利用数据库索引,查询速度极快(毫秒级)
  • 大幅减少需要计算的岗位数量从1万降到几百
  • 只传输少量数据

具体实现步骤

第一步:数据库表结构设计

-- 岗位表
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查询

// 根据简历信息,快速过滤岗位
$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. 数据库索引优化

-- 对常用查询字段建立索引
CREATE INDEX idx_education_age ON positions(education_require, age_min, age_max);
CREATE INDEX idx_gender ON positions(gender_require);

2. 数据预处理

// 岗位入库时,解析并存储结构化数据
$position = [
    'position_require' => [
        '学历要求' => '本科及以上',
        '年龄要求' => '18周岁以上、35周岁以下',
        // ...
    ]
];

// 解析并存储到独立字段
$position['education_require'] = '本科';  // 标准化
$position['age_min'] = 18;
$position['age_max'] = 35;

3. 专业匹配优化

-- 方案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. 缓存机制

// 缓存常见简历的匹配结果
$cacheKey = "match:resume:{$resumeId}";
$result = Redis::get($cacheKey);

if (!$result) {
    // 计算并缓存
    $result = calculateMatch($positions, $resume);
    Redis::setex($cacheKey, 3600, $result); // 缓存1小时
}

完整实现流程

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或预计算