2008年7月2日 星期三

依相關度排序 ---- 更有看頭的『相關文章』功能

.

Correlation 前幾天, 成功實作出『Grazr格中格』的『相關文章』功能, 原本還要繼續嚐試 Google Ajax Search API 或 Google Ajax Feed API ...。不過, 最後還是決定回到『json 加 java script』, 再加上『依相關度排序』---- 希望可以就這麼定案 ----。

不過我猜, 說不定還得請大家投票來決定。

.

下面將介紹 :

  • 遺珠的『相關文章』功能
  • 原始版本的『相關文章』功能 -- Abin's Tech Note
  • 依相關度排序---- 讓『相關文章』更有看頭
  • 補充 ----『隨機文章』

另外寫了一個『不用寫程式, 不用改模版的方法』, 要先掛 jQuery, 再依文章所述安裝。目前的設計, 是要單篇文章才會顯示相關文章。對程式不熟的人, 建議使用 相關文章點播台 -- RPS 1.0 beta

有興趣『寫程式/改模版』的人, 再看下文。

.

  • 遺珠的『相關文章』功能

之所以沒使用下面這些, 來呈現『相關文章』, 有幾個原因 :

  • 無法呈現文章的相關性, 也無法處理重複文章
  • Google Ajax Search API 處理的是『關鍵字』, 而非『標籤』
  • 另外兩個某種程度上比較像『標籤文章選台器』, 而不是『相關文章』

.

不過, 還是列出它們的效果, 說不定你用得上。

Grazr-Related

『Grazr格中格』的『相關文章』功能

2008-07-01_140908
Google Ajax Feed API (Meme -- 教學與反省,
.阿欣部落.)

.

Ajax-Search
Google Ajax Search API

.

建議大家先看一下原始版本的『相關文章』做法 (加入相關文章功能, Abin's Tech Note 2007-03-05), 或者是 替Blogger加入相關文章功能(二)(挖哩勒~胡說八道, 2008-06-30)

裡面, 詳細介紹了『相關文章』的做法, 還有程式碼要安裝在模版的什麼地方。

簡單的說, ABIN 的做法如下 :

  • 集合A = 目前文章的標籤 * (每個標籤取出10 篇最新的文章, 並且不包含目前文章)
  • 集合B = 集合A 的 不重複文章
  • 相關文章 = 從 集合B 隨機取出 5 篇文章

.

  • 依相關度排序 ---- 讓『相關文章』更有看頭

再來看看我的做法, 不同之處以紅色標示 :

  • 集合A = 目前文章的標籤 * (每個標籤取出10 篇最新的文章, 並且不包含目前文章), 並記錄目前的文章有幾個標籤 (labelNum)
  • 集合B = 集合A 的 不重複文章, 並順便統計 每篇文章 在 集合A 出現的次數 (relatedStar),
  • 集合C = 將 集合B 依 文章次數 排序
  • 相關文章 = 集合C 依 文章次數, 由多到少列出, 相關度以 relatedStar / labelNum 表示

.

另外, 我還朝減少記憶體 (陣列) 使用量, 和減少迴圈次數的方向改寫, 所以直接就產生 集合B, 而且 集合C 也只是一個『索引』而已。這樣,『理論上』會跑快一點, 只是不知如何測試。

假設你已經安裝完成原始版本的『相關文章』([1][2]), 只要將 </head> 之前的程式碼整個換成我的版本, 就會有『依相關度排序』的效果。

.

其中的 optionRGB, 請改成適合的顏色設定

var optionRGB = [ {P: 100, R :208, G: 0, B: 0}, {P: 50, R: 255, G: 204, B: 0}, {P: 0, R: 0, G: 64, B: 128} ];

P = 百分比, (R, G, B) = 該百分比的顏色設定。如果介於兩個百分比之間, 則會使用中間色。也可以 增加 或 減少 顏色的組別, 但要維持 P (百分比) 由大到小排列, 還有注意語法即可。

P

R

G

B

100

208

0

0

50

255

204

0

0

0

64

128

.

如果不想使用顏色, 則將以下紅色部分刪去, 並注意 myRBG (內含 <span>) 和 </span> 是成對的。

myRBG = spanRGB(myP, optionRGB);
document.write('<h4>' + myRBG);
document.write('相關度 ' + myStars + ' ' + myP + '% 的文章 :</span></h4> <ul>' );

.

如果想用『分數』(例: 3/5 ) 來表示, 可以將灰色部份與前一行替換,

// document.write('相關度 ' + myStars + ' (' + relatedStar[r] + '/' + labelNum + ') 的文章 :</span> </h4> <ul>' );

.

再來是列出的文章總數, 目前是 20 則, 如藍色部分, 可以自行修改

for (var j=0; j<u_IdxNum && j<20 ; j++)

.

尚待努力之處

  • 看能不能再增進執行效率
  • 將程式主體搬到側邊欄, 縮短文章載入的時間, 之後再插入相關文章的結果

.

</head> 之前的程式碼如下 :

<script type='text/javascript'>
//<![CDATA[
<!-- Script functions for Related Posts: RelatedLabels(), RemoveDuplicatedPosts(), contains(), ShowRelatedPosts()-->
var relatedPostsNum = 0;
var labelNum = 0;
var maxStar = 1;
var relatedStar = new Array();
var relatedTitles = new Array();
var relatedUrls = new Array();
var relatedDates = new Array();
var u_Idx = new Array();
var u_IdxNum = 0;

function RelatedLabels(json) {
var regex1=/</g, regex2=/>/g;
var entryURL = "";
labelNum += 1;
for (var i = 0; i < json.feed.entry.length; i++) {
var entry = json.feed.entry[i];
entryURL = "";
for (var j = 0; j < entry.link.length; j++) {
if (entry.link[j].rel == 'alternate') {
entryURL = entry.link[j].href;
break;
}
}
if (entryURL != "") {
for (var j = 0; j <= relatedPostsNum; j++) {
if (relatedUrls[j] == entryURL) {
relatedStar[j]++;
if (relatedStar[j]>maxStar)
maxStar=relatedStar[j];
entryURL = "";
break;
}
}
}
if (entryURL != "") {
relatedPostsNum++;
relatedTitles[relatedPostsNum] = (entry.title.$t.replace(regex1, '&lt;')).replace(regex2, '&gt;');
relatedDates[relatedPostsNum] = entry.published.$t.substr(0,10);
relatedUrls[relatedPostsNum] = entryURL;
relatedStar[relatedPostsNum] = 1;
}
}
}

function SortRelatedPosts(PostUrl) {
for (var j = maxStar; j > 0 ; j--) {
for(var i = 0; i < relatedUrls.length; i++) {
if (relatedStar[i]==j && PostUrl != relatedUrls[i]) {
u_Idx[u_IdxNum] = i;
u_IdxNum++;
}
}
}
}

function spanRGB(myP, PRGB) {
var myR, myG, myB;
for (var i=0; i< PRGB.length; i++) {
if (myP >= PRGB[i].P) {
if (i==0) {
myR = PRGB[i].R;
myG = PRGB[i].G;
myB = PRGB[i].B;
} else {
var P0 = myP - PRGB[i].P;
var P1 = PRGB[i-1].P - myP;
var deltaP = PRGB[i-1].P - PRGB[i].P;
myR = Math.floor( (PRGB[i-1].R*P0 + PRGB[i].R*P1) / deltaP );
myG = Math.floor( (PRGB[i-1].G*P0 + PRGB[i].G*P1) / deltaP );
myB = Math.floor( (PRGB[i-1].B*P0 + PRGB[i].B*P1) / deltaP );
}
return('<span >');
break;
}
}
return('<span>');
}

function ShowRelatedPosts(PostUrl) {

var r = 0;
var i = 0;
var currStar = 0;
var myStars = "";
var myRBG;
var optionRGB = [ {P: 100, R :208, G: 0, B: 0}, {P: 50, R: 255, G: 204, B: 0}, {P: 0, R: 0, G: 64, B: 128} ];

SortRelatedPosts(PostUrl);
if (relatedTitles.length > 0) {
for (var j=0; j<u_IdxNum && j<20 ; j++) {
r = u_Idx[j];
if (currStar!=relatedStar[r]){
if (currStar != 0)
document.write('</ul>');
currStar = relatedStar[r];
myStars = "";
for (i=0; i<currStar; i++)
myStars = myStars + '★';
var myP = Math.floor(100*relatedStar[r]/labelNum);
myRBG = spanRGB(myP, optionRGB);
document.write('<h4>' + myRBG);
document.write('相關度 ' + myStars + ' ' + myP + '% 的文章 :</span></h4> <ul>' );
// document.write('相關度 ' + myStars + ' (' + relatedStar[r] + '/' + labelNum + ') 的文章 :</span> </h4> <ul>' );
}
document.write('<li><a href="' + relatedUrls[r] + '">' + relatedTitles[r] + '</a> - ' + relatedDates[r] + '</li>');
}
if (currStar != 0)
document.write('</ul>');
document.write('== 以上 ' + j + ' 則 ==, <a href="http://eucaly61.blogspot.com/2008/07/related-posts-with-correlation.html" target="_blank">相關文章及相關度說明</a>');
}
}
//]]>
</script>

.

另外寫了一個『不用寫程式, 不用改模版的方法』, 要先掛 jQuery, 再依文章所述安裝。對程式不熟的人, 建議使用 相關文章點播台 -- RPS 1.0 beta

.

  • 補充 ----『隨機文章』

至於『隨機文章』, 可以參考底下的做法, 將它的精神改寫到 ABIN 的程式裡面。

Blogger Feeling Lucky Widget (Random Post)

  • 按鈕呼叫 feelingLucky()
  • feelingLucky()

/feeds/posts/summary?max-results=0&alt=json-in-script 傳給 readLucky()

  • readLucky()

取得 文章總數, parseInt(feed.openSearch$totalResults.$t,10)
產生 亂數
將 亂數 傳給 fetchLuck()

  • fetchLuck()

/feeds/posts/summary?start-index=+亂數+&max-results=1&alt=json-in-script 傳給 showLucky()

  • showLucky

秀出文章

.

12 意見:

發表您的回應
  1. LVCHEN 提到...

    我現在正仔細看你的code,很有趣的概念呢。
    害我又手癢起來...
    我有在想,其實不需要將不同相關度分門別類,是不是整個顯示成一個 List,然後在每一條後面加上相關度的提示即可?
    例如:
    『相關文章』『格中格』 -- Grazr - 2008-06-30 (100%)

    這樣也可以省掉處理顏色的麻煩。

  2. 水瓶尤加利 / Eucaly61 提到...

    @ LVCHEN,
    相關度的算法 還有其他方式在 思考中 (就不會是簡單的分數 5/5, 5/4, 5/3, ...)

    看了程式就知道, 其實我並沒有『真的排序』, ( O(n*n) 或 O(n*log n) ...),
    只是照著『有幾個相同標籤』將它們挑出來, ( O(n*m) m是標籤數, n是文章數),

    不過, 那可能都不是速度的關鍵, 我猜真正的關鍵是在 json 抓 feed, 只是不知如何測試?

    顏色有助於吸引目光, .... 那是我的偏見 ....

    我們來辦個投票好了 ~~
    .

  3. LVCHEN 提到...

    你說的沒錯,相關度的確還有其他的方法,例如標題的關鍵字等等...
    其實我說的方法也不需要真的排序,關鍵應該還是你的相關度計算方式。
    我同意顏色有助於吸引目光,只是在調整時多了些麻煩,不如只要加上 ID,方面使用 CSS 或是額外的參數調整就好了。
    json 抓 feed 的速度我也不知道有沒有辦法知道,有時是遠端的伺服器,有時是使用者端自己的問題,也許是無解的...
    只是根據我做最新回應 1.7 版的經驗,google 回傳的速度,真的很快...因為我那一版寫的效率不好,不過也沒有太明顯的延遲...僅供參考囉

  4. s 提到...

    首先先謝謝小弟幾篇文章獲得您的推薦,能讓您抬愛真是讓我又驚又喜,至少不讓小弟覺得寫的東西很難看、沒人看...(看Google analytics那人氣...嗚嗚)

    再來是針對您本文的隨機文章,小弟提出一點看法。其實說真的,我不是學程式背景出身的人,因此有許多地方其實我看不太懂...囧>

    但如果站在我一個使用者的立場,我個人覺得相當期待你文後「尚待努力之處」的那兩點。因為說真的,我已經是hinet光纖10m/2m的頻寬了,連blogger,跟連國內無名、pixnet、Xuite等等相比,速度真的有差...blogger國內似乎沒有伺服器,因此雖無可避免,但站在讀者、版主立場來說,當然都希望blog頁面越快開好越好....

    因此,小弟大膽在下面提出一個點給水瓶大大參考,如果立論不佳,還請水瓶大大見諒..

    如果我是站在一個讀者的立場,我會覺得其實相關文章的「相關性」不是那麼重要。當然這是小弟一點看法,但相關性75%,跟相關性50%,說真的...除非我剛好在針對我閱讀的文章主題做研究(例如想看看還有哪些blogger hack等等),不然大部分時間我都是隨意瀏覽的狀態,比起相關性的數字高低,題目更能吸引我的注意...

    換句話說,會去閱讀其他相關文章,相關性真的不是一個影響我的因素。當然啦,這是站在我的立場,別人不一定抱著跟我一樣的想法囉...^^

    我繼續期盼水瓶大大能完成此篇「相關文章」的程式,完成了我一定第一個安裝使用~非常謝謝嚕~~~

  5. 水瓶尤加利 / Eucaly61 提到...

    @ Sango

    速度的聲音我聽到了, 目前看來, 讀4個 json feed 大約要 2~4 秒, 尚不知如何改善, 但或許有機會改成在背景更新, 另外可參考 Blog側邊欄改用iframe以提升網頁載入速度

    至於版面和相關度, 我想再多收集一點意見, 再做決定

  6. s 提到...

    非常感謝!簡睿兄的文章也是我常去拜訪的大作~
    有空我會來測試看看~

  7. 匿名 提到...

    你這篇文章真的超棒
    棒到受不了

    如果看了有問題
    可以請你指導一下嗎

    感恩

  8. 水瓶尤加利 / Eucaly61 提到...

    @高藥師,
    您的站看來像是 WordPress, 不知會不會超出小弟能力所及 ..., 還是歡迎討論!!

  9. 高藥師 提到...

    可能我沒有留清楚

    http://breastca.blogspot.com/

    我現在留在這裡
    搞了半天
    因為本身不懂程式
    所以看不懂
    謝謝您

    我的MSN service@24cc.cc

    Email arguskao@gmail.com

    我想要有像您這樣相關文章的功能
    我要怎麼開始??

  10. 高藥師 提到...

    我做了這樣的動作

    head 之前的程式碼如下 :
    ......

    我加到HTML裡面了

    然後安裝隨機文章

    至於『隨機文章』, 可以參考底下的做法, 將它的精神改寫到 ABIN 的程式裡面。

    Blogger Feeling Lucky Widget (Random Post)

    裝了以後也沒反應還是亂碼??哪裡錯了嗎

  11. 水瓶尤加利 / Eucaly61 提到...

    @高藥師,
    你要不要試試不用寫程式, 不用改模版的方法, 如下,
    相關文章點播台 -- RPS 1.0 beta 測試
    要先掛 jQuery, 再依文章所述安裝 那一行, 及其他設定。
    目前的設計, 是要單篇文章才會顯示相關文章。

    如果還是決定寫程式/改模版, 我會再到你的 Blogspot 看看的。

  12. daxiguo 提到...

    酷!非常感谢分享!

張貼留言