织梦arclist如何过滤重复文章

arclist 去重 SQL优化

重复文章是怎么产生的

织梦 {dede:arclist} 在多栏目调用、推荐位调用、tag 聚合时,经常会出现同一篇文章被多次列出。常见原因:

方案一:用 idlist 排除已展示的文章

第一个 arclist 调出文章后,把它们的 ID 收集起来,传给下一个 arclist 的 idlist 参数做反向排除:

<!-- 第一块:调用最新5条 -->
{dede:arclist row='5' orderby='pubdate'}
  [field:id runphp='yes']
    global $exclude_ids;
    $exclude_ids[]=@me;
  [/field:id]
  <li>[field:title/]</li>
{/dede:arclist}

<!-- 第二块:调用其他,排除已显示的 -->
{dede:arclist row='5' orderby='pubdate' idlist=''}
  [field:id runphp='yes']
    global $exclude_ids;
    if(in_array(@me, $exclude_ids)){@me='';}else{@me='显示';}
  [/field:id]
{/dede:arclist}

这个写法依赖 runphp,对服务器性能有少量影响。

方案二:用 flag 互斥

把首页「头条」文章标记为 h,「推荐」标记为 c,调用时分别取,避免重复:

{dede:arclist flag='h' row='1'}...{/dede:arclist}
{dede:arclist flag='c' row='5'noflag='h'}...{/dede:arclist}

noflag='h' 表示排除带头条属性的文章。

方案三:SQL层面 DISTINCT 去重

使用 {dede:sql} 直接写 SQL,GROUP BY 文章 ID:

{dede:sql sql="SELECT DISTINCT arc.id,arc.title,arc.pubdate
  FROM dede_archives arc
  LEFT JOIN dede_arctype t ON arc.typeid=t.id
  WHERE arc.arcrank>-1
  AND (arc.typeid IN (1,2,3) OR FIND_IN_SET(arc.typeid, t.typeid))
  GROUP BY arc.id
  ORDER BY arc.pubdate DESC
  LIMIT 10"}
  <li><a href="/view.php?aid=[field:id/]">[field:title/]</a></li>
{/dede:sql}

方案四:自定义函数过滤

include/extend.func.php 加一个全局去重函数:

$GLOBALS['shown_ids']=array();

function FilterDuplicated($id){
    if(in_array($id, $GLOBALS['shown_ids'])){
        return false;  // 已显示过
    }
    $GLOBALS['shown_ids'][]=$id;
    return true;
}

模板里:

{dede:arclist row='10' orderby='pubdate'}
  [field:id runphp='yes']
    if(!FilterDuplicated(@me)){ @me='HIDE'; } else { @me=''; }
  [/field:id]
  [field:array runphp='yes']
    if(@me['id']==='HIDE'){ @me=''; }else{
      @me="<li><a href='{@me['arcurl']}'>{@me['title']}</a></li>";
    }
  [/field:array]
{/dede:arclist}
注意:runphp 方案在数据量大时性能下降明显,建议每页 arclist 数量不超过 30 条,并配合静态缓存。

方案五:从源头治理——禁止一稿多投

采集或后台发布时,统一用一个主栏目,需要联动展示通过 arclist 的 typeid='1,2,3' 多栏目调用即可,不要真把同一篇文章复制到多个栏目。这是最根本的去重方法。

查库排查重复

定期用以下 SQL 检查是否有重复标题的文章:

SELECT title, COUNT(*) AS cnt
FROM `dede_archives`
GROUP BY title
HAVING cnt > 1
ORDER BY cnt DESC;

发现后通过后台「文档维护」批量删除或合并。

行动建议

先跑一遍上面的排查 SQL,看看站点里是否真的存在重复文档;如果数量不少,先做源头治理;模板层面的去重则用 noflagidlist 方案更轻量。把每个首页推荐位都规划清楚用途(头条、最新、热门、推荐),互不重叠,自然就没有重复问题了。SEO 上一稿多 URL 是大忌,趁早治理对收录质量有明显帮助。