這篇文章將為大家詳細(xì)講解有關(guān)怎樣解析Lucene查詢?cè)?,文章?nèi)容質(zhì)量較高,因此小編分享給大家做個(gè)參考,希望大家閱讀完這篇文章后對(duì)相關(guān)知識(shí)有一定的了解。
創(chuàng)新互聯(lián)是一家專注于成都做網(wǎng)站、網(wǎng)站建設(shè)與策劃設(shè)計(jì),祥符網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)10多年,網(wǎng)設(shè)計(jì)領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:祥符等地區(qū)。祥符做網(wǎng)站價(jià)格咨詢:028-86922220
Lucene 是一個(gè)基于 Java 的全文信息檢索工具包,目前主流的搜索系統(tǒng)Elasticsearch和solr都是基于lucene的索引和搜索能力進(jìn)行。想要理解搜索系統(tǒng)的實(shí)現(xiàn)原理,就需要深入lucene這一層,看看lucene是如何存儲(chǔ)需要檢索的數(shù)據(jù),以及如何完成高效的數(shù)據(jù)檢索。
在數(shù)據(jù)庫中因?yàn)橛兴饕拇嬖?,也可以支持很多高效的查詢操作。不過對(duì)比lucene,數(shù)據(jù)庫的查詢能力還是會(huì)弱很多,本文就將探索下lucene支持哪些查詢,并會(huì)重點(diǎn)選取幾類查詢分析lucene內(nèi)部是如何實(shí)現(xiàn)的。為了方便大家理解,我們會(huì)先簡單介紹下lucene里面的一些基本概念,然后展開lucene中的幾種數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),理解了他們的存儲(chǔ)原理后就可以方便知道如何基于這些存儲(chǔ)結(jié)構(gòu)來實(shí)現(xiàn)高效的搜索。本文重點(diǎn)關(guān)注是lucene如何做到傳統(tǒng)數(shù)據(jù)庫較難做到的查詢,對(duì)于分詞,打分等功能不會(huì)展開介紹。
Lucene中包含了四種基本數(shù)據(jù)類型,分別是:
Index:索引,由很多的Document組成。
Document:由很多的Field組成,是Index和Search的最小單位。
Field:由很多的Term組成,包括Field Name和Field Value。
Term:由很多的字節(jié)組成。一般將Text類型的Field Value分詞之后的每個(gè)最小單元叫做Term。
在lucene中,讀寫路徑是分離的。寫入的時(shí)候創(chuàng)建一個(gè)IndexWriter,而讀的時(shí)候會(huì)創(chuàng)建一個(gè)IndexSearcher,
下面是一個(gè)簡單的代碼示例,如何使用lucene的IndexWriter建索引以及如何使用indexSearch進(jìn)行搜索查詢。
Analyzer analyzer = new StandardAnalyzer(); // Store the index in memory: Directory directory = new RAMDirectory(); // To store an index on disk, use this instead: //Directory directory = FSDirectory.open("/tmp/testindex"); IndexWriterConfig config = new IndexWriterConfig(analyzer); IndexWriter iwriter = new IndexWriter(directory, config); Document doc = new Document(); String text = "This is the text to be indexed."; doc.add(new Field("fieldname", text, TextField.TYPE_STORED)); iwriter.addDocument(doc); iwriter.close(); // Now search the index: DirectoryReader ireader = DirectoryReader.open(directory); IndexSearcher isearcher = new IndexSearcher(ireader); // Parse a simple query that searches for "text": QueryParser parser = new QueryParser("fieldname", analyzer); Query query = parser.parse("text"); ScoreDoc[] hits = isearcher.search(query, 1000).scoreDocs; //assertEquals(1, hits.length); // Iterate through the results: for (int i = 0; i < hits.length; i++) { Document hitDoc = isearcher.doc(hits[i].doc); System.out.println(hitDoc.get("fieldname")); } ireader.close(); directory.close();
從這個(gè)示例中可以看出,lucene的讀寫有各自的操作類。本文重點(diǎn)關(guān)注讀邏輯,在使用IndexSearcher類的時(shí)候,需要一個(gè)DirectoryReader和QueryParser,其中DirectoryReader需要對(duì)應(yīng)寫入時(shí)候的Directory實(shí)現(xiàn)。QueryParser主要用來解析你的查詢語句,例如你想查 “A and B",lucene內(nèi)部會(huì)有機(jī)制解析出是term A和term B的交集查詢。在具體執(zhí)行Search的時(shí)候指定一個(gè)最大返回的文檔數(shù)目,因?yàn)榭赡軙?huì)有過多命中,我們可以限制單詞返回的最大文檔數(shù),以及做分頁返回。
下面會(huì)詳細(xì)介紹一個(gè)索引查詢會(huì)經(jīng)過幾步,每一步lucene分別做了哪些優(yōu)化實(shí)現(xiàn)。
在lucene中查詢是基于segment。每個(gè)segment可以看做是一個(gè)獨(dú)立的subindex,在建立索引的過程中,lucene會(huì)不斷的flush內(nèi)存中的數(shù)據(jù)持久化形成新的segment。多個(gè)segment也會(huì)不斷的被merge成一個(gè)大的segment,在老的segment還有查詢?cè)谧x取的時(shí)候,不會(huì)被刪除,沒有被讀取且被merge的segement會(huì)被刪除。這個(gè)過程類似于LSM數(shù)據(jù)庫的merge過程。下面我們主要看在一個(gè)segment內(nèi)部如何實(shí)現(xiàn)高效的查詢。
為了方便大家理解,我們以人名字,年齡,學(xué)號(hào)為例,如何實(shí)現(xiàn)查某個(gè)名字(有重名)的列表。
docid | name | age | id |
---|---|---|---|
1 | Alice | 18 | 101 |
2 | Alice | 20 | 102 |
3 | Alice | 21 | 103 |
4 | Alan | 21 | 104 |
5 | Alan | 18 | 105 |
在lucene中為了查詢name=XXX的這樣一個(gè)條件,會(huì)建立基于name的倒排鏈。以上面的數(shù)據(jù)為例,倒排鏈如下:
姓名
Alice | [1,2,3]
---- | --- |
Alan | [4,5]
如果我們還希望按照年齡查詢,例如想查年齡=18的列表,我們還可以建立另一個(gè)倒排鏈:
18 | [1,5]
---| --- |
20 | [2]
21 | [3,4]
在這里,Alice,Alan,18,這些都是term。所以倒排本質(zhì)上就是基于term的反向列表,方便進(jìn)行屬性查找。到這里我們有個(gè)很自然的問題,如果term非常多,如何快速拿到這個(gè)倒排鏈呢?在lucene里面就引入了term dictonary的概念,也就是term的字典。term字典里我們可以按照term進(jìn)行排序,那么用一個(gè)二分查找就可以定為這個(gè)term所在的地址。這樣的復(fù)雜度是logN,在term很多,內(nèi)存放不下的時(shí)候,效率還是需要進(jìn)一步提升??梢杂靡粋€(gè)hashmap,當(dāng)有一個(gè)term進(jìn)入,hash繼續(xù)查找倒排鏈。這里hashmap的方式可以看做是term dictionary的一個(gè)index。 從lucene4開始,為了方便實(shí)現(xiàn)rangequery或者前綴,后綴等復(fù)雜的查詢語句,lucene使用FST數(shù)據(jù)結(jié)構(gòu)來存儲(chǔ)term字典,下面就詳細(xì)介紹下FST的存儲(chǔ)結(jié)構(gòu)。
我們就用Alice和Alan這兩個(gè)單詞為例,來看下FST的構(gòu)造過程。首先對(duì)所有的單詞做一下排序?yàn)椤癆lice”,“Alan”。
插入“Alan”
http://weahome.cn/article/gicdco.html