lucene简介_Lucene简介
lucene簡介
本文是我們名為“ Apache Lucene基礎知識 ”的學院課程的一部分。
在本課程中,您將了解Lucene。 您將了解為什么這樣的庫很重要,然后了解Lucene中搜索的工作方式。 此外,您將學習如何將Lucene Search集成到您自己的應用程序中,以提供強大的搜索功能。 在這里查看 !
目錄
1.簡介1.簡介
在本課程中,我們將深入探討Apache Lucene。 Lucene是一款功能豐富的開源全文搜索工具。 這意味著Lucene將幫助您實現針對您的應用程序需求量身定制的全文搜索引擎。 我們將處理Lucene的Java風格,但請記住,存在用于各種編程語言的API客戶端。
1.1什么是全文搜索
用戶通常需要檢索與某些條件匹配的文檔或來源列表。 例如,圖書館用戶需要能夠找到特定作者撰寫的所有書籍。 或所有書名中帶有特定單詞或短語的書籍。 或在特定年份從特定出版商發行的所有書籍。 上面的查詢可以通過眾所周知的關系數據庫輕松地處理。 如果您擁有一個存儲(元組, 標題,作者,出版者,出版年)元組的表,則可以有效地完成上述搜索。 現在,如果用戶想要獲取在其實際內容中包含某個單詞或短語的所有文檔,該怎么辦? 如果您嘗試使用傳統數據庫并將所有文檔的原始內容存儲在元組的字段中,那么搜索將花費不可接受的時間。
那是因為在全文搜索中 ,搜索引擎必須掃描文本文檔或一般文本流中的所有單詞 ,并嘗試針對它匹配多個條件,例如查找其內容中的某些單詞或短語。 傳統的關系數據庫中的此類查詢將毫無希望。 當然,許多數據庫系統(例如MySQL和PostgreSQL)都支持全文搜索,無論是本機搜索還是使用外部庫。 但這效率不高,速度不夠快或無法自定義。 但是最大的問題是可伸縮性。 他們只是無法處理全文搜索引擎可以處理的數據量。
1.2為什么我們需要全文搜索引擎
生成大量數據的過程是我們這個時代的主要特征之一,也是技術進步的主要結果。 它被稱為信息過載 。 話雖如此,只有當您能夠從中提取有用的信息,并使應用程序的最終用戶可以訪問這些信息時,收集和存儲所有這些數據才有用。 當然,最著名和最常用的工具就是搜索。
有人可能會爭辯說,在文件中搜索單詞或短語就像從上到下以串行方式掃描文件一樣簡單,就像使用grep命令一樣。 實際上,這可能只需要少量的文檔。 但是,擁有數百萬個文件的巨大文件系統又如何呢?如果這對您而言似乎非同尋常,那么網頁,數據庫,電子郵件,代碼存儲庫,僅舉幾例,將它們全部結合在一起,又如何呢? 容易理解的是,每個用戶所需的信息可能駐留在一個小小的文檔中,位于大量不同信息資源的某個地方。 而且該文檔的檢索必須像呼吸一樣容易。
現在可以看到為什么完全定制的基于搜索的應用程序越來越受到關注和吸引。 更重要的是,搜索已成為最終用戶體驗的一個重要方面,以至于對于現代Web應用程序(從簡單的博客到Twitter或Facebook之類的大型平臺,甚至是軍用級應用程序)來說,沒有搜索功能都是不可理解的。 這就是為什么大型供應商不想冒險將其搜索功能弄亂,并希望保持它們盡可能快而又簡單的原因。 這導致需要將搜索從簡單功能升級到完整平臺。 具有強大,高效,必要的靈活性和定制性的平臺。 而Apache Lucene提供了,這就是為什么在上述大多數應用程序中都使用它的原因。
1.3 Lucene的工作方式
因此,您一定想知道Lucene如何執行快速的全文本搜索。 毫不奇怪,答案是它使用了index 。 Lucene索引屬于倒排索引的類別。 倒置索引不是在每個文檔中都包含其包含的單詞(或術語 )完整列表的經典索引,而是相反。 對于文檔中的每個術語 (單詞),您都有包含該術語的所有文檔的列表。 當執行全文搜索時,這非常方便。
下圖顯示了反向索引如此之好的原因。 假設您有3個非常大的文件。 經典索引的格式如下:
經典索引:
Document1 -> { going, to, dive, into, Apache, Lucene, rich, open , source , full, text, search,... } Document2 -> { so, must, wonder, Lucene, can, achieve, very, fast, full, text, search, not,... } Document3 -> { reason, that, inverted, index, work, good ,can, be, seen, following, diagrams,... }對于每個文檔,都有一個包含所有術語的龐大列表。 為了查找文檔是否包含特定術語,您必須進行掃描,可能是順序掃描這些龐大的列表。
另一方面,反向索引將具有以下形式:
倒排索引:
reason -> { (3,0} } Lucene -> { (1,6), (2,4) } full -> { (1,10),(2,9) } going -> { (1,0) } index -> { (3,3) } search -> { (1,11), (2,10)} ...對于每個術語,我們維護一個包含該術語的所有文檔的列表,然后是該術語在文檔中的位置(當然,可以保留其他信息)。 現在,當用戶搜索術語“ Lucene”時,我們可以立即回答,術語“ Lucene”位于文檔1的位置6的位置和文檔2的位置4的位置??偠灾?#xff0c;倒排索引使用大量可以立即搜索的小清單。 相反,經典索引將使用少量無法快速搜索的非常大的列表。
1.4基本Lucene工作流程
因此,Lucene必須在實際搜索之前完成一些工作。 大概就是創建索引。 索引過程的基本工作流程如下所示:
如上圖所示:
到目前為止,Lucene似乎是一個非常強大的工具,因為它可以分析文本,創建索引并對該索引執行查詢。 但是您必須自己做一些工作,例如選擇要建立索引的文檔,組織和管理整個過程以及過程的多個方面,以及最終從用戶那里獲得搜索查詢并向他們提供任何可能的結果。
2.索引的基本組件
在本節中,我們將描述用于創建索引的基本組件和基本Lucene類。
2.1目錄
Lucene索引僅托管在普通文件系統位置,或在需要額外性能且您不希望將其永久存儲在驅動器上時存儲在內存中。 您甚至可以選擇通過JDBC將索引存儲在數據庫中。 前述選項的實現擴展了抽象Directory類。
為了簡單起見,我們只說它使用了文件系統中的目錄,盡管使用內存或數據庫時并沒有太多區別,但是我認為普通目錄更加直觀。 Lucene將使用該目錄存儲索引所需的所有內容。 您可以使用FSDirectory類使用這樣的目錄,并為它提供文件系統的任意路徑(使用內存時,使用RAMDirectory )。 FSDirectory類只是普通Java File操作類之上的抽象。
這是創建FSDirectory :
Directory directory = FSDirectory.open( new File( "C:/Users/nikos/Index" ));這就是創建RAMDirectory :
Directory ramDirectory = new RAMDirectory();2.2文件
如您所記得,我們說過,您有責任選擇文檔(文本文件,PDF,Word文檔等)以及您要搜索的所有文本源,然后對其進行索引。 對于要索引的每個文檔,必須創建一個代表該Document對象。 在這一點上,重要的是要了解文檔是索引組件,而不是實際的文本源。 自然,由于Document代表單個物理文本源,因此它是索引的構建單元。 創建此類文檔后,您必須將其添加到索引中。 稍后,在調度搜索時,結果將得到一個滿足查詢條件的Document對象的列表。
這樣可以創建一個新的空Document :
Document doc = new Document();現在是時候用Fields填充Document了。
2.3領域
Document對象填充有Fields的集合。 一個Field只是一對(名稱,值)項。 因此,當創建一個新的Document對象時,必須用這種對來填充它。 Field可以存儲在索引中,在這種情況下,字段的名稱和值都按字面意義存儲在索引中。 另外,可以對Field進行索引 ,或者更精確地說,可以對字段進行倒置 ,在這種情況下,該字段的值將被分析并標記為Terms ,并且可以進行搜索。 Term表示來自Field值文本的單詞。 Field既可以被存儲又可以被索引/取反 ,但是您不必存儲一個字段就可以對其進行索引/取反。 存儲字段和對字段建立索引/取反是兩個不同的獨立事物。
如前所述,在部署搜索時,作為回報,您將獲得一個滿足查詢條件的Document對象列表(代表物理文本源)。 如果要訪問Field的實際值,則必須聲明該Field存儲。 當您要存儲本Document代表的文件名,上次修改日期,完整文件路徑或有關您要訪問的文本源的任何其他信息時,這通常很有用。 例如,如果您正在索引的文本源是電子郵件,則表示該電子郵件的Document對象可以具有以下字段:
代表電子郵件的示例文檔:
領域 | 已儲存 | 索引 | |
名稱 | 值 | ||
標題 | 來自示例的電子郵件 | 是 | 沒有 |
位置 | 電子郵件位置 | 是 | 沒有 |
從 | example@javacodegeeks.com | 是 | 沒有 |
至 | foo@example.com | 是 | 沒有 |
學科 | 通訊 | 是 | 沒有 |
身體 | 嗨,您好 ! 很高興見到你… | 沒有 | 是 |
在以上文檔中,我選擇了對電子郵件的正文進行索引/反轉,但不進行存儲。 這意味著將對電子郵件的正文進行分析并將其標記為可搜索的術語,但實際上不會將其存儲在索引中。 當文本源的內容量很大并且要節省空間時,可以采用這種策略。 另一方面,我選擇存儲而不是索引所有其他字段。 當我執行搜索時,將僅搜索正文 ,而搜索中未考慮所有其他字段,因為它們沒有被索引。
如果Body的上述切分項符合查詢,這個Document將被包括在結果中。 現在,當您訪問檢索到的Document ,您只能查看其存儲的Fields及其值。 因此,盡管可以搜索,但文件的實際主體將無法通過Document對象提供給您。 您只能看到標題,位置,從,到主題 Fields 。 存儲該電子郵件的位置,將有助于我訪問其實際正文內容。 當然,如果要通過Document對象檢索電子郵件的主體,從而使其既可搜索又可存儲(其他字段也是如此),則也可以存儲電子郵件的主體。
因此,讓我們看看如何創建上述Document 。 要創建僅存儲的字段,我們將使用StoredField類。 為了創建文本的未存儲和索引主體,我們將使用TextField類。
領域如您所見,我們給了FileReader作為"body"字段的值。 在分析階段中將使用此FileReader ,以從該源中提取純文本。 從文件中提取純文本后,Lucene的特殊組件將對其進行分析并將其拆分為索引詞。
2.4條款
術語表示文本中的單詞。 術語是從Fields值的分析和標記化中提取的,因此Term是搜索的單位。 術語由兩個元素組成,實際的文字單詞(可以從文字到電子郵件地址,日期等的任何形式)以及該單詞出現的字段的名稱。
標記和分析字段以從中提取術語并不是絕對必要的。 在上一個示例中,如果要對“ From Field索引,則不必真正將其標記化。 電子郵件地址example@javacodegeeks.com可以用作Term 。
2.5分析儀
Analyzer是索引和搜索過程中最關鍵的組件之一。 它負責獲取純文本并將其轉換為可搜索的術語。 現在,重要的是要了解分析器可以使用純文本輸入。 提供一個解析器以將文本源(例如HTML頁面或文件系統中的文件)轉換為純文本,是程序員的責任。 該解析器通常是Reader。 例如,如果是文件,則可以是FileReader。
分析器內部使用Tokenizer 。 令牌生成器可以將上述閱讀器用作輸入,并使用它從特定來源(例如文件)中提取純文本。 在獲得純文本之后,令牌生成器將文本簡單地拆分為單詞。 但是,分析器可以做的不僅僅是簡單的文本拆分。 它可以執行多種文本和單詞分析,例如:
- 詞干:用詞干代替詞。 例如,在英語中,“橙色”的詞干是“橙色”。 因此,如果最終用戶搜索“橙色”,則將獲得包含“橙色”和“橙色”的文檔。
- 停用詞過濾:執行搜索時,諸如“ the”,“ and”和“ a”之類的詞沒有特別的意義,因此不妨將其視為“噪音”。 刪除它們將導致更好的性能和更準確的結果。
- 文本規范化:刪除重音符號和其他字符標記。
- 同義詞擴展:在與當前單詞相同的標記位置添加同義詞。
這些只是Lucenes Analyzer類內置的一些分析工具。 分析器中最常用的內置工具是StandardAnalyzer ,它可以刪除停用詞,將單詞轉換為小寫字母并進行詞干處理。 如您所知,不同的語言有不同的語法規則。 Lucene社區正在嘗試為盡可能多的不同語言嵌入盡可能多的語法。 但是,如果Lucene的內置分析儀都不適合您的應用程序,則可以創建自己的分析儀。
2.6與索引互動
到目前為止,我們已經看到了如何創建索引Directory ,創建Document并向其添加Fields 。 現在,我們必須將Document寫入Directory ,然后將其添加到索引。 這也是步驟,其中Analyzers和Tokenizers發揮自己的部分。
正如您所期望的那樣,在Lucene中沒有稱為Index (或類似的東西)的特殊類。 與索引進行交互的方式是通過IndexWriter ,當您要將內容推送到索引(并通常對其進行操作)時,通過IndexReader從索引中讀取內容,以及通過IndexSearcher ,當您要搜索索引時課程。
現在,讓我們看看如何創建所需的IndexWriter :
領域我們選擇為此使用StandardAnalyzer實例。 其構造函數將Version.LUCENE_46作為參數。 這有助于發現多個Lucene版本之間的兼容性依賴性。 請記住, StandardAnalyzer在內部使用StandardTokenizer 。 然后,我們創建一個IndexWriterConfig實例。 這是一個幫助程序類,可以保存IndexWriter所有配置選項。 如您所見,我們已指定我們希望IndexWriter使用先前創建的analyzer并將其設置為適當的版本。 最后,我們創建IndexWriter實例。 在其構造函數參數中,我們提供FSDirectory實例和先前創建的配置選項。
現在,您可以繼續使用上述IndexWriter將先前創建的Document添加到Index中:
領域就是這樣。 現在,當addDocument時,所有前面描述的操作都會發生:
現在我們的文檔已建立索引。 添加到索引的每個Document都遵循相同的過程。
現在,一切都變得更加清晰了,讓我們來看一下在圖表中使用的類的索引編制過程:
如你看到的:
- 我們將Document對象傳遞給IndexWriter 。
- 他使用Analyzer從Reader獲得的純文本中生成Terms 。
- 然后,他將更新索引所需的所有內容都寫入Directory 。
嘗試構建搜索引擎時,索引編制工作很難,因為您必須:
- 選擇您要索引的文檔和文本源。
- 提供讀取器類,以讀取文本源并將其轉換為純文本。 內置的類(或外部庫)種類繁多,可以讀取大量的文檔格式。 但是,如果它們都不適合您的文檔,則您將必須編寫自己的Reader來解析它們并將其轉換為純文本。
- 確定適合您應用程序需求的標記和分析策略。 大多數應用程序使用StandardAnalyzer和StandardTokenizer都可以正常工作。 但是,您可能想進一步自定義分析步驟,這需要做一些工作。
- 確定使用哪種字段,以及存儲和/或索引哪些字段。
3.搜索的基本組件
在本節中,我們將描述用于執行搜索的基本組件和基本Lucene類。 搜索是Lucene這樣的平臺的目標,因此它必須盡可能靈活和容易。
3.1 QueryBuilder和查詢
在Lucene中,傳遞給Index的每個查詢都是一個Query對象。 因此,在與索引進行實際交互以執行搜索之前,必須構建此類對象。
一切都以查詢字符串開頭。 就像您放在眾所周知的搜索引擎(例如Google)上的查詢字符串一樣。 可以是任意短語,也可以是結構更復雜的短語,我們將在下一課中看到。 但是只發送要在索引中搜索的原始字符串將是沒有用的。 您必須像處理帶索引的純文本一樣處理它。 您必須將查詢字符串拆分為單詞并創建可搜索的術語。 據推測,這可以使用分析儀來完成。
注意:需要注意的重要一點是,您應該使用與用于索引過程的分析器相同的Analyzer子類來檢查查詢,以檢查純文本。
這是創建由StandardAnalyzer處理的簡單查詢的方式:
領域我們將QueryBuilder對象與StandarAnalyzer的實例綁定。 現在,您可以使用該QueryBuilder實例創建Query對象。
Query是一個抽象類,并且有許多具體的子類可用,例如:
- 搜索包含特定術語的Document的TermQuery 。
- 創建其他查詢的布爾組合的BooleanQuery
- WildcardQuery以實現通配符搜索,例如用于查詢字符串“ * abc *”。
- PhraseQuery可以搜索整個短語,而不僅僅是單個術語。
- PrefixQuery搜索具有預定義前綴的術語。
所有這些不同的Query風格都將確定將在索引上執行的搜索的性質。 并且每個對象都可以通過該QueryBuilder實例獲得。 在我們的示例中,我們選擇使用createBooleanQuery方法。 它有兩個參數。 第一個是將要搜索其值(確定為索引且可能已標記化)的Field的名稱。 第二個是將使用StandardAnalyzer分析的查詢字符串。 createBooleanQuery可以根據查詢字符串的語法返回TermQuery或BooleanQuery 。
3.2 IndexReader
大概是要在索引中進行搜索,首先必須打開它。 您可以使用IndexReader打開和訪問它。 所有需要將數據從索引中拉出的過程都通過該抽象類。
使用IndexReader打開已經創建的索引非常容易:
領域如您所見,我們使用DirectoryReader打開存儲索引的目錄。 DirectoryReader返回索引的句柄,這就是IndexReader的含義。
3.3 IndexSearcher
IndexSearcher是用于搜索單個Index的類。 它與IndexReader綁定。
這是創建一個的方法:
領域您可以使用IndexSearcher將Query對象傳遞給IndexReader 。 方法如下:
領域我們使用IndexSearcher public TopDocs search(Query query, int n)方法執行搜索。 此方法需要兩個參數。 第一個是Query對象。 第二個是整數,用于設置返回的搜索結果數的限制。 例如,如果您有10000個滿足查詢條件的文檔,則可能不希望全部返回。 您可以聲明只需要前n個結果。 最后,該方法返回一個TopDocs實例。
3.4 TopDocs
TopDocs類表示滿足您的查詢的匹配。 TopDocs有一個public ScoreDoc[]類字段。
3.5 ScoreDoc
SocreDoc代表查詢命中。 它包括 :
- 一個public int doc字段,即滿足查詢條件的Document的ID。
- 還有一個public float score字段,即Document在查詢中獲得的分數。
評分公式是任何搜索平臺中必不可少且非常復雜的部分,這正是Lucene發揮出色的作用。 該公式用于為檢索到的文檔提供相關性度量。 分數越高,Document與您的查詢越相關。 這有助于表征“好”和“差”的文檔,并確保為您提供盡可能接近您真正需要的文檔的高質量結果。 您可以在當前版本的“ 相似性”類的文檔, 舊版本的“ 相似性”類的文檔中以及此信息檢索文章中找到一些有關評分的有用信息。
4.一個簡單的搜索應用程序
我們將構建一個簡單的搜索應用程序,該應用程序將演示索引和搜索的基本步驟。 在此應用程序中,我們將使用包含一堆Java源文件的輸入文件夾。 本文檔中的每個文件都將被處理并添加到索引中。 然后,我們將對該索引執行簡單查詢,以了解其工作原理。
我們將使用:
- Eclipse Kepler 4.3作為我們的IDE。
- JDK 1.7。
- Maven 3構建我們的項目。
- Lucene 4.6.0,Lucene的最新版本。
首先,讓我們使用Eclipse創建我們的Maven項目。
4.1使用Eclipse創建一個新的Maven項目
打開Eclipse并轉到File-> New-> Other-> Maven-> Maven Project,然后單擊Next。
在下一個窗口中,選擇“創建簡單項目(跳過原型選擇)”選項,然后單擊下一步:
在下一個窗口中,填寫組ID和工件ID,如下圖所示,然后單擊“完成”:
將使用以下結構創建一個新的Maven項目:
4.2 Maven依賴
打開pom.xml并添加使用Lucene庫所需的依賴項:
pom.xml:
領域如您所見,我們將導入提供所有核心類的lucene-core-4.6.0.jar ,以及提供所有文本分析所需的所有類的lucene-analyzers-common-4.6.0.jar包。
一個簡單的索引器類
要創建此類,請轉到Eclipse的Package Explorer。 在src/java/main創建一個名為com.javacodegeeks.enterprise.lucene.index的新包。 在新創建的包下,創建一個名為SimpleIndexer的新類。
讓我們看一下該類的代碼,該代碼將進行索引編制:
SimpleIndexer.java:
領域在上述類中,我們指定了將文本文件放置在C:/Users/nikos/Desktop/LuceneFolders/LuceneHelloWorld/SourceFiles輸入文件夾,還將要存儲索引的文件夾放置在C:/Users/nikos/Desktop/LuceneFolders/LuceneHelloWorld/Index 。
在index方法上,首先我們創建一個新的StandardAnalyzer實例和一個新的IndexWriter實例。 IndexeWriter將使用StrandardAnalyzer分析文本,并將索引存儲在FSDirectory指向上述索引路徑。
有趣的是在for循環上。 對于源目錄中的每個文件:
循環后:
當我運行此代碼時,這是它產生的輸出 :
領域Here is the index folder in my system. As you can see, several special files are created (more on that next lessons):
Now let's search that index.
4.4。
To create this class go to the Package Explorer of Eclipse. Under src/java/main create a new package named com.javacodegeeks.enterprise.lucene.search . Under the newly created package, create a new class named SimpleSearcher .
To get a more clear view of he final structure of the project, have a look at the image bellow:
Let's see the code of that class, which will do the searching:
SimpleSearcher.java:
領域In the searchIndex method we pass the index directory and the query string as arguments. So I'm going to search for “private static final String”. Remember that the files I've indexed were Java source files,
The code is pretty self explanatory:
Let's run the program and see what is the output :
領域It is important to understand that these files do not certainly contain the whole phrase "private static final String" . Intuitively, the documents with the higher score contain most of the words of that sentence and more frequently than documents with smaller scores. Of course the scoring formula is much more complex than that, as we said earlier.
For example if you change:
領域至
領域the whole phrase will be searched. Only documents that contain the whole phrase will be returned. When you run the code with that minor change, here is the output :
領域These files contain the whole query string "private static final String" in their contents.
4.5 Download the source code
You can download the Eclipse project of this example here: LuceneHelloWorld.zip
5. Final notes
It is important to mention that an IndexReader reads the “image” that the index has the moment he opens it. So, if your application is dealing with text sources that change over short periods of time, it is possible that you have to re-index those files at run time. But you want to be sure that the changes are reflected when you search the Index, while your application is still running and you have already opened an IndexReader (who now is outdated). In this case you have to obtain an updated IndexReader like this:
領域This will ensure that you get a new more updated IndexReader , but only if the index has changed. Furthermore, if you want to achieve fast, near real time searches ( eg for stream data) you can obtain your IndexReader like so:
領域For performance reasons, the IndexWriter doesn't flush the changes of the index immediately to the disk. It uses buffers instead, and persists the changes asynchronously. Opening an IndexReader like in the above snippet, gives him immediate access to the write buffers of the IndexWriter , and thus he has instant access to index updates.
Finally, it's worth mentioning that IndexWriter is thread safe, thus you can use the same instance in many threads to add Documents one particular index. The same goes for the IndexReader and IndexSearcher . Many threads can use the same instance of these classes to simultaneously read or search the same index.
翻譯自: https://www.javacodegeeks.com/2015/09/introduction-to-lucene.html
lucene簡介
總結
以上是生活随笔為你收集整理的lucene简介_Lucene简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 我花了3000买电视回家我花了3000买
- 下一篇: swagger生成示例_生成器设计模式示