天天看點

whoosh mysql_Whoosh搜尋引擎

Whoosh搜尋引擎

whoosh 是一個純python實作的全文搜尋引擎,它小巧輕便,安裝簡單,設計上參考了 Lucene ,性能上雖有欠缺,但貴在友善,無需複雜安裝,對于建構小型網站的搜尋引擎來說,是一個不錯的選擇。

1. 快速入門

whoosh 可以使用pip進行安裝

pip install whoosh

現在通過官網的例子,快速體驗

from whoosh.index import create_in

from whoosh.fields import *

# 建構索引

schema = Schema(title=TEXT(stored=True), path=ID(stored=True), content=TEXT)

ix = create_in("indexdir", schema)

writer = ix.writer()

writer.add_document(title=u"First document", path=u"/a",content=u"This is the first document we've added!")

writer.add_document(title=u"Second document", path=u"/b", content=u"The second one is even more interesting!")

writer.commit()

# 搜尋

from whoosh.qparser import QueryParser

with ix.searcher() as searcher:

query = QueryParser("content", ix.schema).parse("first")

results = searcher.search(query)

print(results[0])

程式最終輸出結果為

官網上的例子,我沒有做任何修改,隻是添加了兩行注釋。整個程式分為兩部分,第一部分是建構索引的過程,第二部分是搜尋的過程。

2. 建構索引

2.1 反向索引

搜尋引擎的關鍵技術是建立反向索引,反向索引記錄了哪些文檔中包含了某個單詞,比如 “酷python” 這個詞出現在了你正在看的這篇文章中,假設這篇文章的編号是111, 那麼索引中就會記錄一條 酷python:111的記錄。當你搜尋 酷python 這個詞的時候,搜尋引擎從反向索引中找到 酷python所對應的文檔,如果有多個,搜尋引擎則計算文檔與搜尋詞的相關性,并根據相關性進行排序傳回給你結果。

2.2 分詞

我們在搜尋時,所搜尋的關鍵詞可能是一個句子,文檔裡那麼多内容,但索引隻記錄詞與文檔編号之間的映射關系,是以,不論是建構索引還是根據關鍵詞進行搜尋,都得進行分詞。對于英國文檔,分詞是一件簡單的事情,因為英語的句子是由若幹個單次組成的。而中文的分詞則相對複雜,因為我們的詞是由單個漢字組成的,而詞與詞之間是沒有空格這種明顯的分界的,具體哪幾個漢字組成一個詞,要看所處的語境,比如 “ 軍任命了一名中将 ”, 這裡中将就是一個詞,但在句子“ 産量三年中将增長兩倍 ”, 中将 就不再是一個詞。

但你大可不必擔心,因為現在的中文分詞技術已經非常成熟了,開源庫jieba可以滿足你絕大部分需求。

2.3 索引模式

現在要為100篇文章建構索引,一篇文章的資訊可能包括 文章标題,内容,作者,在建構索引的時候,你需要定義索引模式,就如同定義一張mysql裡的表,你需要指出需要存儲哪些字段,以及這些字段的類型

from whoosh.fields import TEXT, SchemaClass

from jieba.analyse import ChineseAnalyzer

analyzer = ChineseAnalyzer()

class ArticleSchema(SchemaClass):

title = TEXT(stored=True, analyzer=analyzer)

content = TEXT(stored=True, analyzer=analyzer)

author = TEXT(stored=True, analyzer=analyzer)

與官網中的例子不同,我通過繼承SchemaClass 來實作一個新的類,以此定義索引模式。而且我設定了analyzer 為ChineseAnalyzer, 這樣whoosh就可以支援中文索引了,analyzer會對文檔中的中文進行分詞。

2.4 添加文檔

schema = ArticleSchema()

ix = create_in("indexdir", schema, indexname='article_index')

writer = ix.writer()

writer.add_document(title="登鹳雀樓", author="王之渙",content="白日依山盡,黃河入海流,欲窮千裡目,更上一層樓")

writer.add_document(title="登高", author="杜甫", content="風急天高猿嘯哀,渚清沙白鳥飛回")

writer.add_document(title="胡亂寫的", author="黃河戀", content="展示效果")

writer.commit()

create_in 會建立一個名為indexdir 的檔案夾,添加文檔時,一定要根據你所定義的索引模式進行添加,這樣就建立好了索引,添加文檔的過程,就如同向mysql的表裡寫入資料。

3. 搜尋

搜尋的過程,需要使用open_dir函數打開索引檔案,建立Searcher 對象

from whoosh.qparser import QueryParser

from whoosh.index import open_dir

ix = open_dir("indexdir", indexname='article_index')

with ix.searcher() as searcher:

query = QueryParser("content", ix.schema).parse("黃河")

results = searcher.search(query)

print(results[0])

程式輸出結果

3.1 高亮顯示

我們在百度搜尋引擎搜尋關鍵詞所得到的結果,那些與關鍵詞比對的部分會被高亮顯示,這樣友善使用者檢視内容,這個功能,whoosh同樣支援

with ix.searcher() as searcher:

query = QueryParser("content", ix.schema).parse("黃河")

results = searcher.search(query)

data = results[0]

text = data.highlights("content")

print(text)

程式輸出結果為

白日依山盡,

黃河

入海流,欲窮千裡目

在html檔案中,你可以自己來定義match 和 term0 的樣式。

3.2 多個字段同時搜尋

對多個字段同時搜尋,需要使用MultifieldParser

from whoosh.qparser import QueryParser, MultifieldParser

from whoosh.index import open_dir

ix = open_dir("indexdir", indexname='article_index')

with ix.searcher() as searcher:

query = MultifieldParser(["content", 'author'], ix.schema).parse("黃河")

results = searcher.search(query)

for data in results:

print(data)

content中有黃河,或者author有黃河的文檔,都可以被搜尋出來,程式輸出結果

3.3 多個關鍵詞同時搜尋

如果你所搜尋的内容并不僅僅是一個關鍵詞,而是多個,或者你搜尋的是一個句子,搜尋引擎會把你的句子進行分詞,得到若幹個詞,這些詞作為條件進行搜尋,隻有被搜尋的字段同時滿足這些關鍵詞時,才能得到搜尋結果,比如下面的搜尋

query = MultifieldParser(["content", 'author'], ix.schema).parse("黃河 杜甫")

這個搜尋條件不會得到任何結果,原因在于搜尋條件等價于

((content:黃河 OR author:黃河) AND (content:杜甫 OR author:杜甫))

被搜尋的字段中,比如同時包含黃河與杜甫。如果你希望這些關鍵詞之間是或的關系,那麼需要你自己來建構搜尋條件

from whoosh.qparser import QueryParser, MultifieldParser

from whoosh.index import open_dir

from whoosh.query import compound, Term

ix = open_dir("indexdir", indexname='article_index')

with ix.searcher() as searcher:

author_query = [Term('author', '黃河'), Term('author', '杜甫')]

content_query = [Term('content', '黃河'), Term('content', '杜甫')]

query = compound.Or([compound.Or(author_query), compound.Or(content_query)])

print(query)

results = searcher.search(query)

for data in results:

print(data)

三個文檔都會被搜尋到, 如果你搜尋的是一個句子,那麼你可以使用analyzer 對整個句子進行分詞,然後構造搜尋條件,我所說的analyzer就是 analyzer = ChineseAnalyzer() 語句建立的對象。

3.4 分頁搜尋

如果搜尋結果太多,那麼你需要分頁查詢

results = searcher.search_page(query, 1) # 搜尋第1頁,預設每頁10個結果

print(results.total) # 搜尋到的文檔總量,幫助你進行分頁

你擷取的是第一頁的搜尋結果,但results.total 會告訴你搜尋結果一共有多少條,這樣,你就知道該搜尋多少頁的資料了。