为PJBlog添加相关日志显示功能,在我这篇文章之前就已经有很多人研究过了。像在PJBlog官方论坛就有WBC相关日志和静¢脉提供的插件:相关日志插件 FOR PJBLOG 2.7 080110修正。但是仔细研究这两篇文章,去除他们在页面上的表现不同外,其原理基本相似:以文章的tag作为关键字,根据tag来搜索相关日志再根据点击次数、回复次数或者发表、更新的时间来进行排序。这固然正确,也很好,但是却不是我想要的结果,或者说与我的需求不相符。
在开始讲怎么实现“相关日志”功能之前,我们必须先花一点时间来搞搞清楚我们的需求是什么,或者什么才是真正的相关日志功能。
- 相关日志就是一些具有相同关键字的文章,在PJBlog里我们把tag当作文章的关键字(具体请参见简简单单为PJBlog实现动态关键字),之前的两篇文章已经做到这一点了,也相当棒。本文的实现方法也依据tag来实现相关日志功能的;
- 关键是相关日志的排序问题。前面提到的两篇文章在相关日志的排序上都用了点击次数或者评论人数作为排序的依据,但是如果我们仔细想想看,如果有一篇文章的tag是“CSS,Web2.0”,另外还有两篇文章它们的tag分别是“CSS,xhtml”和“CSS,Ajax,Web2.0”,那么它们哪个前面会好呢?肯定是后者,因为他们的内容最相似,拥有两个相同的关键字,而前者只有一个关键字。对于正在浏览你文章的人来说,他们之所以会花几分钟看你文章,那一定是他对文章中的内容感兴趣,那么他可能就会对与本文类似内容的文章感兴趣(这也就是我们为什么把“相关日志”的标题写成“您可能还会对下面的文章感兴趣”了),所以你如果把这样的文章放在最前面他就有可能点击了。
- 还有一种情况就是,我经常写一个系列的文章,它们有1、2、3好几篇日志,因为他们是一个系列的文章,所以他们的关键字会完全相同,这样根据相似度排列“相关日志”后,当你浏览其中一篇的时候,其于的几篇文章就会显示在最前面,便于你连续查看(通过搜索引擎过来的访问者就有可能再点击其它文章)。您可以看这个演示。
好了,我们在明确需求之后就可以定程序了(其实一个程序,需求部分占相当比重):
第一步:我们在/common/文件夹下新建一个relatedArticles.asp文件,并构造下面这样一个方法(具体的解释已经在注释中)
Private Function arrRelBlog(sTag,logid) Dim arrTag,arrTable() '定义数组 Dim i,k,bound1 '定义可用数值变量 Dim strSQL '定义字符串变量 Dim rs '定义对象存储变量 ReDim arrTable(2,0) '将tag代码分组而以不破坏其完事性 sTag = Replace(sTag,"}{","},{") arrTag = Split(sTag,",") '选取具有相同tag的记录,循环 For i=0 To UBound(arrTag) '剔除标记为草稿、隐藏以及正在浏览的记录 strSQL ="Select [log_ID],[log_Title] FROM [blog_Content] Where [log_tag] LIKE '%" & arrTag(i) & "%' AND [log_ID] <> " & logid & " AND [log_IsDraft] = False AND [log_IsShow] = True" Set rs = Conn.Execute(strSQL) Do While Not rs.EOF Dim arrRow '定义一下数组用于存储选取的记录各字段 Dim flag '定义标志值,用来标记记录是否已经选出 Dim m '已经存在的记录在二维数组中的位置 flag = False arrRow = Array(0,rs("log_ID"),rs("log_Title")) bound1 = UBound(arrTable,2) '遍历二维数组,如果存在文章的log_ID已经存在则返回True并退出上层循环,否则返回False For k = 0 To bound1 If arrTable(1,k) = arrRow(1) Then flag = True m = k Exit For Else flag = false End If Next '如果flag为True,计数器加1;否则追加一条新记录 If flag Then arrTable(0,m) = arrTable(0,m) + 1 Else Dim bound,rebound bound = UBound(arrTable,2) rebound = bound + 1 '向二维数组中追加新记录 ReDim Preserve arrTable(2,rebound) arrTable(0,rebound) = arrRow(0) arrTable(1,rebound) = arrRow(1) arrTable(2,rebound) = arrRow(2) End If '回收内存 Set arrRow = Nothing rs.MoveNext Loop Next arrRelBlog = arrTable End Function
上面这段代码的核心思想就是,把tag放入一个一维数组中,然后把这个一维数组中的每一个tag都到数据库中匹配一篇,每取出的一条匹配记录都和一个二维数组去比较,如果文章的ID已经存在那么就把这个文章的出现次数加1,如果文章的ID在二维数组中没有出现过,那么就把这条记录的ID、title和出现次数(0)添加到这个二维数组中。
第二步:对取得的二维数组进行排序。二维数组的排序参考了来自网络上的一篇文章
Private Function sortArr(arr,index) Dim Ub1,Ub2,i,n Dim flag Dim arrU1,arrU2,arrF Dim temp1,temp2 If Not IsArray(arr) Then Exit Function If Not IsNumeric(index) Then index = 0 Ub1 = UBound(arr,1) Ub2 = UBound(arr,2) ReDim arrU2(Ub2), arrU1(Ub2), arrF(Ub1,Ub2) For i = 0 To Ub2 arrU2(i) = arr(index, i) arrU1(i) = i Next flag = True '冒泡排序 Do Until Not flag flag = False For i = 0 To Ub2 If i = Ub2 Then Exit For If arrU2(i) < arrU2(i+1) Then temp1 = arrU2(i+1) : arrU2(i+1) = arrU2(i) : arrU2(i) = temp1 '排序值 temp2 = arrU1(i+1) : arrU1(i+1) = arrU1(i) : arrU1(i) = temp2 '排序索引 flag = True End If Next Loop '根据排序后的序列号重新排序二维数组 For i = 0 To Ub1 For n = 0 To Ub2 arrF(i,n) = arr(i, arrU1(n)) Next Next Erase arr : Erase arrU1 : Erase arrU2 sortArr = arrF Erase arrF End Function
第三步,做一个Public方法供外部调用
Public Function showRelatedArticle(tags,nowId) Dim arr,i,n i = 0 arr = sortArr (arrRelBlog(tags, nowId),0) '如果没有相关文章,不做处理 If UBound(arr,2) = 0 Then Exit Function Response.Write(" <dl> id="""relatedArticles"""</dl> <dt>您可能还会对下面的文章感兴趣:</dt> ") For n = 0 To UBound(arr,2) If i = 10 Then Exit For 'i是显示条日志的数量,可以自己修改 Response.Write(" <dd><a href="""/article.asp?id="">" & arr(2,n) & "</a></dd> ") i = i + 1 Next Response.Write("</dl> ") Erase arr '释放内存 End Function
注意:我们使用了 <dl> <dt> </dt> <dd>标签来显示相关日志,并有一个id:relatedArticles这可以方便我们来为相关日志定制样式。
这样我们的核心程序已经有了,剩下的就是修改article.asp调用showRelatedArticle()方法来显示了。relatedArticle.asp已经打包上传了,可以按照下面的步骤修改:
按相似度排序的“相关日志”功能的添加
1、下载RelatedArticle.asp文件,上传到PJBlog目录下的Common/文件夹下
2、修改article.asp,在头部加入引用
3、找到
Dim id,tKey
在后面添加
Dim tagsArr '输出相关日志时用到
找到
log_ViewArr=log_View.GetRows
在其后添加
tagsArr = log_ViewArr(19,0) '输出相关日志
保存。
4、打开class/cls_article.asp
找到
set getTag=Nothing
在其后添加
showRelatedArticle tagsArr,id
保存
到这里,相关日志的显示功能已经实现了。现在我们要做的添加一点样式,让它在页面中的样子尽可以的好看一点。下面是我的样式,你可以根据自己的皮肤样式来定制。
5、定制样式。我们已经为dl元素添加了relatedArticles的id,这里就可以直接引用它了:
在skin/当前正在使用的皮肤/layout.css中添加:
#relatedArticles{text-align:left; width:94%; line-height:1.5; margin:auto auto 20px; border:1px solid #ccc} #relatedArticles dt{font-weight:bold; line-height:1.5; background-color:#f5f7f7; padding:4px; border-bottom:1px dotted #ccc} #relatedArticles dd a{font-size:14px}
在skin/当前正在使用的皮肤/link.css中添加:
#relatedArticles dd a:link, #relatedArticles dd a:visited {color:#069;} #relatedArticles dd a:hover, #relatedArticles dd a:active {color:#f00;}
保存上传。
至此,我们按照相似度排列的相关日志功能就已经实现了。
就如同前面据说的,每个修改都是根据不同的需求来实现的,你可以在WBC和静¢脉以及本方法中选择一个最适合你的来使用。
不足及有待改进
1、只能显示指定数目的相关日志,可以考虑翻页(个人太倾向这样);
2、所有完全相同tag的日志应该排在最前面,如文章的tag为1、2、3有两篇文章A的tag是1、2、3、4、5和B的tag是 1、2、3那么A和B谁应该排在前面呢?(个人倾向是B,它们有完全相同的tag);
3、其它未知;
补充
1、希望大家在写日志的时候要养成添加tag的习惯,而且tag的数量要适中,tag太少作用就是会很大,比如你给一篇文章只加一个tag:CSS,这很明显太宽泛,你不可能在一篇文章中讲全部CSS知识,你可能讲的是hack知识,也有可能是CSS的选择符等,因此CSS hack或者CSS Selector都可以用来作tag,而且他们更准确;
2、尽量使用已经存在的tag,在添加tag时先看看是否已经存在,例如tag中已经有了Javascript,你再用一个Jscript或者JS的话就会显得有点多余;
3、有些描述性的tag可以不用写,比如“原创”、“体会”、“感想”等,类似这样的词汇可以作为Catagory或者出现在标题和文章正文中;
欢迎大家补充,并提出宝贵意见。
相当棒的东西!!
[回复]
好东东,忍不住赞一赞!
[回复]
确实是好文章,目前升级到PJBlog3后自带了此功能!
不过,对于学习PJ来说还是不错。
[回复]
是吗?自带的功能在哪开启啊,我的是PJBLOG3的,怎么还是没有?
[回复]