日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Lucene3.5自学4--建索引相关知识总结

發布時間:2023/12/20 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Lucene3.5自学4--建索引相关知识总结 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Lucene簡單介紹(該部分摘自網絡)

Lucene是一個高效的,基于Java的全文檢索庫。

所以在了解Lucene之前要費一番工夫了解一下全文檢索。

那么什么叫做全文檢索呢?這要從我們生活中的數據說起。

我們生活中的數據總體分為兩種:結構化數據和非結構化數據。

  • 結構化數據:指具有固定格式或有限長度的數據,如數據庫,元數據等。
  • 非結構化數據:指不定長或無固定格式的數據,如郵件,word文檔等。

當然有的地方還會提到第三種,半結構化數據,如XMLHTML等,當根據需要可按結構化數據來處理,也可抽取出純文本按非結構化數據來處理。

非結構化數據又一種叫法叫全文數據。

?

按照數據的分類,搜索也分為兩種:

  • 對結構化數據的搜索:如對數據庫的搜索,用SQL語句。再如對元數據的搜索,如利用windows搜索對文件名,類型,修改時間進行搜索等。
  • 對非結構化數據的搜索:如利用windows的搜索也可以搜索文件內容,Linux下的grep命令,再如用Google和百度可以搜索大量內容數據。

對非結構化數據也即對全文數據的搜索主要有兩種方法:

一種是順序掃描法(Serial?Scanning):所謂順序掃描,比如要找內容包含某一個字符串的文件,就是一個文檔一個文檔的看,對于每一個文檔,從頭看到尾,如果此文檔包含此字符串,則此文檔為我們要找的文件,接著看下一個文件,直到掃描完所有的文件。如利用windows的搜索也可以搜索文件內容,只是相當的慢。如果你有一個80G硬盤,如果想在上面找到一個內容包含某字符串的文件,不花他幾個小時,怕是做不到。Linux下的grep命令也是這一種方式。大家可能覺得這種方法比較原始,但對于小數據量的文件,這種方法還是最直接,最方便的。但是對于大量的文件,這種方法就很慢了。

有人可能會說,對非結構化數據順序掃描很慢,對結構化數據的搜索卻相對較快(由于結構化數據有一定的結構可以采取一定的搜索算法加快速度),那么把我們的非結構化數據想辦法弄得有一定結構不就行了嗎?

這種想法很天然,卻構成了全文檢索的基本思路,也即將非結構化數據中的一部分信息提取出來,重新組織,使其變得有一定結構,然后對此有一定結構的數據進行搜索,從而達到搜索相對較快的目的。

這部分從非結構化數據中提取出的然后重新組織的信息,我們稱之索引。

這種說法比較抽象,舉幾個例子就很容易明白,比如字典,字典的拼音表和部首檢字表就相當于字典的索引,對每一個字的解釋是非結構化的,如果字典沒有音節表和部首檢字表,在茫茫辭海中找一個字只能順序掃描。然而字的某些信息可以提取出來進行結構化處理,比如讀音,就比較結構化,分聲母和韻母,分別只有幾種可以一一列舉,于是將讀音拿出來按一定的順序排列,每一項讀音都指向此字的詳細解釋的頁數。我們搜索時按結構化的拼音搜到讀音,然后按其指向的頁數,便可找到我們的非結構化數據——也即對字的解釋。

這種先建立索引,再對索引進行搜索的過程就叫全文檢索(Full-text?Search)

?

下面這幅圖來自《Lucene?in?action》,但卻不僅僅描述了Lucene的檢索過程,而是描述了全文檢索的一般過程。

??

全文檢索大體分兩個過程,索引創建(Indexing)和搜索索引(Search)。

  • 索引創建:將現實世界中所有的結構化和非結構化數據提取信息,創建索引的過程。
  • 搜索索引:就是得到用戶的查詢請求,搜索創建的索引,然后返回結果的過程

詳情可以參考http://forfuture1978.iteye.com/blog/546771?

Lucene3.5?建立索引總結

Lucene的索引結構是有層次結構的,主要分以下幾個層次:

  • 索引(Index)
    • Lucene中一個索引是放在一個文件夾中的。
    • 如上圖,同一文件夾中的所有的文件構成一個Lucene索引。
  • (Segment)
    • 一個索引可以包含多個段,段與段之間是獨立的,添加新文檔可以生成新的段,不同的段可以合并。
    • 如上圖,具有相同前綴文件的屬同一個段,圖中共兩個段?"_0"?和?"_1"。
    • segments.gen和segments_5是段的元數據文件,也即它們保存了段的屬性信息。
  • 文檔(Document)
    • 文檔是我們建索引的基本單位,不同的文檔是保存在不同的段中的,一個段可以包含多篇文檔。
    • 新添加的文檔是單獨保存在一個新生成的段中,隨著段的合并,不同的文檔合并到同一個段中。
  • (Field)
    • 一篇文檔包含不同類型的信息,可以分開索引,比如標題,時間,正文,作者等,都可以保存在不同的域里。
    • 不同域的索引方式可以不同,在真正解析域的存儲的時候,我們會詳細解讀。
  • (Term)
    • 詞是索引的最小單位,是經過詞法分析和語言處理后的字符串。

(一)Field相當于數據庫表的字段

1.其中的Field(字段或域)的構造方法有以下幾種

Field(String?name,?boolean?internName,?String?value,?Field.Store?store,?Field.Index?index,?Field.TermVector?termVector)?常用的

Field(String?name,?byte[]?value)?

Field(String?name,?byte[]?value,?int?offset,?int?length)?

Field(String?name,?Reader?reader)?

Field(String?name,?Reader?reader,?Field.TermVector?termVector)?該Reader當在值是從文件中讀取很長的數據時用,單身磁盤I/O操作太多效率太低了

Field(String?name,?String?value,?Field.Store?store,?Field.Index?index)

Field(String?name,?String?value,?Field.Store?store,?Field.Index?index,?Field.TermVector?termVector)?

Field(String?name,?TokenStream?tokenStream)?

Field(String?name,?TokenStream?tokenStream,?Field.TermVector?termVector)?

l?其中?Field.Store表示是否存儲,值分別為YES?,NO

l??Field.Index?表示是否索引(允許檢索),它已經包括了是否分詞,其值有以下幾種

ANALYZED?分詞并索引
??????????Index?the?tokens?produced?by?running?the?field's?value?through?an?Analyzer.

ANALYZED_NO_NORMS?分詞索引?但是禁用存儲規范
??????????Expert:?Index?the?tokens?produced?by?running?the?field's?value?through?an?Analyzer,?and?also?separately?disable?the?storing?of?norms.

NO??不索引,當然肯定不會去分詞
??????????Do?not?index?the?field?value.

NOT_ANALYZED?索引但不會分詞
??????????Index?the?field's?value?without?using?an?Analyzer,?so?it?can?be?searched.

NOT_ANALYZED_NO_NORMS?不索引?同時禁用存儲規范

?

l?Field.TermVector?表示對Field詞條向量是否進行存儲,(具體什么意思我也還沒弄明白)其值有以下幾種

NO??不存儲詞條向量
??????????Do?not?store?term?vectors.

WITH_OFFSETS?存儲詞條和其偏移量
??????????Store?the?term?vector?+?Token?offset?information

WITH_POSITIONS?存儲詞條和其位置
??????????Store?the?term?vector?+?token?position?information

WITH_POSITIONS_OFFSETS?存儲詞條和?詞條偏移量及其位置
??????????Store?the?term?vector?+?Token?position?and?offset?information

YES?存儲每個document的詞條向量

???????Store?the?term?vectors?of?each?document.

2.document:簡單的說就像數據庫中的一條記錄,它的每個字段就是Field。注意:數據庫中你建立了字段,所有的記錄具有相同記錄,即數據庫是以字段為主導的;而Lucene是以document為主導的,同一個索引(相當于數據庫中一張表)中不同的document是可以不一樣的。下面介紹docuemnt常用幾種方法:

add(Fieldable?field)?將一個Field?加入document,注意Field是實現了Fieldable接口的類

get(String?name)?返回當前docuement指定Field名的Field

getBoost()?返回索引時設置的加權因子(具體到底是什么沒搞明白)
??????????Returns,?at?indexing?time,?the?boost?factor?as?set?by?setBoost(float).

getFieldable(String?name)?看英語吧,這個很簡單
??????????Returns?a?field?with?the?given?name?if?any?exist?in?this?document,?or?null.

getFieldables(String?name)??看英語吧,這個很簡單,只不過返回的是多個
??????????Returns?an?array?of?Fieldables?with?the?given?name.

getFields()?
??????????Returns?a?List?of?all?the?fields?in?a?document.

getFields(String?name)?
??????????Deprecated.?use?getFieldable(java.lang.String)?instead?and?cast?depending?on?data?type.

getValues(String?name)?返回指定Field名的Field值的數組
??????????Returns?an?array?of?values?of?the?field?specified?as?the?method?parameter.

removeField(String?name)?移除當前document的指定的Field?
??????????Removes?field?with?the?specified?name?from?the?document.

removeFields(String?name)?移除多個Field
??????????Removes?all?fields?with?the?given?name?from?the?document.

setBoost(float?boost)?
??????????Sets?a?boost?factor?for?hits(詞條)?on?any?field?of?this?document.

toString()?
??????????Prints?the?fields?of?a?document?for?human?consumption.

(三)、AnalyzerLucene的分析工具,無論是建立索引還是搜索過程,該類是一個抽象類,所以網上常用適合Lucene的分詞器都是它的繼承,例如用Lucene自帶的StandardAnalyzer;如?Analyzer?analyzer?=?new?StandardAnalyzer(Version.LUCENE_35)?

?

(四)IndexWriter?他是建立索引的類,至于該類如何實現建立索引請參考前面的文章

IndexWriter.setMaxFieldLength(int)表示索引數據時對數據源的最大長度進行現在,如設置為100,則表示?取數據源前100個長度進行索引分析,當然存儲是全都存儲,當然長度不足100的就全都索引。

l?、一個索引可以有多個segment(段),但一個索引目錄里只有一個segments(該文件記錄了所有的segmet);一個segment有多個document(可以設置最大值),同一個segment在磁盤上各種物理的文件的前綴是相同的:如圖


其中?

l?.frq?記錄的是詞條頻率信息,

l?.prx記錄的詞條的未知信息,

l?.fnm記錄了所有Field的信息,

l?.fdt/.fdx?

  • 域數據文件(fdt):
    • 真正保存存儲域(stored?field)信息的是fdt文件
    • 在一個段(segment)中總共有segment?size篇文檔,所以fdt文件中共有segment?size個項,每一項保存一篇文檔的域的信息
    • 對于每一篇文檔,一開始是一個fieldcount,也即此文檔包含的域的數目,接下來是fieldcount個項,每一項保存一個域的信息。
    • 對于每一個域,fieldnum是域號,接著是一個8位的byte,最低一位表示此域是否分詞(tokenized),倒數第二位表示此域是保存字符串數據還是二進制數據,倒數第三位表示此域是否被壓縮,再接下來就是存儲域的值,比如new?Field("title",?"lucene?in?action",?Field.Store.Yes,?),則此處存放的就是"lucene?in?action"這個字符串。
  • 域索引文件(fdx)
    • 由域數據文件格式我們知道,每篇文檔包含的域的個數,每個存儲域的值都是不一樣的,因而域數據文件中segment?size篇文檔,每篇文檔占用的大小也是不一樣的,那么如何在fdt中辨別每一篇文檔的起始地址和終止地址呢,如何能夠更快的找到第n篇文檔的存儲域的信息呢?就是要借助域索引文件。
    • 域索引文件也總共有segment?size個項,每篇文檔都有一個項,每一項都是一個long,大小固定,每一項都是對應的文檔在fdt文件中的起始地址的偏移量,這樣如果我們想找到第n篇文檔的存儲域的信息,只要在fdx中找到第n項,然后按照取出的long作為偏移量,就可以在fdt文件中找到對應的存儲域的信息。

l?詞典文件(tis)

  • TermCount:詞典中包含的總的詞數
  • IndexInterval:為了加快對詞的查找速度,也應用類似跳躍表的結構,假設IndexInterval4,則在詞典索引(tii)文件中保存第4個,第8個,第12個詞,這樣可以加快在詞典文件中查找詞的速度。
  • SkipInterval:倒排表無論是文檔號及詞頻,還是位置信息,都是以跳躍表的結構存在的,SkipInterval是跳躍的步數。
  • MaxSkipLevels:跳躍表是多層的,這個值指的是跳躍表的最大層數。
  • TermCount個項的數組,每一項代表一個詞,對于每一個詞,以前綴后綴規則存放詞的文本信息(PrefixLength?+?Suffix),詞屬于的域的域號(FieldNum),有多少篇文檔包含此詞(DocFreq),此詞的倒排表在frqprx中的偏移量(FreqDelta,?ProxDelta),此詞的倒排表的跳躍表在frq中的偏移量(SkipDelta),這里之所以用Delta,是應用差值規則。

l?詞典索引文件(tii)

  • 詞典索引文件是為了加快對詞典文件中詞的查找速度,保存每隔IndexInterval個詞。
  • 詞典索引文件是會被全部加載到內存中去的。
  • IndexTermCount?=?TermCount?/?IndexInterval:詞典索引文件中包含的詞數。
  • IndexInterval同詞典文件中的IndexInterval。
  • SkipInterval同詞典文件中的SkipInterval
  • MaxSkipLevels同詞典文件中的MaxSkipLevels。
  • IndexTermCount個項的數組,每一項代表一個詞,每一項包括兩部分,第一部分是詞本身(TermInfo),第二部分是在詞典文件中的偏移量(IndexDelta)。假設IndexInterval4,此數組中保存第4個,第8個,第12個詞...

l?標準化因子文件(nrm)

為什么會有標準化因子呢?從第一章中的描述,我們知道,在搜索過程中,搜索出的文檔要按與查詢語句的相關性排序,相關性大的打分(score)高,從而排在前面。相關性打分(score)使用向量空間模型(Vector?Space?Model),在計算相關性之前,要計算Term?Weight,也即某Term相對于某Document的重要性。在計算Term?Weight時,主要有兩個影響因素,一個是此Term在此文檔中出現的次數,一個是此Term的普通程度。顯然此Term在此文檔中出現的次數越多,此Term在此文檔中越重要。

這種Term?Weight的計算方法是最普通的,然而存在以下幾個問題:

  • 不同的文檔重要性不同。有的文檔重要些,有的文檔相對不重要,比如對于做軟件的,在索引書籍的時候,我想讓計算機方面的書更容易搜到,而文學方面的書籍搜索時排名靠后。
  • 不同的域重要性不同。有的域重要一些,如關鍵字,如標題,有的域不重要一些,如附件等。同樣一個詞(Term),出現在關鍵字中應該比出現在附件中打分要高。
  • 根據詞(Term)在文檔中出現的絕對次數來決定此詞對文檔的重要性,有不合理的地方。比如長的文檔詞在文檔中出現的次數相對較多,這樣短的文檔比較吃虧。比如一個詞在一本磚頭書中出現了10次,在另外一篇不足100字的文章中出現了9次,就說明磚頭書應該排在前面碼?不應該,顯然此詞在不足100字的文章中能出現9次,可見其對此文章的重要性。

由于以上原因,Lucene在計算Term?Weight時,都會乘上一個標準化因子(Normalization?Factor),來減少上面三個問題的影響。

標準化因子(Normalization?Factor)是會影響隨后打分(score)的計算的,Lucene的打分計算一部分發生在索引過程中,一般是與查詢語句無關的參數如標準化因子,大部分發生在搜索過程中,會在搜索過程的代碼分析中詳述。

標準化因子(Normalization?Factor)在索引過程總的計算如下:

?

它包括三個參數:

  • Document?boost:此值越大,說明此文檔越重要。
  • Field?boost:此域越大,說明此域越重要。
  • lengthNorm(field)?=?(1.0?/?Math.sqrt(numTerms)):一個域中包含的Term總數越多,也即文檔越長,此值越小,文檔越短,此值越大。

從上面的公式,我們知道,一個詞(Term)出現在不同的文檔或不同的域中,標準化因子不同。比如有兩個文檔,每個文檔有兩個域,如果不考慮文檔長度,就有四種排列組合,在重要文檔的重要域中,在重要文檔的非重要域中,在非重要文檔的重要域中,在非重要文檔的非重要域中,四種組合,每種有不同的標準化因子。

(五)索引優化,合并策略,以前的版本中通過合并因子Mergefactor以及maxMergegeDocs都是通過IndexWriter來設置的,在3.5版本中這些方法都過時了,現在這些優化方法都集成到MergePolicy(一個抽象類),所以索引優化時可以用如下方法來設置
MergePolicy?me?=?new?LogMergePolicy()該類繼承MergePolicy;?然后通過IndexWriterConfig調用setMergePolicy(MergePolicy?mergePolicy)??來設置,然后通過3.5版本中IndexWriter的唯一推薦的構造方法IndexWriter(Directory?d,?IndexWriterConfig?conf)??來設置,其他構造方法都過時了。
(六)、IndexReader類,該類主要負責索引的操作,如讀取,修改,刪除操作,具體可以參考http://xiaozu.renren.com/xiaozu/258210/336375170?,很代碼已經詳細說明了。

轉載于:https://www.cnblogs.com/qingfeideyi/archive/2012/03/04/2379526.html

總結

以上是生活随笔為你收集整理的Lucene3.5自学4--建索引相关知识总结的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。