從搜索說算法
編輯導(dǎo)讀:我們每天都在用的搜索引擎,看似簡單,其實背后的技術(shù)細節(jié)非常復(fù)雜。本文將從六個方面分析搜索引擎是如何工作的,希望對你有幫助。
我們每天都在用 Google, 百度這些搜索引擎,那大家有沒想過搜索引擎是如何實現(xiàn)的呢?看似簡單的搜索其實技術(shù)細節(jié)非常復(fù)雜,說搜索引擎是 IT 皇冠上的明珠也不為過,今天我們來就來簡單看一下搜索引擎的原理,看看它是如何工作的。
- 網(wǎng)頁抓?。核阉饕嫱ㄟ^爬蟲將網(wǎng)頁爬取,獲得頁面 HTML 代碼存入數(shù)據(jù)庫中。
- 預(yù)處理:索引程序?qū)ψト淼捻撁鏀?shù)據(jù)進行文字提取,中文分詞,(倒排)索引等處理,以備排名程序使用。
- 排序:排名程序調(diào)用索引數(shù)據(jù)庫數(shù)據(jù),計算網(wǎng)頁的相關(guān)性。其中最著名的是Google搜索引擎的核心排序算法:PageRank。
- 查詢:用戶輸入關(guān)鍵詞后,首先肯定是要經(jīng)過分詞器的處理。比如我輸入「中國人民」,假設(shè)分詞器分將其分為「中國」,「人民」兩個詞,接下來就用這個兩詞去倒排索引里查相應(yīng)的文檔。
我們重點來看一下第一步:網(wǎng)頁抓取。
這一步的大致操作如下:給爬蟲分配一組起始的網(wǎng)頁,我們知道網(wǎng)頁里其實也包含了很多超鏈接,爬蟲爬取一個網(wǎng)頁后,解析提取出這個網(wǎng)頁里的所有超鏈接,再依次爬取出這些超鏈接,再提取網(wǎng)頁超鏈接。如此不斷重復(fù)就能不斷根據(jù)超鏈接提取網(wǎng)頁。
如下圖示:
如上所示,最終構(gòu)成了一張圖,于是問題就轉(zhuǎn)化為了如何遍歷這張圖。
一、什么是圖的遍歷?
從已給的連通圖中某一頂點出發(fā),沿著一些邊訪遍圖中所有的頂點,且使每個頂點僅被訪問一次,就叫做圖的遍歷,它是圖的基本運算。
遍歷的實質(zhì)是找每個頂點的連接點的過程。
圖的特點:圖中可能存在回路,且圖的任一頂點都可能與其他頂點想通,在訪問完某個頂點之后可能會沿著某些邊又回到了曾經(jīng)訪問過的頂點。
以逛公園為例,從公園入口v1出發(fā),如何用最短的路程逛完公園全部7個景點,這就是一個典型的圖的遍歷。
圖常用的遍歷方法有兩種:
- 深度優(yōu)先搜索(Depth_First Search——DFS)
- 廣度優(yōu)先搜索(Breadth_First Search——BFS)
二、什么是深度優(yōu)先搜索?
以經(jīng)典的迷宮圖來看看如何遍歷。
題目:如何從迷宮入口出發(fā),點亮迷宮中所有的燈?
步驟一:從頂點(迷宮入口)開始遍歷,它相鄰的頂點有向右和向下的兩盞燈,我們隨機選擇向右的那盞燈并將其點亮。
步驟二:以點亮后的這盞燈為頂點繼續(xù)遍歷。它相鄰的頂點有兩個:入口的燈和右下角的燈,由于入口的燈已點亮,我們只能點亮右下角的那盞燈。
步驟三:重復(fù)以上步驟,以被點亮的燈為頂點繼續(xù)遍歷,直至這條路走不通為止,用通俗的話來說就是“把一條路走到黑”。如下圖:
步驟四:無路可走后,沿著原路返回,繼續(xù)尋找沒有被點亮的燈,直至把所有的燈全部點亮。至此,我們完整地實現(xiàn)了深度優(yōu)先搜索。如下圖:
總結(jié):
深度優(yōu)先搜索的主要思路是:從圖中一個未訪問的頂點 V 開始,沿著一條路一直走到底,然后從這條路盡頭的節(jié)點回退到上一個節(jié)點,再從另一條路開始走到底……
不斷遞歸重復(fù)此過程,直到所有的頂點都遍歷完成,它的特點是不撞南墻不回頭,先走完一條路,再換一條路繼續(xù)走。
三、什么是廣度優(yōu)先搜索?
題目:如何從入口1出發(fā),遍歷整顆樹?
步驟一:先遍歷節(jié)點1的所有節(jié)點——2,3,4。
步驟二:再分別遍歷節(jié)點2,3,4的所有節(jié)點——5,6,7,8。
步驟三:再分別遍歷節(jié)點5,6,7,8的所有節(jié)點——9,10。
總結(jié):
具體思想:從圖中某頂點1出發(fā),在訪問了1之后依次訪問1的各個未曾訪問過的鄰接點,然后分別從這些鄰接點出發(fā)依次訪問它們的鄰接點,并使得“先被訪問的頂點的鄰接點先于后被訪問的頂點的鄰接點被訪問”,直至圖中所有已被訪問的頂點的鄰接點都被訪問到。如果此時圖中尚有頂點未被訪問,則需要另選一個未曾被訪問過的頂點作為新的起始點,重復(fù)上述過程,直至圖中所有頂點都被訪問到為止。
簡單來說,廣度優(yōu)先遍歷,指的是從圖的一個未遍歷的節(jié)點出發(fā),先遍歷這個節(jié)點的相鄰節(jié)點,再依次遍歷每個相鄰節(jié)點的相鄰節(jié)點。
所以廣度優(yōu)先遍歷也叫層序遍歷,先遍歷第一層(節(jié)點 1),再遍歷第二層(節(jié)點 2,3,4),第三層(5,6,7,8),第四層(9,10)。
四、什么是棧?
棧是一種只能從表的一端存取數(shù)據(jù)且遵循 “先進后出”?原則的線性存儲結(jié)構(gòu)。
例如,我們經(jīng)常使用瀏覽器在各種網(wǎng)站上查找信息。假設(shè)先瀏覽的頁面 A,然后關(guān)閉了頁面 A 跳轉(zhuǎn)到頁面 B,隨后又關(guān)閉頁面 B 跳轉(zhuǎn)到了頁面 C。而此時,我們?nèi)绻胫匦禄氐巾撁?A,有兩個選擇:
- 重新搜索找到頁面 A;
- 使用瀏覽器的”回退”功能。瀏覽器會先回退到頁面 B,而后再回退到頁面 A。
而瀏覽器 “回退” 功能的實現(xiàn),底層使用的就是棧存儲結(jié)構(gòu)。
五、什么是隊列?
與棧結(jié)構(gòu)不同的是,隊列的兩端都”開口”,要求數(shù)據(jù)只能從一端進,從另一端出。隊列中數(shù)據(jù)的進出要遵循 “先進先出” 的原則,即最先進隊列的數(shù)據(jù)元素,同樣要最先出隊列。
隊列的應(yīng)用也很廣泛,只要滿足“先來先服務(wù)”特性的應(yīng)用均可采用隊列作為其數(shù)據(jù)組織方式。例如在多用戶系統(tǒng)中,多個用戶排成隊,分時地循環(huán)使用CPU和主存。
棧和隊列在圖的遍歷中的應(yīng)用:
深度優(yōu)先搜索由于是先入后出的算法,使用棧來實現(xiàn)。而廣度優(yōu)先搜索是先入先出的算法,使用隊列實現(xiàn)。
以二叉樹為例來看下如何用棧來實現(xiàn) DFS。
同樣以以上圖二叉樹為例來看看如何用隊列來實現(xiàn)廣度優(yōu)先遍歷。
六、如何抓取網(wǎng)頁?
回到開篇提到的搜索引擎,我們來繼續(xù)看看網(wǎng)頁抓取的大致思路。
如果是廣度優(yōu)先遍歷:先依次爬取第一層的起始網(wǎng)頁,再依次爬取每個網(wǎng)頁里的超鏈接。
如果是深度優(yōu)先遍歷:先爬取起始網(wǎng)頁 1,再爬取此網(wǎng)頁里的鏈接,爬取完之后,再爬取起始網(wǎng)頁 2。
實際上爬蟲是深度優(yōu)先與廣度優(yōu)先兩種策略一起用的,比如在起始網(wǎng)頁里,有些網(wǎng)頁比較重要(權(quán)重較高),那就先對這個網(wǎng)頁做深度優(yōu)先遍歷,遍歷完之后再對其他(權(quán)重一樣的)起始網(wǎng)頁做廣度優(yōu)先遍歷。
本文由 @CARRIE 原創(chuàng)發(fā)布于人人都是產(chǎn)品經(jīng)理。未經(jīng)許可,禁止轉(zhuǎn)載
題圖來自Unsplash,基于CC0協(xié)議
這二叉樹和棧、隊列,立馬讓我想起了大學(xué)時候被C++和數(shù)據(jù)結(jié)構(gòu)支配的恐懼。