<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    Jason ---分享,共同進步

    激情成就夢想,努力創(chuàng)造未來
    隨筆 - 53, 文章 - 1, 評論 - 45, 引用 - 0
    數(shù)據(jù)加載中……

    lucene 搜索技術(shù)簡介

    lucene 全文檢索簡介

    一,信息檢索的過程簡介

    全文檢索和數(shù)據(jù)庫應(yīng)用最大的不同在于:讓最相關(guān)的頭100條結(jié)果滿足98%以上用戶的需求
    1,構(gòu)建文本庫
    在開發(fā)功能前,一個信息檢索系統(tǒng)需要做些準(zhǔn)備工作,首先,必須要構(gòu)建一個文本數(shù)據(jù)庫,這個文本數(shù)據(jù)庫用來保存所有用戶可能檢索的信息。在這些信息的基礎(chǔ)上,確定索引中

    的文本類型,文本類型是被系統(tǒng)所認(rèn)可的一種信息格式,這種格式應(yīng)當(dāng)具有可識別,冗余程度低的特點。一旦文本模型確定下來后,就不應(yīng)當(dāng)對其進行大的行動。
    2,建立索引
    有了這種文本模型后,就應(yīng)該根據(jù)數(shù)據(jù)庫內(nèi)的文本建立索引。索引可以大大的提高信息檢索的速度。目前,有許多索引的建立方式。采用哪種方式取決于信息檢索系統(tǒng)的規(guī)模。大
    型信息檢索系統(tǒng)(百度,google這樣的搜索)均采用倒排的方式來建立索引。
    3,進行搜索
    在文檔建立索引之后,就可以開始對其進行搜索。這時,通常都是由用戶提交一個檢索請求,請求將被分析,然后利用文本操作進行處理。對于真實的信息檢索系統(tǒng),在真正處理
    請求前,還可以對請求進行一些預(yù)處理,然后再將請求送到后臺,并返回用戶需要的信息。
    4,對結(jié)果進行過濾
    通常,在信息檢索系統(tǒng)檢索到用戶需要的信息后,還要做一步操作,就是將信息以一定的規(guī)則進行排序或過濾,再返回給用戶。這一步實際上關(guān)乎到最終用戶的體驗。

    二,Lucene 索引

       1,使用索引提高檢索速度
    常用的3種索引方式為
    (1)倒排
    倒排是一種面向單詞的索引機制。通常它由(關(guān)鍵字)和出現(xiàn)情況兩部分組成。對于索引中的每個詞(關(guān)鍵字),都跟隨一個列表(位置表),用來記錄單詞在所有文檔中出現(xiàn)的
    位置。
     倒排的特點:
    在倒排索引中,關(guān)鍵字的數(shù)量并非隨著文本內(nèi)容的增長也線性增長。這是因為無論多大數(shù)量的文本數(shù)據(jù)庫,總能夠規(guī)范出一個關(guān)鍵字表。這種關(guān)鍵字受到實際語言因素的限制,他
    的增長率在文本數(shù)據(jù)庫達(dá)到一定規(guī)模后可以忽略不計。

    (2)后綴數(shù)組

    (3)簽名文件

      2,索引的Segment

    每個segment代表lucene的一個完整索引段,通常,一個索引中,包含有多個segment,每個segment都有一個統(tǒng)一的前綴,這個前綴是根據(jù)當(dāng)前索引的document的數(shù)量而確立的,前
    綴名是document 數(shù)量轉(zhuǎn)成36進制后,在前面加上“_”而構(gòu)成的。

    segment的格式
    (1).fnm格式
    包含了document中的所有field的名稱。
    (2).fdx 和.fdt格式
    .fdx 和.fdt是綜合使用的兩個文件,其中.fdt類型文件用于存儲具有store.YES屬性的field的數(shù)據(jù)。而.fdx類型文件則是一個索引,用于存儲document在.fdt中的位置。

    (3).tii 與.tis格式
    .tis 文件用于存儲分詞的詞條(Term),而.tii就是它的索引文件,它標(biāo)明了每個.tis文件的詞條的位置。
    (4).cfs復(fù)合格式
    在indexWriter 中有一個屬性:useCompoundFile,它的默認(rèn)值為True,這個屬性的含義是:是否使用復(fù)合索引格式來保存索引。索引的內(nèi)容可能非常大,文件的數(shù)量可能非常多,
    如果遇到這種情況,系統(tǒng)打開文件數(shù)量巨大將會極大地耗費系統(tǒng)資源。因此, lucene提供了一種簡單文件索引格式,也就是所謂的復(fù)合索引格式。

       3,索引的優(yōu)化

     (1)合并因子mergeFactor

    當(dāng)mergeFactor取比較小的值時,內(nèi)存中注入的文檔數(shù)量少,向磁盤寫入segment的操作比較多,故此時將占用較少的內(nèi)存,但是索引的建立由于i/o操作頻繁所以會比較慢.而當(dāng)mergeFactor取較大的值時,內(nèi)存中駐留的document數(shù)量比較多.向磁盤寫入segment的操作較少,故此時將占用較多的內(nèi)存,但索引的建立速度比較快.

    maxMergeDocs
    對索引的合并的最多文檔數(shù)量.
    mixMergeDocs(maxBufferedDocs)

      (2)索引的合并與索引的優(yōu)化

    FSDirectory 和 RAMDirectory目錄文件

    FSDirectory 是與文件系統(tǒng)目錄有關(guān)的,而RAMDirectory則是與內(nèi)存相關(guān)的。
    對于lucene 來說,兩中目錄都可以作為索引的存儲路徑。在初始化indexwriter的時候需要傳入一個directory類型的對象作為參數(shù)之一,當(dāng)indexwriter接收這樣的參數(shù)時(無論
    是fsdirectory還是ramdirectory),它都會在指定的位置下將索引進行存儲。但是文件系統(tǒng)目錄就會直接將索引寫到磁盤上。而ramdirectory則是在內(nèi)存中一個區(qū)域,雖然向其中添加document的過程與使用fsdirectory一樣,但是由于它是內(nèi)存中的一塊區(qū)域,因此如果不將ramdirectory中的內(nèi)存寫入磁盤,當(dāng)虛擬機退出后,里面的內(nèi)容也會隨之消失。因此,需要將ramdirectory中的內(nèi)容轉(zhuǎn)到fsdirectory中。

        (3)使用indexWriter來合并索引
    document可以被放置在 ramdirectory中,使用它的優(yōu)點就是索引的速度很快。當(dāng)document被加入到ramdirectory中后, ramdirectory在邏輯上就是一個完整的索引了,它在邏輯
    上就應(yīng)當(dāng)包括如前所說的所有索引格式的文件(但是不能被持久的保存起來)。
    indexwriter的addindexs()方法,可以實現(xiàn)索引的合并。addindexs()方法的參數(shù)是一個directory類型的數(shù)組,因此,可以同時合并多個目錄下的索引,只要分別為這些目錄創(chuàng)建
    其對應(yīng)的directory類型的對象就可以了。

        (4)索引的優(yōu)化
    indexwriter的optimize()方法正是為了這個目的而設(shè)置的,該方法能夠?qū)Ξ?dāng)前indexwriter所制定的索引目錄以及其所使用的緩存目錄下的所有segment 進行優(yōu)化,使所有的
    segments合并成一個完整的segement,即整個索引目錄內(nèi)出現(xiàn)一種文件前綴。
    對于系統(tǒng)的優(yōu)化會有什么性能上的損失呢?由于優(yōu)化時需要對已有的索引內(nèi)的文件進行操作,因此需要耗費更多的內(nèi)存和磁盤空間,索引優(yōu)化采用的策略是建立新的segment來取代
    那些被合并的segements,所以在舊的segement還未被刪除之前,索引內(nèi)的磁盤空間消耗將會非常大,甚至可能使原來索引的兩倍。同理,在進行優(yōu)化時的磁盤i/o也會非常多,所以這是一個耗費資源的過程。

        2,索引中刪除文檔

    索引的讀取工具IndexReader,IndexReader中的getVersion方法可以查看當(dāng)前索引的版本,這個version是索引建立時的精確到毫秒的時間,IndexReader的indexReader.numDosc()方法,可以查看當(dāng)前索引內(nèi)總共有多少個document,IndexReader.document(int)方法可以從索引中取出相應(yīng)的document.

         (1)使用文檔的id號來刪除特定文檔

    在創(chuàng)建索引的過程中 lucene會為每一個加入索引的document賦予一個id號,這個id號將唯一的標(biāo)識每個文檔.reader.deleteDocument(int),int參數(shù)為id 號刪除完畢后需要執(zhí)行reader.close()方法關(guān)閉.使刪除操作寫入索引的deletable文件中,如果不關(guān)閉怎沒有刪除掉,實際上lucene的刪除機制為回收站機制,刪除操作沒有真正刪除文件,而是做了一標(biāo)記,可以進行還原;reader.undeleteall()方法可以幫助實現(xiàn)反刪除(當(dāng)使用indexwriter對索引optimize一次時,lucene 為每個document重新分配id,這樣那些被標(biāo)記為已刪除的document真正的被物理刪除了).

        (2)使用field信息來刪除批量文檔
    reader.deleteDocuments(term)該方法是一個能夠批量刪除索引的方法,它刪除索引是按照詞條來進行的. term類是用于表示詞條的一個工具,它能夠?qū)⒃~條表示成<field,value>(
    例如: 詞條為<bookename,男>也就是indexReader就會刪除所有在"bookname"這個field中含有"男"這個term的document).

      3, lucene的同步問題

    writer.lock
    出現(xiàn)在向索引中添加文檔時,或是將文檔從索引中刪除時,在indexwriter的close()方法被調(diào)用時被釋放
    commit.lock
    主要是與segment合并和讀取的操作相關(guān).

      indexModifier類

        三,lucene 的搜索 

        1,indexSearcher進行搜索

         (1)indexSearcher的簡單使用:
            indexSearcher searcher=new IndexSearcher("索引路徑");
            //構(gòu)建一個term對象
            Term term=new Term("name","女")
            //構(gòu)建一個query對象
            Query q =new TermQuery (term);
            //檢索
            Hits hits=searcher.search(q);
            //顯示結(jié)果
            for(int i=0;i<hits.lengtth();i++){
                system.out.println(hits.doc(i));
            }

        上面的例子中介紹了indexsearcher的search方法,search方法是整個檢索系統(tǒng)的核心。
    indexSearcher有多種重載search方法,這些方法有些在于indexSearcher的父類Search中,有些在本身,Search類實現(xiàn)了一個接口Searchable,該接口提供了可以搜索的功能。

        (2)Hits對象是搜索結(jié)果的集合 主要有下面幾個方法 [list=1]

    length() ,這個方法記錄有多少條結(jié)果返回(lazy loading)
    doc(n) 返回第n個記錄
    id(in) 返回第n個記錄的Document ID
    score(n) 第n個記錄的相關(guān)度(積分)
    由于搜索的結(jié)果一般比較大,從性能上考慮,Hits對象并不會真正把所有的結(jié)果全部取回,默認(rèn)情況下是保留前100個記錄(對于一般的搜索引擎,100個記錄足夠了).
     

    hits類,在上面的例子中使用了hits,從Hits的doc(int n)方法來研究Hits的工作原理.
    doc(int n)方法用于搜索索引的返回結(jié)果中取出相應(yīng)的文檔。參數(shù)n代表結(jié)果中的第n個文檔。而doc(int n)方法的第一步就是使用hitDoc(int n)方法從緩存中取去相應(yīng)的文檔。
    在hitDoc(int n)方法中,會先判斷當(dāng)前用戶需要取出的文檔是不是已經(jīng)超過了緩存的大小。如果是,則先調(diào)用getMoreDocs(int min)方法來擴大緩存,然后再從緩存中返回需要的
    文檔。

         2,搜索結(jié)構(gòu)的評分

        (1)文檔的得分算法公式:略
            搜索的結(jié)果可以按照分?jǐn)?shù)來排序。

        3,lucene內(nèi)建的query對象
    (1) 內(nèi)建的query對象主要包括:
    (2)TermQuery詞條搜索 
    (3) BooleanQuery布爾搜索 
    (4)RangeQuery范圍搜索 
    (5) PrefixQuery前綴搜索 
    (6) PhraseQuery短語搜索 
    (7)MultiPhraseQuery多短語搜索 
    (8)FuzzyQuery模糊搜索 
    (9)WildcardQuery通配符搜索 
    (10)SpanQuery跨度搜索  
    (11)還有第三方提供的Query對象:RegexQuery
    上面的這些內(nèi)建的query對象都是可以用來做根據(jù)不同的情況來進行搜索。(具體略)

        4,Lucene查詢總結(jié):

    Lucene面向全文檢索的優(yōu)化在于首次索引檢索后,并不把所有的記錄(Document)具體內(nèi)容讀取出來,而起只將所有結(jié)果中匹配度最高的頭100條結(jié)果(TopDocs)的ID放到結(jié)果集
    緩存中并返回,這里可以比較一下數(shù)據(jù)庫檢索:如果是一個10,000條的數(shù)據(jù)庫檢索結(jié)果集,數(shù)據(jù)庫是一定要把所有記錄內(nèi)容都取得以后再開始返回給應(yīng)用結(jié)果集的。所以即使檢索匹配總數(shù)很多,Lucene的結(jié)果集占用的內(nèi)存空間也不會很多。對于一般的模糊檢索應(yīng)用是用不到這么多的結(jié)果的,頭100條已經(jīng)可以滿足90%以上的檢索需求。

    如果首批緩存結(jié)果數(shù)用完后還要讀取更后面的結(jié)果時Searcher會再次檢索并生成一個上次的搜索緩存數(shù)大1倍的緩存,并再重新向后抓取。所以如果構(gòu)造一個Searcher去查1-120條結(jié)果,Searcher其實是進行了2次搜索過程:頭100條取完后,緩存結(jié)果用完,Searcher重新檢索再構(gòu)造一個200條的結(jié)果緩存,依此類推,400條緩存,800條緩存。由于每次Searcher對象消失后,這些緩存也訪問那不到了,你有可能想將結(jié)果記錄緩存下來,緩存數(shù)盡量保證在100以下以充分利用首次的結(jié)果緩存,不讓Lucene浪費多次檢索,而且可以分級進行結(jié)果緩存。

    Lucene的另外一個特點是在收集結(jié)果的過程中將匹配度低的結(jié)果自動過濾掉了。這也是和數(shù)據(jù)庫應(yīng)用需要將搜索的結(jié)果全部返回不同之處.

      四,排序、過濾、分頁

        1, 自然排序

    相關(guān)度排序是一種最簡單的排序方式,所謂相關(guān)度,其實就是文檔的得分。
    searcher的explain方法可以每一個文檔的得分是怎么樣的算出來的,他們的idf,tf,lengthNorm的值得情況。如:searcher.explain(q,hits.id(i).toString());
     通過改變boost值來改變文檔的得分在進行相關(guān)度排序的時候,如果想人為的增加某個文檔的相關(guān)度,使其在搜索的結(jié)構(gòu)中排在考前的位置上,可以使用boost。
    如:索引寫入document 的時,在寫入之前,使用document方法(document.setBoost(3f))
    原理:在lucene中,文檔的boost的值一般情況默認(rèn)為1.0,但當(dāng)某個文檔的boost值大于1.0后,所有的文檔boost值均會除以這個最大值,以此來為每個文檔獲取一個小于1.0的數(shù)
    作為新的boost值。

      2,使用Sort來排序

    Sort是lucene自帶的一個排序工具,通過它,可以方便地對檢索結(jié)果進行排序。
    Sort所提供的排序功能是以field為基礎(chǔ)的,也就是說,最終的排序準(zhǔn)則,總是以某個field(或多個)的值為基礎(chǔ),經(jīng)過這樣的處理,最終的排序就轉(zhuǎn)變成對所有文檔中同一個
    field(或多個field)的值的排序。方法:Sort(String field,boolean reverse),field表示參照制定的field排序,第二個參數(shù)reverse 表示排序的順序,升序還是降序(reverse的默認(rèn)值為false,升序排序)。
    SortField是一個包裝類型,通過它的包裝,可以使Sort類清楚地了解要進行排序的field的各種信息。
    構(gòu)造函數(shù)(略)
    按文檔的內(nèi)部id號來排序
    如:Hits hits=searcher.search(q,Sort.INDEXORDER);
    這個內(nèi)部需要是在建立索引的時候自動創(chuàng)建的。
    按一個或多個Field來排序
    如:Sort sort=new Sort();//定義一個Sort對象
    SortField f=new SortField("bookno",SortField.INT,false);//定義SortField對象,同時是按照bookno升序來排序的。
    sort.setSort(f);
    //下面就可以查找排序了.

      3,搜索的過濾器

    lucene 中有兩種過濾器,一個是搜索時的過濾器,一個是分析的過濾.
    搜索時的過濾是一種減小搜索范圍的方式.同時也可以實現(xiàn)一種安全機制,即保護某些文檔無法被檢索.
    搜索時的過濾器來自于一個抽象基類Filter,它定義了過濾器的基本行為
    public abstract BitSet bits(IndexReader reader);可以看到,這個方法返回一個bitSet類型的對象,filter是一種過濾行為,這種過濾行為在搜索時的表現(xiàn)就是"視而不見" ,即遇
    到該文檔時,發(fā)現(xiàn)它被"過濾"了,于是就忽略它,BitSet是一種"位集合"隊列,這個隊列中的每個元素都只有兩種取值,即true或false,這倆種值代表文檔是否被過濾,也就是說,返回結(jié)果時,會首先遍歷BitSet盡將那些對應(yīng)值為true的文檔返回。在BitSet集合中,將其索引號看作是文檔的內(nèi)部id。
    lucene中內(nèi)置了幾個Filter,
    RangeFilter(范圍過濾,詳細(xì)略)
    QueryFilter(重要)在結(jié)果中查詢
    實際應(yīng)用:在filter的行為可以看到,它總是在搜索前,首先對索引進行一次遍歷,然后返回一個被業(yè)務(wù)邏輯處理好的BitSet對象,這種做法無可厚非,但是卻存在很嚴(yán)重的性能

    問題,這相當(dāng)于對索引進行了兩次遍歷,這樣會降低性能。
    CachingWrapppeFilter將一個Filter作為構(gòu)造函數(shù)的參數(shù)傳入,在需要使用原Filter的地方,將這個CachingWrapppeFilter的對象傳入,就可以在原來的filter進行過濾了。
    CachingWrapppeFilter的原理: 其中使用了緩存,在調(diào)用的時候,查看緩存中是否存在處理的結(jié)構(gòu),如果存在,則直接取出后返回,如果沒有執(zhí)行被注入的Filter.

        4,Lucene翻頁

     (1)依賴于session的翻頁
    是指將搜索的結(jié)果存儲于session中,用戶翻頁的時候就從session中取出hits集合,這種方式簡單不需要什么算法,一次查詢就可以獲得結(jié)果,但是這樣很容易造成服務(wù)器的內(nèi)存
    溢出。
     (2)多次查詢
    使用完全無狀態(tài)保持的開發(fā)方式,即用戶每次翻頁,都對索引進行重新檢索,然后取得當(dāng)前頁的結(jié)果并返回。
     (3)緩存+多次查詢
    使用session方式的查詢有內(nèi)存問題,但是如果采用完全無狀態(tài)的查詢方式,又會出現(xiàn)磁盤i/o太過頻繁的問題,以致降低了效率。可以采用在session或者內(nèi)存中其他空間,另外在
    緩存一部分結(jié)果,比如后5頁10頁等,這樣當(dāng)進行翻頁的時候,就可以從緩存中取出內(nèi)容,不用重新查索引,如果沒有緩存,則重新查詢,更新緩存。
       (4)緩存+多次查詢+數(shù)據(jù)庫
    這種方式是在上面的基礎(chǔ)上增加的,如果索引的量很大可以考慮把內(nèi)容多的東西放在數(shù)據(jù)庫中,索引中的id和數(shù)據(jù)庫庫中的id同步。


    搜索時的過濾器可以自己定義.

        5,lucene的分析器

    信息檢索所要處理的主要對象就是信息,在實際應(yīng)用中,大部分時候信息是以一種文本的方式呈現(xiàn)的。而信息檢索的第一件事,就是要對這種文本進行分析,以便能夠繼續(xù)下面的處理。
        (1) 分詞
    分詞就是將一段文本拆分成多個詞。(需要注意的一點是,在建立索引時使用的分詞工具,與在分析用戶的檢索請求時使用的分詞工具應(yīng)當(dāng)是同一個)。

         (2)分詞器的結(jié)構(gòu)
    一個標(biāo)準(zhǔn)的分詞器是由兩部分組成,一部分是分詞器,被稱為Tokenizer;另一部分是過濾器,被稱為TokenFilter。一個分析器往往是由一個分詞器和多個過濾器組成。這里所說的過濾器,與前面所說的檢索時使用的過濾器完全是不同的兩個概念。此處的Filter主要是用于對用戶切出來的詞進行一些處理,如去掉一些敏感詞、轉(zhuǎn)換大小寫、轉(zhuǎn)換單復(fù)數(shù)等。
    lucene內(nèi)部提供了過濾器,StandarFilter,StopFilter,LowerCaseFilter

    (待續(xù).........................................)

    posted on 2008-05-06 10:08 agun 閱讀(1293) 評論(0)  編輯  收藏 所屬分類: 搜索技術(shù)


    只有注冊用戶登錄后才能發(fā)表評論。


    網(wǎng)站導(dǎo)航:
    博客園   IT新聞   Chat2DB   C++博客   博問  
     
    主站蜘蛛池模板: 亚洲线精品一区二区三区影音先锋| 欧洲乱码伦视频免费| 免费a级毛片无码a∨蜜芽试看| 久久精品亚洲乱码伦伦中文| 337p日本欧洲亚洲大胆人人| 久久久久免费看黄A片APP| 97se亚洲综合在线| 无人在线观看免费高清| 亚洲亚洲人成综合网络| xxxxx做受大片视频免费| 国产免费资源高清小视频在线观看| 亚洲中文字幕人成乱码| 日韩免费无码一区二区三区 | 亚洲aⅴ无码专区在线观看春色| h视频在线观看免费网站| 婷婷亚洲久悠悠色悠在线播放| 中国在线观看免费的www| 亚洲国产成人久久精品99 | 中文字幕在线免费看线人| 亚洲国产成人综合| 30岁的女人韩剧免费观看| 国产成人99久久亚洲综合精品| 亚洲精品无码午夜福利中文字幕| 无遮挡a级毛片免费看| 国产一级高清免费观看| 国产亚洲精品91| 亚洲高清无码在线观看| 日韩在线视频免费| mm1313亚洲精品国产| 产传媒61国产免费| 亚洲精品无码Av人在线观看国产| 男女一进一出抽搐免费视频| 中文字幕日韩亚洲| 拍拍拍无挡视频免费观看1000| 国产成人亚洲综合无码精品| 日本免费人成网ww555在线| 亚洲色大成网站www永久| 欧洲精品成人免费视频在线观看| 亚洲熟妇无码AV| 国产免费牲交视频| 一本一道dvd在线观看免费视频|