建立索引lucene_用Lucene建立搜索索引
建立索引lucene
本文是我們名為“ Apache Lucene基礎知識 ”的學院課程的一部分。
在本課程中,您將了解Lucene。 您將了解為什么這樣的庫很重要,然后了解Lucene中搜索的工作方式。 此外,您將學習如何將Lucene Search集成到您自己的應用程序中,以提供強大的搜索功能。 在這里查看 !
目錄
1.簡介 2.了解索引操作1.簡介
該索引是利用Lucene的任何組件的核心。 就像書籍的索引一樣,它組織所有數據,以便可以快速訪問。 索引由包含一個或多個字段的文檔組成。 “文檔和字段”可以代表我們選擇的任何內容,但一個常見的隱喻是“文檔”代表數據庫表中的條目,而“字段”類似于表中的字段。
2.了解索引操作
讓我們看一下Lucene搜索索引的圖形表示。
圖1
簡而言之,當Lucene對文檔進行索引時,它會將其分解為許多術語。 然后,它將術語存儲在索引文件中,其中每個術語都與包含該術語的文檔相關聯。 我們可以把它當作一個哈希表。 術語是使用分析器生成的,該分析器將每個單詞的詞根都提取出來。 發出查詢時,將通過用于構建索引的同一分析器來處理該查詢,然后使用該分析器在索引中查找匹配項。 這提供了與查詢匹配的文檔列表。
現在,讓我們看一下整個Lucene搜索過程。
基本概念是索引,文檔,字段和術語。
2.1倒排索引
索引存儲有關術語的統計信息,以使基于術語的搜索更加高效。 Lucene的索引屬于稱為反向索引的索引族。 這是因為它可以長期列出包含它的文檔。 這與自然關系相反,在自然關系中文檔列出了術語。
2.2字段類型
在Lucene中,可以存儲字段,在這種情況下,它們的文本按原樣以非反轉的方式存儲在索引中。 反轉的字段稱為索引。 字段可以被存儲和被索引。
可以將字段的文本標記為要索引的術語,或者可以將字段的文本從字面上用作要索引的術語。 大多數字段都是標記化的,但有時對于某些標識符字段按字面意義進行索引很有用。
2.3細分
Lucene索引可以由多個子索引或段組成。 每個段都是完全獨立的索引,可以分別進行搜索。 索引按以下方式演變:
2.4文件編號
在內部,Lucene通過整數文檔號引用文檔。 添加到索引的第一個文檔編號為零,并且隨后添加的每個文檔的編號都比前一個大。
請注意,文檔編號可能會更改,因此在將這些編號存儲在Lucene之外時應格外小心。 特別是在以下情況下,數字可能會更改:
存儲在每個段中的數字僅在該段內是唯一的,并且必須進行轉換才能在更大的上下文中使用它們。 標準技術是根據該段中使用的數字范圍為每個段分配一個值范圍。 要將文檔編號從段轉換為外部值,需要添加段的基本文檔編號。 要將外部值轉換回特定于細分的值,可以通過外部值所在的范圍來標識細分,然后減去細分的基值。 例如,可以合并兩個五個文檔的段,以便第一個段的基值為零,第二個為五個。 第二段中的文檔3的外部值為8。
刪除文檔后,在編號中會留出空白。 隨著索引通過合并的發展,這些最終被刪除。 合并段時刪除已刪除的文檔。 因此,新合并的段在編號上沒有空白。
2.5搜索索引
搜索索引由javascript函數定義。 它以類似于視圖的地圖功能的方式運行在所有文檔上,并定義了搜索可查詢的字段。 搜索索引是數據庫的一種變體。 它與RDBMS相似,因為它需要快速查找密鑰,但是大部分數據駐留在輔助存儲上。
3.創建索引
到目前為止,我們已經看到了Lucene索引的所有組成部分。 在本節中,我們將使用Lucene索引創建文檔索引。
考慮一個學生在其中提交年度雜志文章的項目。 輸入控制臺包含用于學生姓名,文章標題,文章類別和文章正文的選項。 我們假設該項目正在網絡中運行并且可以通過它進行訪問。 要為這篇文章建立索引,我們將需要文章本身,作者姓名,撰寫日期,文章主題,文章標題以及文件所在的URL。 利用這些信息,我們可以構建一個程序,該程序可以正確索引文章以使其易于查找。
讓我們看一下我們類的基本框架,包括我們將需要的所有導入。
import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.standard.StandardAnalyzer; import org.apache.lucene.index.IndexWriter; import org.apache.lucene.search.IndexSearcher; import org.apache.lucene.search.Query; import org.apache.lucene.queryParser.QueryParser; import org.apache.lucene.search.Hits; import java.util.Date; public class ArticleIndexer { }我們需要添加的第一件事是將文章轉換為Document對象的方法。
為此,我們將使用方法createDocument() ,
private Document createDocument(String article, String author,String title, String topic,String url, Date dateWritten) { Document document = new Document();document.add(Field.Text("author", author));document.add(Field.Text("title", title));document.add(Field.Text("topic", topic));document.add(Field.UnIndexed("url", url));document.add(Field.Keyword("date", dateWritten));document.add(Field.UnStored("article", article));return document;}首先,我們創建一個新的Document對象。 我們需要做的下一步是將文章的不同部分添加到Document 。 我們為每個部分提供的名稱完全是任意的,并且像HashMap鍵一樣工作。 使用的名稱必須是String 。 Document的add方法將采用一個Field對象,該對象是使用Field類提供的靜態方法之一構建的。 提供了四種將Field對象添加到Document的方法。
Field.Keyword –數據已存儲并建立索引,但未標記化。 這對于應保留不變的數據(例如日期)最有用。 實際上,Field.Keyword可以將Date對象作為輸入。
Field.Text –數據被存儲,索引和標記化。 Field.Text字段不應用于諸如文章本身之類的大量數據,因為索引將變得非常大,因為它將包含文章的完整副本以及標記化的版本。
Field.UnStored –不存儲數據,但對其進行索引和標記化。 大量的數據(如文章的文本)應放置在未存儲的索引中。
Field.UnIndexed –數據已存儲但未建立索引或標記化。 它與要與搜索結果一起返回的數據一起使用,但實際上不會在該數據上進行搜索。 在我們的示例中,由于我們不允許搜索URL,因此沒有理由對其進行索引,但是我們希望在找到搜索結果后將其返回給我們。
現在我們有了一個Document對象,我們需要獲得一個IndexWriter來將此Document寫入索引。
String indexDirectory = "lucene-index"; private void indexDocument(Document document) throws Exception {Analyzer analyzer = new StandardAnalyzer();IndexWriter writer = new IndexWriter(indexDirectory, analyzer, false);writer.addDocument(document);writer.optimize();writer.close();}我們首先創建一個StandardAnalyzer ,然后使用分析器創建一個IndexWriter 。 在構造函數中,我們必須指定索引將駐留的目錄。 構造函數末尾的布爾值告訴IndexWriter是創建新索引還是添加到現有索引。 在將新文檔添加到現有索引時,我們將指定false。 然后,我們將Document添加到索引。 最后,我們優化然后關閉索引。 如果要添加多個Document對象,則應始終進行優化,然后在將所有Document對象都添加到索引之后關閉索引。
現在,我們只需要添加一種將各個部分組合在一起的方法即可。
為了驅動索引??操作,我們將編寫一個indexArticle()一些參數的方法indexArticle() 。
public void indexArticle(String article, String author,String title, String topic,String url, Date dateWritten)throws Exception {Document document = createDocument(article, author,title, topic,url, dateWritten);indexDocument(document);}對文章運行此操作會將該文章添加到索引中。 將IndexWriter構造函數中的布爾值更改為true會創建一個索引,因此我們應該在第一次創建索引以及每次要從頭開始重建索引時使用它。 現在我們已經構建了索引,我們需要在索引中搜索文章。
索引存儲為單個目錄中的一組文件。
索引由任意數量的獨立段組成,這些段存儲有關已索引文檔子集的信息。 每個段都有自己的術語詞典,術語詞典索引和文檔存儲(存儲的字段值)。 所有段數據都存儲在_xxxxx.cfs文件中,其中xxxxx是段名稱。
創建索引段文件后,將無法對其進行更新。 新文檔將添加到新段中。 刪除的文檔僅在可選的.del文件中標記為已刪除。
4.基本索引操作
索引數據
Lucene讓我們可以以文本格式索引任何可用數據。 Lucene可以用于幾乎所有數據源,只要可以從中提取文本信息即可。 我們可以使用Lucene索引和搜索存儲在HTML文檔,Microsoft Word文檔,PDF文件等中的數據。 索引數據的第一步是使其以簡單文本格式可用。 可以使用自定義解析器和數據轉換器。
索引過程
索引編制是將文本數據轉換為便于快速搜索的格式的過程。 一個簡單的類比是您在書末找到的索引:該索引將您指向書中出現的主題的位置。
Lucene將輸入數據存儲在稱為反向索引的數據結構中,該結構作為一組索引文件存儲在文件系統或內存中。 大多數Web搜索引擎使用反向索引。 它使用戶可以執行快速的關鍵字查找,并找到與給定查詢匹配的文檔。 在將文本數據添加到索引之前,它需要由分析器處理(使用分析過程)。
分析
分析將文本數據轉換為基本搜索單位,稱為術語。 在分析過程中,文本數據將經歷多個操作:提取單詞,刪除常用單詞,忽略標點符號,將單詞簡化為根形式,將單詞更改為小寫字母等。分析僅在建立索引和查詢解析之前進行。 分析將文本數據轉換為標記,并將這些標記作為術語添加到Lucene索引中。
Lucene帶有各種內置分析器,例如SimpleAnalyzer , StandardAnalyzer , StopAnalyzer , SnowballAnalyzer等。 這些不同之處在于它們標記文本和應用過濾器的方式。 由于分析會在建立索引之前刪除單詞,因此會減小索引大小,但會對查詢處理的精度產生負面影響。 您可以使用Lucene提供的基本構建塊來創建自定義分析器,從而對分析過程進行更多控制。 表1顯示了一些內置分析儀及其處理數據的方式。
4.1核心索引類
目錄
表示索引文件存儲位置的抽象類。 通常主要使用兩個子類:
FSDirectory —目錄的實現,在實際的文件系統中存儲索引。 這對于大索引很有用。
RAMDirectory —將所有索引存儲在內存中的實現。 這適用于較小的索引,這些索引可以完全加載到內存中,并在應用程序終止時銷毀。 由于索引保存在內存中,因此速度相對較快。
分析儀
如上所述,分析器負責預處理文本數據并將其轉換為存儲在索引中的令牌。 IndexWriter接受用于對數據建立索引之前對其進行標記化的分析器。 要正確索引文本,您應該使用適合需要索引的文本語言的分析器。
默認分析器適用于英語。 Lucene沙箱中還有其他幾種分析器,包括中文,日文和韓文的分析器。
IndexDeletionPolicy
用于實現自定義從索引目錄中刪除過時提交的策略的接口。 默認的刪除策略是KeepOnlyLastCommitDeletionPolicy ,該策略僅保留最新的提交,并在完成新提交后立即刪除所有先前的提交。
索引作家
創建或維護索引的類。 它的構造函數接受一個布爾值,該布爾值確定是創建新索引還是打開現有索引。 它提供了添加,刪除或更新索引中文檔的方法。
最初對索引所做的更改將存儲在內存中,并定期刷新到索引目錄中。 IndexWriter公開了幾個字段,這些字段控制索引在內存中的緩沖方式以及如何將其寫入磁盤。 除非調用IndexWriter的commit或close方法,否則對IndexReader不到對索引所做的更改。 IndexWriter為目錄創建一個鎖定文件,以防止索引同時更新導致索引損壞。 IndexWriter允許用戶指定可選的索引刪除策略。
4.2將數據添加到索引
將文本數據添加到索引涉及兩個類。
字段表示在搜索中查詢或檢索的一條數據。 Field類封裝一個字段名稱及其值。 Lucene提供了一些選項來指定是否需要對字段進行索引或分析以及是否需要存儲其值。 在創建字段實例時可以傳遞這些選項。 下表顯示了字段元數據選項的詳細信息。
| 選項 | 描述 |
| Field.Store.Yes | 用于存儲字段的值。 適用于顯示搜索結果的字段,例如文件路徑和URL。 |
| Field.Store.No | 字段值未存儲-例如,電子郵件正文。 |
| Field.Index.No | 適用于未搜索的字段-通常與存儲的字段一起使用,例如文件路徑。 |
| Field.Index.ANALYZED | 用于索引但未分析的字段。 它完整??保留了字段的原始值,例如日期和個人名稱。 |
| Field.Index.NOT_ANALYZED | 用于索引但未分析的字段。 它完整??保留了字段的原始值,例如日期和個人名稱。 |
字段元數據選項的詳細信息
而文檔是字段的集合。 Lucene還支持增強文檔和字段,如果要重視某些索引數據,這是一個有用的功能。 為文本文件建立索引包括將文本數據包裝在字段中,創建文檔,使用字段填充文本,以及使用IndexWriter將文檔添加到索引中。
5.文件和領域
如您先前所見,文檔是索引和搜索過程的單元。
5.1文件
文檔是一組字段。 每個字段都有一個名稱和一個文本值。 字段可以與文檔一起存儲,在這種情況下,它會隨文檔的搜索命中一起返回。 因此,每個文檔通常應包含一個或多個唯一標識它的存儲字段。
您將文檔添加到索引,并且在執行搜索之后,您將獲得結果列表,它們是文檔。 文檔只是字段的非結構化集合。
5.2領域
字段是Lucene.net的實際內容所有者:它們基本上是一個哈希表,具有名稱和值。 如果我們有無限的磁盤空間和無限的處理能力,那就是我們所需要知道的。 但是不幸的是,磁盤空間和處理能力受到限制,因此您不能僅僅分析所有內容并將其存儲到索引中。 但是Lucene.net提供了將字段添加到索引的不同方法。
Lucene提供了四種不同類型的字段供開發人員選擇: Keyword , UnIndexed , UnStored和Text 。 您應該使用哪種字段類型取決于您要如何使用該字段及其值。
關鍵字字段未標記,但被逐字索引并存儲在索引中。 此字段適用于應完整保留原始值的字段,例如URL,日期,個人姓名,社會保險號,電話號碼等。
未索引字段既沒有標記也沒有索引,但它們的值存儲在逐字索引中。 該字段適用于需要與搜索結果一起顯示但絕不會直接搜索其值的字段。 由于未對該類型的字段編制索引,因此對其進行搜索很慢。 由于此類型的字段的原始值存儲在索引中,因此如果存在索引大小的問題,則此類型不適合存儲值非常大的字段。
未存儲字段與未索引字段相反。 此類型的字段已標記并建立索引,但未存儲在索引中。 此字段適用于索引大量不需要以其原始形式檢索的文本,例如網頁正文或任何其他類型的文本文檔。
文本字段被標記,索引并存儲在索引中。 這意味著可以搜索這種類型的字段,但是請注意存儲為“文本”字段的字段的大小。
如果您回顧一下LuceneIndexExample類,您將看到我使用了Text字段:
document.add(Field.Text("fieldname", text));如果要更改字段fieldname的類型,我們將調用Field類的其他方法之一:
document.add(Field.Keyword("fieldname", text));要么
document.add(Field.UnIndexed("fieldname", text));要么
document.add(Field.UnStored("fieldname", text));盡管Field.Text , Field.Keyword , Field.UnIndexed和Field.UnStored調用最初看起來像是對構造函數的調用,但實際上它們只是對不同Field類方法的調用。 表1總結了不同的字段類型。
| 現場方法/類型 | 代幣化 | 索引 | 已儲存 |
| Field.Keyword(String, String) | 沒有 | 是 | 是 |
| Field.UnIndexed(String, String) | 沒有 | 沒有 | 是 |
| Field.UnStored(String, String) | 是 | 是 | 沒有 |
| Field.Text(String, String) | 是 | 是 | 是 |
| Field.Text(String, Reader) | 是 | 是 | 沒有 |
表1:不同字段類型的概述。
5.3在Lucene中增強文檔
在信息檢索中,文檔與搜索的相關性通過與查詢的相似程度來衡量。 Lucene中實現了幾種相似性模型,您可以通過擴展相似性類并使用Lucene保存的索引統計信息來實現自己的相似性模型。 還可以為文檔分配靜態分數,以表示它們在整體語料庫中的重要性,而與正在執行的查詢無關,例如其受歡迎程度,評分或PageRank。
在Lucene 4.0之前,您可以通過調用document.setBoost為文檔分配靜態分數。 在內部,通過將字段的提升因子乘以文檔的提升因子,將提升應用于文檔的每個字段。 但是,這永遠無法正常工作,并且取決于所執行查詢的類型,可能根本不會影響文檔的排名。
通過在Lucene中添加DocValues,增強文檔就像添加NumericDocValuesField并將其用于CustomScoreQuery一樣簡單, CustomScoreQuery將計算所得的分數乘以“ boost”字段的值。 下面的代碼示例說明了如何實現此目的:
// add two documents to the index Document doc = new Document(); doc.add(new TextField("f", "test document", Store.NO)); doc.add(new NumericDocValuesField("boost", 1L)); writer.addDocument(doc); doc = new Document(); doc.add(new TextField("f", "test document", Store.NO)); doc.add(new NumericDocValuesField("boost", 2L)); writer.addDocument(doc); // search for 'test' while boosting by field 'boost' Query baseQuery = new TermQuery(new Term("f", "test")); Query boostQuery = new FunctionQuery(new LongFieldSource("boost")); Query q = new CustomScoreQuery(baseQuery, boostQuery); searcher.search(q, 10);通過編寫一個簡單的公式,新的Expressions模塊也可以用于增強文檔,如下所示。 盡管比使用CustomScoreQuery更為冗長,但它通過計算更復雜的公式(例如sqrt(_score)+ ln(boost))來提高效率。
Expression expr = JavascriptCompiler.compile("_score * boost"); SimpleBindings bindings = new SimpleBindings(); bindings.add(new SortField("_score", SortField.Type.SCORE)); bindings.add(new SortField("boost", SortField.Type.LONG)); Sort sort = new Sort(expr.getSortField(bindings, true)); searcher.search(baseQuery, null, 10, sort);既然Lucene允許在不重新索引文檔的情況下更新NumericDocValuesField ,您就可以將頻繁變化的字段(受歡迎程度,評分,價格,最后修改時間…)合并到提升因素中,而無需每次對其中任何一個更改時都重新索引文檔。
翻譯自: https://www.javacodegeeks.com/2015/09/building-a-search-index-with-lucene.html
建立索引lucene
總結
以上是生活随笔為你收集整理的建立索引lucene_用Lucene建立搜索索引的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: lucene 查询示例_Lucene查询
- 下一篇: 海贼王为什么画风突变_什么是突变测试?