whoosh使用笔记
1. whoosh安裝
pip install Whoosh
2. 添加索引
第一步:生成schema
第二步:根據(jù)schema生成index.index就是一個目錄中的一堆文件
(針對某個目錄,調(diào)用一個已存在的索引名字的index.create_in方法,會清空已存在索引的內(nèi)容!).若想清除索引,可以把目錄中的索引文件刪掉。若目錄中僅有一個索引,可以刪除整個目錄,然后從新生成目錄即可。
第三步:根據(jù)index生成writer(調(diào)用index.writer())
第四步:writer.add_document即可
由于打開writer時會lock住索引文件,因此在某一時間,僅有一個線程或進(jìn)程可打開一個writer.打開一個已被lock的writer會拋出LockError.whoosh提供了AsyncWriter和BufferWriter可以在lock狀況下工作。
對于某字段,可以索引與存儲分開,使用stored_<fieldname>字段即可。 writer不commit, 或者cancel, 其他線程或進(jìn)程不可再打開writer
3. 編輯和刪除索引
刪除操作使用writer的以下三個方法
delete_document(docnum)方法 (docnum是索引查詢結(jié)果的每條結(jié)果記錄的docnum屬性)
delete_by_term(field_name,termtext)方法 (特別適合刪除ID,或KEYWORD字段)
delete_by_query(query)
刪除一個index僅僅是把該document的docnum添加到一個deleted index列表中
編輯即replace,可以使用上面的delete_*方法刪除后,使用add_document添加。也可以使用update_document。使用該方法時,在schema里定義的字段,至少有一個字段是定義有unique屬性的。whoosh使用該unique字段查找文檔,然后刪除之。
1 from whoosh.fields import Schema, ID, TEXT
2
3 schema = Schema(path = ID(unique=True), content=TEXT)
4 ix = index.create_in("index")
5 writer = ix.writer()
6 writer.add_document(path=u"/a", content=u"The first document")
7 writer.add_document(path=u"/b", content=u"The second document")
8 writer.commit()
9
10 writer = ix.writer()
11 # Because "path" is marked as unique, calling update_document with path="/a"
12 # will delete any existing documents where the "path" field contains "/a".
13 writer.update_document(path=u"/a", content="Replacement for the first document")
14 writer.commit()
其實(shí)unique字段和update_document就是delete和add的一種shortcut.
4. 查詢索引
第一步:若索引已添加了,調(diào)用open_dir("dir of index")即可返回index,若出現(xiàn)exception則說明,還沒有添加任何索引。
第二步:通過調(diào)用index.searcher(),根據(jù)index生成searcher. searcher就是打開的一堆文件,用完一定要關(guān)閉。 searcher有很多獲取索引信息的有用方法,
比如lexicon(fieldname):得到某字段的全部分詞。當(dāng)然其中最重要的方法就是search方法。
第三步: 生成查詢對象, 有兩種方式:
直接構(gòu)建query對象:
類似于:myquery = And([Term("content", u"apple"), Term("content", "bear")])
query language:
就是解析查詢的字符串后,生成一個query對象
step1, 通過 parser=QueryParser("content",index.schema),先生成一個parser. 其中content是若不定義字段時,默認(rèn)的查詢字段。
step2, 調(diào)用parser.parse(querystring),分析query,生成query對象
第四步: 以query對象為參數(shù)調(diào)用searcher的search方法.得到查詢result.
默認(rèn)的search方法的results最多僅返回10個匹配的文檔。若想返回更多,就要使用limit參數(shù)查詢了:
results = searcher.search(query,limit=20). 若要得到全部的結(jié)果,可把limit=None.
search_page(query,page)方法可已讓你得到某page的結(jié)果,默認(rèn)是一頁10個hit,可以使用pagelen參數(shù)調(diào)整
search_page(query,page,pagelen=20)
Results對象表現(xiàn)的就像是list一樣:可進(jìn)行l(wèi)en(results), results[0], results[0:2]
由于默認(rèn)的results僅返回10條記錄,所以results的scored_length()可能會小于索引中實(shí)際匹配的總條目數(shù)。
而調(diào)用len(result),其實(shí)是運(yùn)行了一個快速的非計分版本的查詢,得到的是匹配的全部文檔數(shù)。這個調(diào)用通常很快速,但是若是遇到一個很大的索引的話,會有明顯的延遲。
若要避免這種延遲,可以使用has_exact_length(), estimated_length(), and estimated_min_length() 去估算匹配的文檔數(shù)目而不是使用len()
len()返回的是全部的滿足條件的文檔數(shù)量,estimate_*返回的是預(yù)估的數(shù)量,若預(yù)估已確切,則是確切的數(shù)量.scored_length()返回的數(shù)值小于等于limit
可以在search方法中設(shè)置terms=True,來記錄:在terms查詢中,哪個term匹配哪個document.然后通過results.matched_terms()調(diào)用,返回results中匹配了哪些term.
在hit中調(diào)用matched_terms()返回,在hit中匹配了哪些terms, 設(shè)置terms=True,還可以加速查詢結(jié)果高亮的處理
5. 使用查詢結(jié)果
scoring:
一般而言,result文檔列表使用score值來排序。whoosh.scoring模塊包含了多個不同scoring算法的實(shí)現(xiàn),默認(rèn)是BM25F.
當(dāng)初始化searcher時可以用weighting關(guān)鍵字去替換默認(rèn)的scoring算法。可以繼承WeightingModel實(shí)現(xiàn)定制權(quán)重算法.
過濾結(jié)果:
對searcher對象的search方法使用filter參數(shù),可以限定results中的允許的文檔。也可以使用mask參數(shù)對限定results中不允許的文檔.參數(shù)值可以是query對象,results對象,也可以是承載docnum的set集合。
排序和分類:
對查詢結(jié)果的排序和分類是基于facet的。在查詢結(jié)果中的每個文檔里的每個facet都會和一個值相關(guān),使用這個數(shù)值,可以讓你對結(jié)果排序或分組。
查詢結(jié)果在默認(rèn)情況下,是scoring最高的值排在前面。可以使用在search方法中使用sortedby參數(shù)定義其他的條件對查詢結(jié)果排序。
生成一個可排序的字段:
為了可以針對某字段排序,在定義schema時,需對該字段添加sortable=True參數(shù).也可以針對沒定義sortable=True的字段排序,但是比較沒有效率。
合并results對象:
Results.extend(results):把results加在Results后
Results.filter(results):把results中的文檔從Results中移除
Results.upgrade(results):把出現(xiàn)在results中的Results文檔,移到Results的前頭
Results.upgrade_and_extend(result),出現(xiàn)在results中的Results文檔,移動到Results的前頭,而那些不在Results中的results文檔,則添加到Results后頭。
6. 摘要并高亮查詢結(jié)果
高亮的過程就是一個pipeline的處理過程,和4個元件相關(guān):
Fragments : 基于匹配的term在文檔中的位置,把原始的文檔砍成__fragments__
Scorers: 給每個fragment賦一個分值,允許系統(tǒng)根據(jù)分值排出最好的fragment.
Order functions: 控制展示給用戶的fragment,是展示先出現(xiàn)在文檔里的fragment,還是展示score最高的fragment.
Formatters: 把對應(yīng)的fragment格式化為用戶可讀格式,如html
在對文本進(jìn)行高亮處理前,需要去除格式標(biāo)簽,比如:html,和 wiki tags.
results = mysearcher.search(myquery)
for hit in results:
print(hit["title"])
# Assume "content" field is stored
print(hit.highlights("content"))
若高亮的字段沒有stored在index中,則需要通過其他途徑得到這個字段的text.
whoosh默認(rèn)僅從文本的前32k字符中抽取fragment. 可以通過調(diào)整參數(shù)來增加這個值。
results = mysearcher.search(myquery) results.fragmenter.charlimit = 100000
或者
results.fragmenter.charlimit = None 直接關(guān)閉限制
也可以初始化一個定制的framenter, 直接在fragment上設(shè)置字符限制:
sf = highlight.SentenceFragmenter(charlimit=100000) results.fragmenter = s
定制高亮:
fragment的數(shù)量:
可以使用top參數(shù)控制每個文檔返回的fragment的數(shù)量
print hit.highlights("content", top=5)
fragment的size:
fragmenter的maxchar屬性控制fragment的最大長度,默認(rèn)是200. surround屬性控制fragment里關(guān)鍵字前后截取的背景文字長度,默認(rèn)是20
# Allow larger fragments results.fragmenter.maxchars = 300 # Show more context before and after results.fragmenter.surround = 50
Fragmenter:
Fragmenter控制如何從原始文本中提取摘錄文字. Whoosh.hightlight包里已有以下預(yù)制的fragmenter:
whoosh.highlight.ContextFragmenter (默認(rèn))
這是一個默認(rèn)的智能fragment,可以發(fā)現(xiàn)匹配的term, 并抽取周圍的文字生成 fragment. 這個fragmenter只產(chǎn)生包含匹配term的fragment.
whoosh.highlight.SentenceFragmenter
依標(biāo)點(diǎn)符號,按句子抽取
whoosh.highlight.WholeFragmenter
返回整個文本作為fragment,高效(不做處理,當(dāng)然高效)適合小文本
不同的fragmenter有不同的選項參數(shù)
Scorer:
Scorer是一個可調(diào)用的對象,使用fragment作為參數(shù),返回一個可排序的值(值越大,代表該fragment質(zhì)量越好)。 高亮系統(tǒng)使用這個值去挑選出展示給用戶的最佳fragment.
#定義一個新的scorer
def StandardDeviationScorer(fragment):
"""Gives higher scores to fragments where the matched terms are close
together.
"""
# Since lower values are better in this case, we need to negate the
# value
return 0 - stddev([t.pos for t in fragment.matched])
#使用這個scorer
results.scorer = StandardDeviationScorer
Order:
order是一個函數(shù),該函數(shù)以fragment為參數(shù),返回一個可排序的值,通過該值對fragment進(jìn)行排序。
whoosh.highlight模塊有一下的排序函數(shù):
FIRST(默認(rèn)的)
按出現(xiàn)順序
SCORE:
按得分順序
還有其他不常用的: LONGER長fragment優(yōu)先,SHORTER短fragment優(yōu)先
使用非默認(rèn)的排序函數(shù):
results.order = hightlight.SCORE
Formatter:
formatter負(fù)責(zé)控制分值最高的fragment如何以格式化的方式呈現(xiàn)給用戶。通過設(shè)置不同的formatter可以返回任何格式,包括:html,genshi事件流,SAX事件生成器,等。
highlight模塊有一下預(yù)置實(shí)現(xiàn)
whoosh.highlight.HtmlFormatter
以帶class屬性的html標(biāo)簽包圍的方式返回匹配的term
whoosh.highlight.UppercaseFormatter
把匹配的term以大寫字母呈現(xiàn)
whoosh.highlight.GenshiFormatter
輸出一個genshi事件流
替換formatter的方式和上面替換其他三個元件的方式一致,更改results.formatter屬性即可
總結(jié)
以上是生活随笔為你收集整理的whoosh使用笔记的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 字符串字符统计——js练习
- 下一篇: 屈原跳的什么江(屈原投为什么要投江?)