python實作一個搜尋引擎(Pylucene)實例教程

零下一度
發布: 2017-07-18 10:12:52
原創
13687 人瀏覽過
  1.          Document,文件類別。在Pylucene中建立索引的基本單位是「文件」(Document),一個Document可能是一個網頁、一篇文章、一封郵件。 Document是用以建構索引的單位同時也是進行搜尋時的結果單位,對它進行合理的設計能夠提供個人化的搜尋服務。

  2. Filed,域類別。一個Document之中可以包含多個域(Field)。 Filed是Document的組成部分,就如一篇文章的組成可能是文章標題、文章主體、作者、發表日期等多個Filed。

  3. 將一個頁面當作一個Document,包含三個Field分別是頁面的URL位址(url)、頁面的標題(title)、頁面的主要文字內容(content)。對於索引的儲存方式選擇使用SimpleFSDirectory類,將索引儲存至檔案中。分析器選擇Pylucene自備的CJKAnalyzer,該分析器對中文支援較好,適用於中文內容的文字處理。

  4. 什麼是搜尋引擎?

搜尋引擎是「對網路資訊資源進行蒐集整理並提供資訊查詢服務的系統,包括資訊蒐集、資訊整理和使用者查詢三部分」。如圖1是搜尋引擎的一般結構,資訊蒐集模組從網路擷取資訊到網路資訊庫之中(一般使用爬蟲);然後資訊整理模組對採集的資訊進行分詞、去停用詞、賦權重等操作後建立索引表(一般是倒排索引)構成索引庫;最後使用者查詢模組就可以辨識使用者的檢索需求並提供檢索服務啦。

 

 

圖1  搜尋引擎的一般結構

2.  使用python實作一個簡單搜尋引擎

2.1問題分析

從圖1看,一個完整的搜尋引擎架構從網路蒐集資訊開始,可以使用python寫一個爬蟲,這是python的強項。

接著,訊息處理模組。分詞?停用詞?倒排表? what?什麼亂七八糟的?不用管它,我們有前輩們造好的輪子---Pylucene(lucene的python封裝版本,Lucene能夠幫助開發者為軟體、系統增添檢索功能。Lucene是一套用於全文檢索和搜尋的開源程式庫) 。使用Pylucene可以簡單的幫助我們完成對採集到的資訊進行處理,包括索引的建立和搜尋。

最後,為了能在網頁上使用我們的搜尋引擎,我們使用flask這個輕量級 Web 應用框架做一個小網頁獲取搜尋語句並回饋搜尋結果。

2.2 爬蟲設計

主要蒐集以下內容:目標網頁的標題、目標網頁的主要文字內容、目標網頁指向其他頁面的URL位址。網路爬蟲的工作流程如圖2所。爬蟲的主要資料結構是隊列。首先,起始的種子節點進入隊列,然後從隊列中取出一個節點訪問,抓取該節點頁面上的目標信息,再將該節點頁面指向其他頁面的URL鏈接放進隊列,再從隊列中取出新的節點進行訪問,直至隊列為空。透過佇列「先進先出」的特性實現廣度優先的遍歷演算法,逐一造訪網站的每一頁。

 

                             有Directory、Analyzer、IndexWriter、Document、 Filed。

Directory是Pylucene中關於檔案操作的類別。它有SimpleFSDirectory和RAMDirectory、CompoundFileDirectory、FileSwitchDirectory等11個子類,列舉的四個是與索引目錄的保存相關的子類,SimpleFSDirectory是將構建的索引保存到檔案系統之中;RAMDirectory是將索引保存到RAM內存之中;CompoundFileDirectory是一種複合的索引保存方式;而FileSwitchDirectory允許暫時切換索引的保存方式以發揮各種索引保存方式的優點。

Analyzer,分析器。它是對爬蟲所獲得的將要進行建構索引的文字進行處理的類別。包括了文字進行分詞操作、去掉停用詞、轉換大小寫等操作。 Pylucene自備了若干分析器,建置索引時也可使用第三方分析器或自寫分析器。分析器的好壞關係到建構索引的品質與搜尋服務的所能提供的精準度與速度。

IndexWriter,索引寫入類別。在Directory開闢的儲存空間中IndexWriter可以進行索引的寫入、修改、增添、刪除等操作,但不可進行索引的讀取也不能搜尋索引。

Document,文件類別。在Pylucene中建立索引的基本單位是「文件」(Document),一個Document可能是一個網頁、一篇文章、一封郵件。 Document是用以建構索引的單位同時也是進行搜尋時的結果單位,對它進行合理的設計能夠提供個人化的搜尋服務。

Filed,域類別。一個Document之中可以包含多個域(Field)。 Filed是Document的組成部分,就如一篇文章的組成可能是文章標題、文章主體、作者、發表日期等多個Filed。

將一個頁面當作一個Document,包含三個Field分別是頁面的URL位址(url)、頁面的標題(title)、頁面的主要文字內容(content)。對於索引的儲存方式選擇使用SimpleFSDirectory類,將索引儲存至檔案中。分析器選擇Pylucene自備的CJKAnalyzer,該分析器對中文支援較好,適用於中文內容的文字處理。

使用Pylucene建立索引的特定操作步驟如下:

 

lucene.initVM()
INDEXIDR = self.__index_dir
indexdir = SimpleFSDirectory(File(INDEXIDR))①
analyzer = CJKAnalyzer(Version.LUCENE_30)②
index_writer = IndexWriter(indexdir, analyzer, True, IndexWriter.MaxFieldLength(512))③
document = Document()④
document.add(Field("content", str(page_info["content"]), Field.Store.NOT, Field.Index.ANALYZED))⑤
document.add(Field("url", visiting, Field.Store.YES, Field.Index.NOT_ANALYZED))⑥
document.add(Field("title", str(page_info["title"]), Field.Store.YES, Field.Index.ANALYZED))⑦
index_writer.addDocument(document)⑧
index_writer.optimize()⑨
index_writer.close()⑩
登入後複製

 

索引的建構有10個主要的步驟:

①實例化一個SimpleFSDirectory對象,將索引保存至本地文件之中,保存的路徑為自訂的路徑「INDEXIDR」。

②實例化一個CJKAnalyzer分析器,實例化時的參數Version.LUCENE_30為Pylucene的版本號碼。

③實例化一個IndexWriter對象,所攜帶的四個參數分是前面的實例化的SimpleFSDirectory對象和CJKAnalyzer分析器,布爾型的變量true表示創建一個新的索引,IndexWriter.MaxFieldLength指定了一個索引最大的域(Filed)數量。

④實例化一個Document對象,取名為document。

⑤為document新增名稱為「content」的網域。該網域的內容為爬蟲所取得的某一網頁頁面的主要文字內容。此操作的參數是實例化並馬上使用的Field物件;Field物件的四個參數分別是:

(1)“content”,域的名稱。

(2)page_info["content"],爬蟲蒐集到的網頁頁面的主要文字內容。

(3)Field.Store是用來表示該網域的值是否可以恢復原始字元的變量,Field.Store.YES表示儲存在該網域中的內容可以恢復至原始文字內容,Field. Store.NOT表示不可恢復。

(4)Field.Index變數表示該網域的內容是否應用分析器處理,Field. Index.ANALYZED表示對該網域字元處理使用分析器,Field. Index. NOT_ANALYZED則表示不對該網域使用分析器處理字元。

⑥新增名稱為「url」的網域用於儲存該頁面位址。

⑦新增名稱為「title」的網域用於儲存該頁面的標題。

⑧實例化IndexWriter物件將文件document寫入索引檔。

⑨優化索引庫文件,合併索引庫中的小文件為大文件。

⑩單一週期內建構索引作業完成後關閉IndexWriter物件。

 

Pylucene關於建立索引的搜尋的類別主要有IndexSearcher、Query、QueryParser[16]。

IndexSearcher,索引搜尋類別。用於在IndexWriter建構的索引庫中進行搜尋操作。

Query,描述查詢請求的類別。它將查詢請求遞交給IndexSearcher完成搜尋操作。 Query擁有許多子類別以完成不同的查詢請求。例如TermQuery是按詞條搜索,它是最基本最簡單的查詢類型,用來在指定域中匹配特定項的文檔;RangeQuery,指定範圍內搜索,用於在指定域中匹配特定範圍內的文檔; FuzzyQuery,一種模糊查詢,能夠簡單地識別近義詞匹配與查詢關鍵字語義相近的項。

QueryParser,Query解析器。需要實作不同的查詢需求時必須使用Query提供的不同子類,導致Query使用起來容易造成混亂。因而Pylucene也提供了Query語法解析器QueryParser。 QueryParser能夠解析提交的Query語句,根據Query語法挑選合適Query子類別完成對應的查詢,開發者不必關心底層使用的是什麼Query實作類別。例如Query語句「關鍵字1 and 關鍵字2」 QueryParser解析為查詢同時符合關鍵字1與關鍵字2的文件;Query語句「id[123 to 456]」 QueryParser解析成為查詢名稱為「id」的網域中的值在指定範圍「123」到「456」之間的文件;Query語句「關鍵字site:www.web.com」QueryParser解析成為查詢同時滿足名稱為「site」的網域中值為「www.web .com”  和符合「關鍵字」兩個查詢條件的文件。

索引的搜尋是Pylucene所專注的領域之一,為實現索引的搜尋編寫了一個名為query的類,query實作索引的搜尋有以下主要步驟:

lucene.initVM()
if query_str.find(":") ==-1 and query_str.find(":") ==-1:
query_str="title:"+query_str+" OR content:"+query_str①
indir= SimpleFSDirectory(File(self.__indexDir))②
lucene_analyzer= CJKAnalyzer(Version.LUCENE_CURRENT)③
lucene_searcher= IndexSearcher(indir)④
my_query = QueryParser(Version.LUCENE_CURRENT,"title",lucene_analyzer).parse(query_str)⑤
total_hits = lucene_searcher.search(my_query, MAX)⑥
for hit in total_hits.scoreDocs:⑦
            print"Hit Score: ", hit.score
            doc = lucene_searcher.doc(hit.doc)
            result_urls.append(doc.get("url").encode("utf-8"))
            result_titles.append(doc.get("title").encode("utf-8"))
            print doc.get("title").encode("utf-8")
 
 result = {"Hits": total_hits.totalHits, "url":tuple(result_urls), "title":tuple(result_titles)}
 return result
登入後複製

 

索引的搜尋有7個主要的步驟:

①先對搜尋語句進行判斷,若語句不是針對標題或文章內容進行單一網域的查詢,即不包含關鍵字「title :」或「content:」時預設搜尋title和content兩個網域。

②實例化一個SimpleFSDirectory對象,指定它的工作路徑為先前建立索引的路徑。

③实例化一个CJKAnalyzer分析器,搜索时使用的分析器应与索引构建时使用的分析器在类型版本上均一致。

④实例化一个IndexSearcher对象lucene_searcher,它的参数为第○2步的SimpleFSDirectory对象。

⑤实例化一个QueryParser对象my_query,它描述查询请求,解析Query查询语句。参数Version.LUCENE_CURRENT为pylucene的版本号,“title”指默认的搜索域,lucene_analyzer指定了使用的分析器,query_str是Query查询语句。在实例化QueryParser前会对用户搜索请求作简单处理,若用户指定了搜索某个域就搜索该域,若用户未指定则同时搜索“title”和“content”两个域。

⑥lucene_searcher进行搜索操作,返回结果集total_hits。total_hits中包含结果总数totalHits,搜索结果的文档集scoreDocs,scoreDocs中包括搜索出的文档以及每篇文档与搜索语句相关度的得分。

⑦lucene_searcher搜索出的结果集不能直接被Python处理,因而在搜索操作返回结果之前应将结果由Pylucene转为普通的Python数据结构。使用For循环依次处理每个结果,将结果文档按相关度得分高低依次将它们的地址域“url”的值放入Python列表result_urls,将标题域“title”的值放入列表result_titles。最后将包含地址、标题的列表和结果总数组合成一个Python“字典”,将最后处理的结果作为整个搜索操作的返回值。

用户在浏览器搜索框输入搜索词并点击搜索,浏览器发起一个GET请求,Flask的路由route设置了由result函数响应该请求。result函数先实例化一个搜索类query的对象infoso,将搜索词传递给该对象,infoso完成搜索将结果返回给函数result。函数result将搜索出来的页面和结果总数等传递给模板result.html,模板result.html用于呈现结果

如下是Python使用flask模块处理搜索请求的代码:

app = Flask(__name__)#创建Flask实例

@app.route('/')#设置搜索默认主页

def index():
html="<h1>title这是标题</h1>"
return render_template(&#39;index.html&#39;)
@app.route("/result",methods=[&#39;GET&#39;, &#39;POST&#39;])#注册路由,并指定HTTP方法为GET、POST
def result(): #resul函数
if request.method=="GET":#响应GET请求
key_word=request.args.get(&#39;word&#39;)#获取搜索语句
   if len(key_word)!=0:
      infoso = query("./glxy") #创建查询类query的实例
       re = infoso.search(key_word)#进行搜索,返回结果集
       so_result=[]
       n=0
       for item in re["url"]:
temp_result={"url":item,"title":re["title"][n]}#将结果集传递给模板
        so_result.append(temp_result)
                n=n+1
        return render_template(&#39;result.html&#39;, key_word=key_word, result_sum=re["Hits"],result=so_result)
    else:
        key_word=""
    return render_template(&#39;result.html&#39;)
if __name__ == &#39;__main__&#39;:
    app.debug = True
    app.run()#运行web服务
登入後複製


以上是python實作一個搜尋引擎(Pylucene)實例教程的詳細內容。更多資訊請關注PHP中文網其他相關文章!

相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!