1. 程式人生 > >集體智慧程式設計第四章[搜尋引擎與排名]總結

集體智慧程式設計第四章[搜尋引擎與排名]總結

爬蟲程式

我們開啟一個url,返回一個html檔案,它的格式類似下面的內容:

<!DOCTYPE html PUBLIC "-//W2C//DTD XHTML 1.0 Transitioln//EN""http://www.w2.org/TR/xhtml/DTD/xhtml1-transtitional.dtd">
    <html xmln="http://www.w3.org/1999/xhtml">
        <head></head>
        <body></body>
    </html>

其中和tag中,還有內嵌的很多tag,我們需要一個個分析這些巢狀的tag,並提取其中的文字。這個就是網頁爬蟲。

    1 import urllib2
    2 from bs4 import BeautifulSoup
    3 c = urllib2.urlopen('http://www.51testing.com/html/39/n-860239.html')
    4 cr = c.read()
    5 soup = BeautifulSoup(cr,'html.parser')
    6 c = soup.contents ##得到所有tag,方便以後分析

其中第六行,tag的 .contents 屬性可以將tag的子節點以列表的方式輸出。BeautifulSoup物件本身一定會包含子節點,就是html檔案內的所有html標籤是BeautifulSoup物件本身的子節點。
例如:

    c = soup.contents[0] ##返回html檔案內的第一個tag
    print (type[c])
    print (c)
    ##<class 'bs4.element.Doctype'>
    ##html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"

記住,換行符也是一個子節點。例如:

    c = soup.contents[1] ##返回的是第一個tag後面的換行符
    print
type(c) print (c,'utf-8') ##<class 'bs4.element.NavigableString'> ##(u'\n', 'utf-8')

接下來才是下一個真正的tag:

    c = soup.contents[2] ##返回的是<html xmlns...></html>節點
    print type(c)
    print (c)
    ##<class 'bs4.element.Tag'>
    ##輸出<html xmln="http://www.w3.org/1999/xhtml">

以及它的所有子孫節點內容。
訪問head節點:

    c = soup.contents
    print type(c[2].contents[1])##注意換行符也是子節點
    print (c[2].contents[1])
    ##<class 'bs4.element.Tag'>
    ##輸出<html xmln="http://www.w3.org/1999/xhtml"></html>

以及它的所有子孫節點內容。

建立索引

我們通過爬蟲程式得到網站的資訊之後,包括每一層的url資訊和頁面出現的單詞,還包括連結上出現的單詞等資訊,這個時候我們就需要將這些資訊存入資料庫,併為它們建立索引。
本書中建立的索引如下
這裡寫圖片描述
表wordlist儲存了爬取到的單詞的索引,表urllist儲存了每個url的索引。表wordlocation儲存了每個url對應頁面上出現的wordid以及他們的location(出現在什麼位置,比如 url1對應的頁面,word1在文件的第30 59個字元的位置出現則對應 (url1,word1,30)(url1,word1,59)).另外兩張表後面再談。

查詢

當我們需要搜尋某些單詞對應的網站時候,比如輸入‘world global’則會先將搜尋短語分割為單詞,再在資料庫中查詢所有包含這兩個單詞的url,將結果返回給使用者。這就是最最原始的搜尋引擎。下面我們來提升一下這個引擎的效果。

基於內容的排名

如何在返回的大量網頁中,找出真正和查詢匹配的頁面。這需要我們找到一種能夠針對給定查詢條件為網頁進行評價的方法,並且在返回結果中將評價最高的排列在前面。

單詞頻度

最簡單的思想,搜尋的單詞在網頁中出現頻率較高,則也有可能是我們要的頁面。遺憾的是現實往往沒這麼簡單。

文件位置

文件的主題有可能會出現在靠近文件的開始處,統計單詞在文件中出現的位置資訊,位置越往前的就越有可能是我們想要的結果。同樣這也圖樣圖森破。

單詞距離

如果查詢條件中有多個單詞,則他們在文件中出現的位置應該很靠近。注意這裡不是靠近,而是靠前。同樣然並卵的一條規則。

以上規則,早期的搜尋引擎的確就是這麼幹的。所以我們也需要用這幾條規則來練練手,涉及有資料庫,資料歸一化以及程式設計的知識。書上的例子還是很不錯的。只是我選擇了cnn的網站作為實驗物件,例子中的網站打不開。最重要的是體會到資料庫還是很重要的,要好好學。
書中對單詞距離判斷那裡過於簡單了,直接在查詢單片語中用相鄰兩個最近單詞的距離來評價一個url,這很不科學,但作為例子而已,這點沒必要太深究。

利用外部回指連結

以上是基於網頁內容的評價度。現在我們提高一點逼格。通過考察外界就該網頁所提供的資訊–尤其是哪個頁面鏈向了改網頁,以及他們對該網頁的評價,來進一步改善搜尋結果。

簡單計數

處理外部回指連結最為簡單的做法,就是在每個網頁上統計連結的數目,並將該連結總數所為針對網頁的度量。回到剛才資料庫關係圖:
這裡寫圖片描述

表link中儲存了爬取到的資源中url的指向關係。比如url1的頁面中有url2的連結,則(fromid:url1,toid:url2).
通過這個關係,我們可以在表中查詢所有toid=指定url的記錄,並計數。這個計數值就是這個url對應網頁的評價度,再計算所有的url,並歸一化,排個序就行。

PageRank演算法

PageRank是有Google創始人發明的,並以發明者之一的Larry Page命名。現在基於這種變體已被所有大型搜尋引擎採用。該演算法認為網頁的重要性是依據指向該網頁的所有其他網頁的重要性,以及這些網頁中包含的連結數求得的。沒錯這個演算法就是來評價網頁重要性的。這個演算法和其它演算法(比如計入內容的演算法加權求和得到的評價結果能改進引擎的效果)。
圖2: 計算A的PageRank值
上圖中,網頁B,C和D均指向A,它們的PageRank值已經計算得出。B還指出另外三個網頁,而C則指向其他四個網頁,D只指向A。為了得到A的PageRank值,我們將指向A的每個網頁的PageRank(pr)值除以這些網頁中的連結總數,然後乘以阻尼因子0.85,再加上一個0.15的最小值。PR(A)的計算公式如下:

PR(A)====0.15+0.85(PR(B)/links(B)+PR(C)/links(C)+PR(D)/links(D))0.15+0.85(0.5/4+0.7/5+0.2/1)0.15+0.850.4650.54525
我們發現,由於D指向A,而且能貢獻出它的全部分值,所以相比B或者C,儘管D本身的PageRank值較低,但是是加上它對A的PageRank值貢獻度更大。本例中所有指向A的網頁都已有了PageRank值。只有知道了指向同一網頁的所有其他網頁的評價後,我們才算出該網頁的評價值。同樣,對於這些網頁的所喲其他網頁,如果不先計算它們的評價值,那麼這些網頁的pagerank也是無法計算的。如何對一組還沒有pagerank值得網頁進行pangrank計算呢?
解決方法是,為所有PageRank都設定一個任意的初始值,然後反覆計算,迭代若干次。在每次迭代中,每個網頁的PageRank值將會越來越接近真實值。迭代所需要次數要視網路數量而定,不過對於目前正在處理的這一小組網頁,20次就足夠了。
資料庫關係圖
由於有資料庫操作,所以把資料庫關係圖放在這裡
 def calcuatepagerank(self,iterations=20):
        self.con.execute("drop table if exists pagerank")
        self.con.execute("create table pagerank(urlid primary key, score)")

        #初始化每個url,讓他們pagerank值都相等
        self.con.execute('insert into pagerank select rowid,1.0  from urllist')

        self.dbcommit()

        for i in  range(iterations):
            print "Iteration %d" %(i)
            for (urlid,) in self.con.execute('select rowid from urllist'):
                pr = 0.15
                #迴圈遍歷指向當前網頁的其他所有page
                for (linker,) in self.con.execute('select distinct fromid from link where toid = %d' %urlid):
                    #得到連結源對應網頁的pagerank
                    linkingpr = self.con.execute('select score from \
                    pagerank where urlid=%d' %linker).fetchone()[0]

                    #求連結源的連結總數
                    linkingcount = self.con.execute('select count(* ) from \
                    link where fromid = %d'%linker).fetchone()[0]
                    pr += 0.85 * (linkingpr / linkingcount)
                self.con.execute('update pagerank set score=%f where \
                urlid=%d'%(pr,urlid))
            self.dbcommit()

利用連結文字

另一種對搜尋結果進行排名的方法,是根據指向某一網頁的連結文字來決定網頁的相關程度。大多數時候,相比於被連結的網頁自身所提供的資訊而言,我們從指向該網頁的連結中得到資訊會更有價值。因為針對其所指的連結,網頁上都會提供一些解釋其內容的簡短描述,如下圖
程式碼如下:

def inboundlinkscore(self,rows):
        uniqueurls = set([row[0] for row in rows])
        inboundcount = dict([(u,self.con.execute('select count(*) from link \
        where toid = %d' %u).fetchone()[0]) for u in uniqueurls])
        return self.normalizescores(inboundcount)

現在我們計算出了網站的各種評價度,只要對它們加權求和就能得到不同的效果,其中一些應該就是我們想要的結果。

從點選行為中學習

線上應用的一個最大優勢就在於,它們會持續受到以使用者行為為表現形式的反饋資訊。對於搜尋引擎而言,每一位使用者可以通過只點擊某條結果,而不選擇點選其它內容,向引擎及時提供有關他對搜尋結果喜好程度的資訊。
為了實現這一目的,我們將構建一個人工神經網路,向其提供:查詢條件中的單詞,返回給使用者的搜尋結果,以及使用者的點選決策,然後再對其加以訓練。一旦網路經過了許多不同的點選訓練,我們就可以利用它來改進搜尋結果的排序,以更好的反映使用者在過去一段時間內的實際點選情況。
書中對於神經網路的科普以及資料庫設計等基礎,就不講了,重點看這個神經網路是怎麼設計,並能線上訓練的。
這個神經網路結構如下

nn

神經網路對”World Bank”所做出的反應

上圖,給出了一個針對“world bank”的查詢。途中的實線代表強連結,粗體文字表示節點已經變得非常活躍。當然,最終的結果還要取決於被不斷迭代修正的連結強度(也就是連結權重)。為此,只有有人執行搜尋,並從結果中選擇連結,我們就對該網路進行訓練。在上圖的網路中,許多人對world bank字串進行搜尋,並點選了world bank的連結,加強了單詞與URL的關聯。

神經網路設計

結構:

簡單三成結構,input,hidden,output。而且本例中不是先預先建立一個隱藏層有幾千個節點,全部連結均已就緒的巨大網路,我們只在需要時候建立新的隱藏節點會更加搞笑,更加簡單。每傳入一組以前從未見過的單詞組合,該網路的構建函式就會在隱藏層中建立一個新的節點。隨後函式會為單詞與隱藏節點之間,以及查詢節點與查詢所返回的URL結果之間,建立其具有預設權重的連結。隨著查詢的增多,這個網路也會很大,輸入層隱藏層以及輸出層之間的連結將會變得非常複雜。

 def generatehiddennode(self,wordids,urls):
        if len(wordids) > 3: return None
        createkey = '_'.join([str(wi) for wi in wordids])
        res = self.con.execute('select rowid from hiddennode where create_key=\'%s\'' %createkey).fetchone()
        if res==None:
            cur = self.con.execute('insert into hiddennode(create_key) values(\'%s\')' %createkey)
            hiddenid = cur.lastrowid
            for wordid in wordids:
                self.setstrength(wordid,hiddenid,0,1.0/len(wordids))
            for urlid in urls:
                self.setstrength(hiddenid,urlid,1,0.1)
            self.con.commit()

在命令列呼叫這個函式

mynet = searchnet('nntest.db')
wWorld,wRiver,wBank = 101,102,103
uWorldBank,uRiver,uEarth = 201,202,203
mynet.generatehiddennode([wWorld,wBank],[uWorldBank,uRiver,uEarth])

該程式碼產生會產生如下結構的網路結構:


這裡寫圖片描述
圖6-2:人工神經網路試例

啟用函式:

我們選擇tanh函式(反雙曲正切變換函式)作為啟用函式。它是一類S型函式(sigmod function),所以該型別的函式都會呈現S形狀。神經網路幾乎總是利用s型函式來計算神經元的輸出。

tanh
圖6-3:tanh函式

前向傳播演算法:

如圖6-2所示,前向傳播其實就是根據這個網路拓撲圖,直接計算出結果來而已。

hhX1y1=x1w1+x2w2=tanh(h),=hw1,X2=hw2,X3=hw3=tanh(X1),y2=tanh(X2),y3=tanh(X3)

反向傳播:

這裡其實就是利用梯度下降發不斷更新圖6-2中的權值w的過程:

costfunction:Y=[0.5(y1y1)2+0.5(y2y2)2+0.5(y3y3)2][y1,y2,y

相關推薦

集體智慧程式設計[搜尋引擎排名]總結

爬蟲程式 我們開啟一個url,返回一個html檔案,它的格式類似下面的內容: <!DOCTYPE html PUBLIC "-//W2C//DTD XHTML 1.0 Transitioln//EN""http://www.w2.org/TR/xhtm

集體智慧程式設計4 搜尋排名 個人筆記

第4章 搜尋與排名 1、基於內容的排名 單詞頻度:位於查詢條件中的單詞在文件中出現的次數能有助於我們判斷文件的相關程度。 文件位置:文件的主題有可能會出現在靠近文件的開始處。搜尋引擎可以對待查單詞在文件中出現越早的情況給予越高的評價。 單詞距離:如果查

【知識點總結對象

分享 ima src 對象分配 height ted 公有 功能 簡化 面向對象程序設計的基本概念和特征 抽象性:對對象進行概括,抽出一類對象的公共性質並加以描述的過程。【數據抽象、行為抽象】 封裝性:將抽象得到的數據、行為、功能相結合,形成一個有機的整體。就是將數據與

現代軟件工程-構建之法--- 練習討論

方法 人的 工作效率 isf 強調 一是 成本 不能 時代 1 、結對項目的案例與論文   論文已閱讀。 2、性格對合作的影響   我的MBTI為:ISFJ 照顧者型(內向實感情感判斷)——值得信賴和依靠。   在團隊合作中,外傾型的人一般會較為熱情對工作積極性比較大,內傾

the c programming language second edition 函式程式結構筆記及練習題中

the c programming language second edition 第四章函式與程式結構筆記 4.3外部變數 C語言程式可以看成由一系列的外部物件構成,這些外部物件可能是變數或函式 外部變數和函式具有以下性質:通過同一個名字對外部變數的所有引

the c programming language second edition 函式程式結構筆記及練習題上

the c programming language second edition 第四章函式與程式結構筆記 4.1函式的基本認識 編寫一個程式它將輸入中包含特定模式或字串的各行打印出來。 該任務可以明確地劃分成下列3部分: while(未處理的行) if

組合語言程式設計

4.1 一個源程式從寫出到執行的過程:1編寫彙編源程式  2對源程式進行編譯連線  3執行可執行檔案中的程式。   4.2 (1)偽指令:沒有對應的機器碼的指令,最終不被CPU所執行。 segment和ends是一對成對使用的偽指令。 格式為:段名 segment

對象

.com factory 目錄 核心 student color aaa 3.5 main 一、面對對象編程的三個特性 封裝性:經數據和對數據的操作封裝在一起。通過抽象,從實例中抽取共同性質形成一般概念,例如類。 繼承:子類可繼承父類的屬性和行為,繼承父類所具有的數據和數

C++程式設計答案

4-8 #include <iostream> using namespace std; class Dog { public: Dog(int initialAge=0, int initialWeight=5); ~Dog(); int GetAg

Spring—— SpringDao(二)

4.2 Spring的事物管理 4.2.1 Spring事物管理API (1)事物管理器介面 常用的實現類: DataSourceTransactionManager Spring的回滾方式,發生執行時異常回滾,發生受查異常提交。 受查異常可以丟擲,或者try,c

高質量嵌入式Linux C程式設計 語句 學習

一、語句從流程的角度可以分為幾種 三種基本結構:順序結構、分支結構、迴圈結構 二、空語句有什麼作用 (1)純粹消耗CPU時間,起到延時作用 (2)為了程式的結構清楚,可讀性好,以後擴充新功能方便。 三、 表示式語句的構成 表示式語句由表示式加上;號構成 四、布

學習筆記之《Java核心技術卷I》---- 物件

識別類的簡單規則是在分析問題的過程中尋找名次,而方法對應著動詞 類之間最常見的三種關係: 依賴關係:即"uses-a"的關係。如果一個類的方法操作另一個類的物件(方法引數),也就是說這個類依賴於另一個類。應該儘可能地將相互依賴的類減至最少,即讓類之間的耦合度更小 聚合

C++11多執行緒程式設計 : 共享資料和競態條件

C++11 Multithreading – Part 4: Data Sharing and Race Conditions Varun February 21, 2015C++11 Multithreading – Part 4: Data Sharing and Race Con

翻譯:libevent參考手冊事件一起工作 (六) (轉)

libevent的基本操作單元是事件。每個事件代表一組條件的集合,這些條件包括:v 檔案描述符已經就緒,可以讀取或者寫入v 檔案描述符變為就緒狀態,可以讀取或者寫入(僅對於邊沿觸發IO)v 超時事件v 發生某訊號v 使用者觸發事件所有事件具有相似的生命週期。呼叫libevent函式設定事件並且關聯到event

演算法競賽入門經典(第二版)-劉汝佳- 函式遞迴 發放救濟金Uva133

In a serious attempt to downsize (reduce) the dole queue, The New National Green Labour Rhinoceros Party has decided on the following st

Go Web程式設計 --處理請求

請求和響應 Request結構 URL欄位 Header欄位 Body欄位 Form, PostForm, MultipartForm欄位 在處理器函式中,我們可以通過Request獲取各個欄位的詳細資訊 func get_request_value(w *http.Respon

物件

例4-1 #include<iostream> using namespace std; class Clock { public: void setTime(int newH=0,int newM=0,int newS=0); void showTime(); pr

(資料結構)佇列

4.1 棧 許多程式語言本身就是建立在棧結構之上的,其實時運算環境都是基於棧結構的虛擬機器。 相對於向量和列表,棧與佇列的外部介面更為簡化和緊湊。 棧的應用主要為: 結合函式呼叫棧的機制介紹一般函式呼叫的實現方式與過程,並將其推廣至遞迴呼叫。然後以降低空間複雜度的目標為線索,介紹通過

c++語言程式設計例題

例4-1 #include<iostream> using namespace std; class Clock { public: void setTime(int newH=0,int newM=0,int newS=0); void showTime(); pr

集體智慧程式設計第二三學習總結

2 基於物品的協同過濾:應用場景,當我們在豆瓣只看過一部看過電影《泰囧》並且認為評分還不錯(此時網站還沒有收集使用者足夠多的資訊,無法用基於使用者的協同過濾推薦),下次登陸豆瓣的時候會推薦《港囧》,這裡使用的方法就是基於物品的協同過濾。假如有很多很多電影,我們找到很多人的觀看記錄和評價記錄。比如電影《港囧》我