You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

PHP PDO查询去重:博客搜索功能重复结果问题

解决博客搜索功能的重复结果问题

这个问题我之前也碰到过,核心原因是你循环执行查询的方式导致的——每一个搜索关键词都会触发一次查询,只要文章匹配当前关键词就会被返回,同一个文章如果匹配多个关键词(比如同时包含Smith和Will),就会在每次循环里都被输出一遍,自然就重复了。

下面给你两种靠谱的解决思路:

思路一:合并查询条件,单次查询获取结果

最高效的方式是把所有搜索关键词的匹配逻辑合并到一条SQL里,不用循环执行多次查询。这样数据库只会返回一次符合任意关键词的结果,天然避免重复。

修改后的代码示例:

else {
    $searchbit = explode(" ", $searchterm);
    // 先处理每个关键词的metaphone值,同时构建SQL的条件部分
    $conditions = [];
    $params = [];
    foreach($searchbit as $index => $value){
        $metaphonebit = metaphone($value);
        $paramKey = ":metaphonebit_$index";
        // 每个关键词匹配三个字段的任意一个
        $conditions[] = "(metatext.metatitle LIKE $paramKey OR metatext.metatags LIKE $paramKey OR metatext.metacategory LIKE $paramKey)";
        $params[$paramKey] = "%$metaphonebit%";
    }
    // 把所有条件用OR连接起来
    $conditionStr = implode(" OR ", $conditions);
    
    $sql = "SELECT DISTINCT blogcontent.title, blogcontent.content, blogcontent.blogtimestamp, blogcontent.views, blogcontent.image, blogcontent.author, blogcontent.tdate, blogcontent.category, blogcontent.tags, categories.banner, blogcontent.id, categories.color, metatext.metatitle, categories.name 
            FROM blogcontent 
            JOIN categories ON blogcontent.category = categories.name 
            JOIN metatext ON metatext.metaid = blogcontent.id 
            WHERE $conditionStr";
    
    $query = $con->prepare($sql);
    $query->execute($params);
    $results = $query->fetchAll(PDO::FETCH_OBJ);
    
    if($query->rowCount() > 0) {
        foreach($results as $result){
            echo htmlentities($result->title);
            echo htmlentities($result->category);
        }
    }
}

这里做了几个关键优化:

  • DISTINCT确保数据库返回的结果没有重复(即使同一个文章匹配多个关键词,也只会返回一次)
  • 循环构建条件和参数,避免SQL注入,同时把所有关键词的匹配逻辑合并成一个OR连接的条件
  • 单次查询减少数据库交互,性能更优

思路二:循环查询后去重

如果因为某些原因必须保留循环查询的方式,可以把每次查询的结果先存入数组,用文章ID作为唯一标识去重,最后再统一输出。

修改后的代码示例:

else {
    $searchbit = explode(" ", $searchterm);
    $uniqueResults = []; // 用id作为键存储唯一结果
    
    foreach($searchbit as $value){
        $metaphonebit = metaphone($value);
        $sql = "SELECT blogcontent.title, blogcontent.content, blogcontent.blogtimestamp, blogcontent.views, blogcontent.image, blogcontent.author, blogcontent.tdate, blogcontent.category, blogcontent.tags, categories.banner, blogcontent.id, categories.color, metatext.metatitle, categories.name 
                FROM blogcontent 
                JOIN categories ON blogcontent.category = categories.name 
                JOIN metatext ON metatext.metaid = blogcontent.id 
                WHERE (metatext.metatitle LIKE :metaphonebit OR metatext.metatags LIKE :metaphonebit OR metatext.metacategory LIKE :metaphonebit )";
        
        $query = $con->prepare($sql);
        $query->bindValue(':metaphonebit', '%' . $metaphonebit . '%');
        $query->execute();
        $results = $query->fetchAll(PDO::FETCH_OBJ);
        
        if($query->rowCount() > 0) {
            foreach($results as $result){
                // 用文章id作为键,确保同一个id只存一次
                $uniqueResults[$result->id] = $result;
            }
        }
    }
    
    // 遍历去重后的结果输出
    foreach($uniqueResults as $result){
        echo htmlentities($result->title);
        echo htmlentities($result->category);
    }
}

这个思路的核心是用数组的键唯一性来过滤重复的文章,把每个查询到的结果以id为键存入数组,后续相同id的结果会覆盖之前的,最后输出的时候就是唯一的结果。

推荐优先用第一种思路,因为单次查询的性能比多次循环查询要好很多,尤其是搜索关键词多的时候差异更明显。

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

火山引擎 最新活动