国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
Inside Lucene/超人氣搜索引擎學(xué)習(xí)(1)
何用戶, 包括系統(tǒng)開發(fā)者, 使用搜索引擎的共同方式只有一個(gè): 查詢(query). 整個(gè)搜索過程的目的是為了滿足查詢要求, 搜索過程是由查詢貫穿的. 若沒有指定查詢, 而是從索引(index)的內(nèi)容出發(fā), "搜索"將是漫無目的且毫無意義的過程. 搜索過程的起點(diǎn)只能是索引.

下引用自Lucene in Action 的入門章節(jié), 在其中能看到Query是如何用來啟動(dòng)查詢的.
public class BasicSearchingTest extends LiaTestCase {
public void testTerm() throws Exception {
IndexSearcher searcher = new IndexSearcher(directory);
Term t = new Term(“subject”, “ant”);
Query query = new TermQuery(t);
Hits hits = searcher.search(query);

assertEquals(“JDwA”, 1, hits.length());

t = new Term(“subject”, “junit”);
hits = searcher.search(new TermQuery(t));

assertEquals(2, hits.length());

searcher.close();

}
}

稱為面向?qū)ο笤O(shè)計(jì)經(jīng)典范例的Lucene, 其架構(gòu)確實(shí)能反映"查詢"行為在真實(shí)世界模式, 這不愧是OOA/OOD方法帶來的成熟設(shè)計(jì). 這也讓我對(duì)Lucene設(shè)計(jì)者的軟件設(shè)計(jì)能力產(chǎn)生充足的敬佩, 要知道人家可是研究算法的. 通常搞學(xué)術(shù)和搞工程的人思想極不統(tǒng)一, 我同學(xué)在微軟工作時(shí)曾經(jīng)為研究院和工程院的代碼差異頭疼不已. Lucene的設(shè)計(jì)者們能把算法和代碼集合得如此完美, 可以說是牛中之牛了.

真正關(guān)心的是搜索算法如何依據(jù)Query導(dǎo)出查詢結(jié)果. 上面的代碼給我一些啟示, 我知道了起點(diǎn), 從searcher.search(query)開始, 我可以一步步了解Query在搜索過程里的作用機(jī)制.
為了滿足真實(shí)世界的語義, Lucene提供了眾多Query. 上面代碼中的TermQuery是最簡(jiǎn)單的Query, 日常搜索有許多直接或間就由TermQuery組合而成. search(termQuery)的構(gòu)造最基礎(chǔ), 不經(jīng)過繁瑣的轉(zhuǎn)換. 所以我從TermQuery出發(fā), 一步步考察搜索的核心機(jī)制.

進(jìn)入search 方法前, 我了解了這些限制條件: TermQuery的語義中每一個(gè)Term指一個(gè)(field, keyword)對(duì), 其描述的查詢條件是: "在指定的字段(標(biāo)題、作者、內(nèi)容...)中出現(xiàn)指定的keyword"; 高級(jí)的search方法可以處理自定義的Filter, Sort, 此處的考察對(duì)象是不假這些自定義選項(xiàng)的最簡(jiǎn)單的search.

了以上的限制, 我考察的對(duì)象--TermQuery查詢過程已經(jīng)被徹底簡(jiǎn)化了. 但在他和更復(fù)雜的重載方法中, 開發(fā)人員應(yīng)用了相同的思路, 舉一反三是我們可以期望做到的.
public class IndexSearcher extends Searcher {
public TopDocs search(Query query, Filter filter, final int nDocs)
throws IOException {
Scorer scorer = query.weight(this).scorer(reader);
if (scorer == null)
return new TopDocs(0, new ScoreDoc[0]);

final BitSet bits = filter!=null?filter.bits(reader):null;
final HitQueue hq = new HitQueue(nDocs);
final int[] totalHits = new int[1];
scorer.score(new HitCollector() {
public final void collect(int doc, float score) {
if (score > 0.0f &&
(bits==null || bits.get(doc))) {
totalHits[0]++;
hq.insert(new ScoreDoc(doc, score));
}
}
});


ScoreDoc[] scoreDocs = new ScoreDoc[hq.size()];
for (int i = hq.size()-1; i >= 0; i--)
scoreDocs[i] = (ScoreDoc)hq.pop();

return new TopDocs(totalHits[0], scoreDocs);
}
...
}

主干流程是:1.獲取scorer對(duì)象
 Scorer scorer = termQuery.weight.scorer(indexReader)

2.調(diào)用這個(gè)Scorer對(duì)象(此處是TermScorer)的score (Collector)方法.
 scorer.score(new HitCollector() {
...
});

這兩步之后, collector就把hq用查詢結(jié)果填滿了, 而用戶得到的結(jié)果就是從hq中一個(gè)一個(gè)取出的. 這段代碼中, indexReader用于讀取index數(shù)據(jù), 以供查詢使用, Scorer負(fù)責(zé)用查詢結(jié)果把Collector填滿. 問題是,scorer的‘查詢結(jié)果‘從哪里來? 如果IndexReader向Scorer提供數(shù)據(jù), 數(shù)據(jù)內(nèi)容是如何從索引文件中選取的?

Scorer 用一個(gè)匿名類Collector來收集滿足TermQuery的Doc, 但Scorer怎么能夠知道哪些文檔符合Query? 真實(shí)查詢并非在score()方法中進(jìn)行, 從數(shù)據(jù)提取的角度來說, 現(xiàn)代搜索引擎都是從inverted index中提取的滿足Term的文檔列表. 是個(gè)人都知道inverted index里有什么, 由指定的keyword得到所有對(duì)應(yīng)的文檔就是利用inverted index數(shù)據(jù)結(jié)構(gòu)完成的, 這也是搜索過程的核心--一個(gè)延續(xù)了數(shù)百年的索引方法. 我要考察的是, 在這個(gè)新式的OO搜索引擎框架中, 誰(哪個(gè)對(duì)象/類)負(fù)責(zé)提取term對(duì)應(yīng)的記錄, 他怎樣把結(jié)果交給Scorer?

取inverted index是IndexReader的責(zé)任, 這時(shí)已經(jīng)提到過的. 關(guān)于這一點(diǎn)的知識(shí)來自于Lucene手冊(cè)中星星點(diǎn)點(diǎn)的暗示和大量的代碼閱讀, 此處不糾纏這個(gè)問題, 現(xiàn)在關(guān)心的是Scorer和IndexReader怎樣發(fā)生聯(lián)系? 回憶一下上邊的代碼中TermQuery創(chuàng)建Scorer時(shí)用的參數(shù), 正是IndexReader對(duì)象, 動(dòng)動(dòng)腳趾頭也猜得出來TermQuery利用"創(chuàng)建"這種特權(quán)對(duì)score秘密動(dòng)了手腳. 現(xiàn)在瞄一眼weight在構(gòu)造scorer時(shí)玩了什么花樣. 代碼是這樣寫的
public scorer weight#scorer(IndexReader reader){
TermDocs termDocs = reader.termDocs(term);

if (termDocs == null)
return null;

return new TermScorer(this, termDocs, getSimilarity(searcher),
reader.norms(term.field()));
}


class Scorer{
...
public void score(HitCollector hc) throws IOException {
while (next()) {
hc.collect(doc(), score());
}
}
...
public boolean next() throws IOException {
pointer++;
if (pointer >= pointerMax) {
pointerMax = termDocs.read(docs, freqs); // refill buffer
if (pointerMax != 0) {
pointer = 0;
} else {
termDocs.close(); // close stream
doc = Integer.MAX_VALUE; // set to sentinel value
return false;
}
}
doc = docs[pointer];
return true;
}
...
}

可以看出, 上面的問題唯一可能的答案是: weight在構(gòu)造Scorer時(shí)已經(jīng)為Scorer決定了查詢內(nèi)容就在那個(gè)termDocs里. Scorer的代碼也表明, 它在遍歷所有合法文檔時(shí),背后的查詢動(dòng)作是在窮舉一個(gè)數(shù)組:doc[], 而這個(gè)數(shù)組的來源就是TermDocs. 剩下的問題是,TermDoc在整個(gè)查詢中扮演何種角色--它是怎么讀數(shù)據(jù)的

看看TermDoc是個(gè)蝦米東東
reader 創(chuàng)建好TermDoc后調(diào)用TermDoc.seek(term). 這個(gè)方法在硬盤索引文件中找到term所對(duì)應(yīng)的所有文檔記錄, 每條記錄包含文檔id和term在文檔中出現(xiàn)的次數(shù)tf. 這些文檔信息是編制索引時(shí)就建好的, 索引文件中每個(gè)term對(duì)應(yīng)的文檔記錄按順序緊密排列在一起, seek方法能找到這些記錄在索引中的開始位置及滿足term的文檔總數(shù). 以后, TermDoc在scorer中的作用就是讀入每個(gè)符合term的文檔及term在該文檔中的tf, 由于建好了索引只需在索引文件中遍歷即可, termDoc包含的df將用于此過程的遍歷計(jì)數(shù).就是說scorer接收到的那個(gè)termDoc是調(diào)用過seek的, 已經(jīng)定位到了term對(duì)應(yīng)的數(shù)據(jù)位置,這便讓scorer能遍歷termQuery中所有包含那個(gè)term的Doc.

scorer怎樣遍歷全部doc
數(shù)據(jù)又是另一門學(xué)問, 感興趣的人也許研究過讀一個(gè)100M文件,與讀1000個(gè)1K byte文件有何區(qū)別,結(jié)果當(dāng)然是震撼的.只要有可能,盡量讀取整塊數(shù)據(jù)而不是零碎地讀取小數(shù)總不會(huì)讓人失望,然而同樣沒有人會(huì)在構(gòu)造一個(gè)對(duì)象時(shí)就去對(duì)一個(gè)未知大小(可能真的包含100萬個(gè)文檔)的數(shù)據(jù).只要沒收到必要請(qǐng)求,任何人都會(huì)盡力避免這種冗長(zhǎng)的操作. Lucene的設(shè)計(jì)者同樣只是讓在scorer在需要讀入數(shù)據(jù)即第一次調(diào)用next()方法時(shí)調(diào)用termDoc的read方法讀數(shù)據(jù)(代碼中黑體部分).為了避免零碎讀取降低硬盤效率,termDoc.read()會(huì)一次性讀入所有合法文檔(當(dāng)然僅包括文檔id和tf, 建立索引的過程中,這兩個(gè)數(shù)據(jù)一組組的放在專門的文件中,每個(gè)term對(duì)應(yīng)的全部文檔在這個(gè)文件里連續(xù)排列以避免零碎讀取),scorer調(diào)用next ()語句,遍歷read()返回的文檔id數(shù)組,整個(gè)遍歷過程只需把讀出來的doc[i]里的i進(jìn)行++便萬事大吉.

歷過程中發(fā)生什么事情大家心里應(yīng)該很清楚,無非是把這些doc(這就是搜索結(jié)果)一個(gè)個(gè)添加到Collector中. 查詢結(jié)束后, 我們將得到一個(gè)int數(shù)組, 里面保存著每個(gè)結(jié)果文檔的id. 要使用這些查詢結(jié)果,用戶還需要從按照每篇文檔的id文檔庫(kù)中取出結(jié)果, 這些只需調(diào)用searcher.doc(id)即可完成的事務(wù)性過程不在本"技術(shù)"文章討論范圍中.
所謂搜索原來如此簡(jiǎn)單...
本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
索引維護(hù):添加,刪除,修改與維護(hù)
lucene搜索引擎技術(shù)的分析與整理
使用 Apache Lucene 搜索文本 - - JavaEye技術(shù)網(wǎng)站
Lucene 時(shí)間排序
跟我一起云計(jì)算(4)lucene
java搜索引擎lucene學(xué)習(xí)筆記 --水木尤寒的博客
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服