You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在Laravel中实现多表优先级排序搜索?

Laravel 多表优先级搜索实现方案

针对你需要的多表优先级搜索需求,这里给出一套落地的实现步骤和代码示例:

一、预处理查询词:移除停用词

首先要把查询里的无效停用词过滤掉,比如示例里的“什么是”:

/**
 * 过滤查询中的停用词和标点
 * @param string $query 原始查询语句
 * @return string 清理后的查询词
 */
function filterStopWords(string $query): string
{
    // 可根据业务扩展停用词库
    $stopWords = ['什么是', '什么', '是', '的', '了', '呢'];
    // 移除问号等标点
    $query = preg_replace('/[?!。]/', '', $query);
    // 替换停用词并去重空格
    return trim(preg_replace('/\s+/', ' ', str_replace($stopWords, '', $query)));
}

// 使用示例
$originalQuery = "什么是Backend Developer?";
$cleanQuery = filterStopWords($originalQuery); // 输出:Backend Developer

二、拆分关键词与同义词配置

把清理后的查询词拆分成完整短语、单个关键词,同时维护同义词映射(方便匹配子分类或近义词):

$lowerQuery = strtolower($cleanQuery);
// 拆分单个关键词(假设是双词组合,多词可调整拆分逻辑)
[$mainKeyword, $subKeyword] = explode(' ', $lowerQuery);

// 同义词/子分类映射,可存入配置文件或数据库动态维护
$synonymMap = [
    'backend' => ['后端', '服务器端', 'back-end', '后端开发'],
    'developer' => ['开发工程师', '程序员', 'dev', '研发']
];

三、多表优先级查询

分别对user_profile和feeds表构建查询,通过CASE语句给不同匹配规则赋予权重,权重越高排名越靠前。

1. 用户资料表(user_profile)查询

基于skills、interest、education三个字段搜索:

use Illuminate\Support\Facades\DB;

$userProfiles = DB::table('user_profile')
    ->select(
        'id',
        'name',
        'skills',
        'interest',
        'education',
        // 计算权重:完整短语匹配>单个关键词1>单个关键词2>同义词匹配
        DB::raw("
            CASE
                WHEN LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ? THEN 4
                WHEN LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ? THEN 3
                WHEN LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ? THEN 2
                WHEN (LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ? OR LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ?) THEN 1
                ELSE 0
            END AS weight
        "),
        DB::raw("'user_profile' AS source") // 标记来源表
    )
    // 参数绑定避免SQL注入
    ->whereRaw("
        LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ?
        OR LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ?
        OR LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ?
        OR LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ?
        OR LOWER(CONCAT(skills, ' ', interest, ' ', education)) LIKE ?
    ", [
        "%{$lowerQuery}%",
        "%{$mainKeyword}%",
        "%{$subKeyword}%",
        '%' . implode('%', $synonymMap[$mainKeyword]) . '%',
        '%' . implode('%', $synonymMap[$subKeyword]) . '%'
    ])
    ->having('weight', '>', 0) // 只保留有效匹配结果
    ->get();

2. 动态信息流表(feeds)查询

基于title、description字段搜索,逻辑和用户表一致:

$feeds = DB::table('feeds')
    ->select(
        'id',
        'title',
        'description',
        DB::raw("
            CASE
                WHEN LOWER(CONCAT(title, ' ', description)) LIKE ? THEN 4
                WHEN LOWER(CONCAT(title, ' ', description)) LIKE ? THEN 3
                WHEN LOWER(CONCAT(title, ' ', description)) LIKE ? THEN 2
                WHEN (LOWER(CONCAT(title, ' ', description)) LIKE ? OR LOWER(CONCAT(title, ' ', description)) LIKE ?) THEN 1
                ELSE 0
            END AS weight
        "),
        DB::raw("'feeds' AS source")
    )
    ->whereRaw("
        LOWER(CONCAT(title, ' ', description)) LIKE ?
        OR LOWER(CONCAT(title, ' ', description)) LIKE ?
        OR LOWER(CONCAT(title, ' ', description)) LIKE ?
        OR LOWER(CONCAT(title, ' ', description)) LIKE ?
        OR LOWER(CONCAT(title, ' ', description)) LIKE ?
    ", [
        "%{$lowerQuery}%",
        "%{$mainKeyword}%",
        "%{$subKeyword}%",
        '%' . implode('%', $synonymMap[$mainKeyword]) . '%',
        '%' . implode('%', $synonymMap[$subKeyword]) . '%'
    ])
    ->having('weight', '>', 0)
    ->get();

四、合并结果并按优先级排序

把两个表的查询结果合并,按照权重降序排列,权重相同的可以根据更新时间或其他业务字段二次排序:

// 合并两个集合
$combinedResults = $userProfiles->merge($feeds);

// 按权重降序排序,权重相同则按id降序(可替换为updated_at等字段)
$sortedResults = $combinedResults
    ->sortByDesc(function ($item) {
        return [$item->weight, $item->id];
    })
    ->values(); // 重置集合索引

// 返回最终结果
return response()->json($sortedResults);

性能优化建议

  • SQL注入防护:上面的代码已经用参数绑定替代了字符串拼接,务必坚持这种写法,避免注入风险。
  • 全文索引:如果数据量较大,原生LIKE查询效率极低,建议给搜索字段创建MySQL FULLTEXT索引,或者直接使用Elasticsearch等专业搜索引擎。
  • 缓存优化:高频查询的关键词可以缓存结果,减少数据库查询压力。
  • 动态词库:把停用词、同义词库存入数据库或配置文件,方便运营人员动态维护,无需修改代码。

内容的提问来源于stack exchange,提问作者Sonali Temani

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.22 13:09:26