本打算直接來學習Solr, 現在先把Lucene的只是捋一遍.
本文內容:
1、 搜索引擎的發展史
2、 Lucene入門
3、 Lucene的API詳解
4、 索引調優
5、 Lucene搜索結果排名規則
1 搜索引擎的發展史
1.1 搜索引擎的發展史
萌芽:Archie、Gopher
起步:Robot(網絡機器人)和spider(網絡爬蟲)
1、 Robot:網絡機器人,自動在網絡中運行,完成特定任務的程序,如刷票器、搶票軟件等。
2、 spider:網絡爬蟲,是一中特殊的機器人,抓取(下載)並分析網絡資源,包括網頁里面的超鏈接、圖片、數據庫、音頻、視頻等資源信息。
發展:excite、galaxy、yahoo
繁榮:infoseek、altavista、Google、百度
1.2 搜索引擎的原理
1.2.1 信息檢索過程
1、 構建文本庫
2、 建立索引
3、 進行搜索
4、 對結果進行排序
1.2.2 原理
搜索引擎的工作原理,通過用戶輸入的信息,通過網絡爬蟲即搜索服務器,將各與之相關的網站信息抓取並存放到自己的數據服務器中,在存入數據服務器的過程中將這些數據信息需要創建索引庫,用戶查詢的結果信息都是來源與索引庫信息,如果點擊該結果超鏈接則訪問的是該網站信息,如果選擇“快照”則訪問的是緩存信息。
那為什么要建立索引庫呢?建立索引庫的過程就是將該結果建立索引,通俗一點的理解就是建立目錄的過程。
1.3 搜索引擎的使用場景
1.3.1 使用場景
1、 電商網站的搜索,如京東、天貓等
2、 論壇、BBS等站內搜索
3、 垂直領域的搜索,垂直領域:即專門做一件事。如818工作網、拉勾網等都屬於垂直領域。
4、 Windows的資源管理器中的搜索
5、 Word中的Ctrl+F、eclipse中的Ctrl+shift+T等單機軟件的搜索
這些都是屬於信息檢索的范圍。
1.3.2 倒排索引
倒排索引,就是提取信息並建立索引(目錄)的過程中,搜索時,根據關鍵字找到資源的具體位置。如:
2 Lucene入門
2.1 什么是Lucene
2.1.1 概念
Lucene是apache下的一個開放源代碼的全文檢索引擎工具包。提供了完整的查詢引擎和索引引擎,部分文本分析引擎。Lucene的目的是為軟件開發人員提供一個簡單易用的工具包,以方便的在目標系統中實現全文檢索的功能。
2.1.2 Lucene與搜索引擎的區別
全文檢索系統是按照全文檢索理論建立起來的用於提供全文檢索服務的軟件系統。全文檢索系統是一個可以運行的系統,包括建立索引、處理查詢返回結果集、增加索引、優化索引結構等功能。例如:百度搜索、eclipse幫助搜索、淘寶網商品搜索。
搜索引擎是全文檢索技術最主要的一個應用,例如百度。搜索引擎起源於傳統的信息全文檢索理論,即計算機程序通過掃描每一篇文章中的每一個詞,建立以詞為單位的倒排文件,檢索程序根據檢索詞在每一篇文章中出現的頻率和每一個檢索詞在一篇文章中出現的概率,對包含這些檢索詞的文章進行排序,最后輸出排序的結果。全文檢索技術是搜索引擎的核心支撐技術。
Lucene和搜索引擎不同,Lucene是一套用java或其它語言寫的全文檢索的工具包,為應用程序提供了很多個api接口去調用,可以簡單理解為是一套實現全文檢索的類庫,搜索引擎是一個全文檢索系統,它是一個單獨運行的軟件系統。
Lucene開源免費,它既不是搜索引擎,也不是可直接運行的軟件,它只是一套API,可以根據該API開發自己的搜索系統。
2.2 掌握什么
這里我們使用的是Lucene4.x版本,我們需要知道是如何創建索引的,並根據輸入的信息將我們的結果查詢出來這樣的一套流程。
2.3 企業中如何使用Lucene
例如BBS貼吧的站內搜索,它是如何完成的呢?難道是查詢數據庫的信息並將結果返回的么?
2.4 入門程序
2.4.1 下載Lucene
官網,http://lucene.apache.org/,我們通過官網下載我們需要的jar包。目前最新的版本5.3.1,那這里我們使用的是4.10.2這個版本。
2.4.2 創建索引
2.4.2.1 導入jar包
解壓我們的zip壓縮文件,導入我們需要的jar包。這里我們需要分詞器的包、Lucene的核心包、高亮顯示的包和查詢需要的包。
2.4.2.2 創建索引
在發帖並提交時,我們創建帖子的索引庫。
創建索引庫的過程:將文本內容-à轉換成Document對象(該對象中有很多Field,可以把該Document對象當做是一個帖子),然后在通過IndexWriter創建我們的索引。
2.4.2.2.1 代碼
代碼里提到了分詞器的概念,這個再將API的時候在細說。
2.4.2.2.2 索引庫
2.4.2.3 查看索引庫
我們通過lukeall工具查看創建的索引庫中的內容。我們通過java –jar xxx.jar的方式運行我們的lukeall工具,並通過該工具查看我們創建的索引庫的內部結構。
2.4.2.3.1 overview
目錄庫,分詞后的詞條信息。
2.4.2.3.2 document
也就是內容庫。存放數據的。
2.4.3 基於索引搜索
2.4.3.1 檢索過程
檢索過程。
2.4.3.2 代碼
3 Lucene API詳解
3.1 創建索引API
3.1.1 Directory
l Directory,指的是文件磁盤的索引路徑
l RAMDirectory,指的是內存中的索引路徑
3.1.2 Analyzer
3.1.2.1 原理
Analyzer是一個抽象類,在Lucene的lucene-analyzers-common包中提供了很多分析器,比如:org.apache.lucene.analysis.standard.standardAnalyzer標准分詞器,它是Lucene的核心分詞器,它對分析文本進行分詞、大寫轉成小寫、去除停用詞、去除標點符號等操作過程。
什么是停用詞?停用詞是為節省存儲空間和提高搜索效率,搜索引擎在索引頁面或處理搜索請求時會自動忽略某些字或詞,這些字或詞即被稱為Stop Words(停用詞)。比如語氣助詞、副詞、介詞、連接詞等,通常自身並無明確的意義,只有將其放入一個完整的句子中才有一定作用,如常見的“的”、“在”、“是”、“啊”等。
如下是org.apache.lucene.analysis.standard.standardAnalyzer的部分源碼:
final StandardTokenizer src = new StandardTokenizer(getVersion(), reader);//創建分詞器
src.setMaxTokenLength(maxTokenLength);
TokenStream tok = new StandardFilter(getVersion(), src);//創建標准分詞過濾器
tok = new LowerCaseFilter(getVersion(), tok);//在標准分詞過濾器的基礎上加大小寫轉換過濾
tok = new StopFilter(getVersion(), tok, stopwords);//在上邊過濾器基礎上加停用詞過濾
3.1.2.2 中文分詞器
學過英文的都知道,英文是以單詞為單位的,單詞與單詞之間以空格或者逗號句號隔開。而中文則以字為單位,字又組成詞,字和詞再組成句子。所以對於英文,我們可以簡單以空格判斷某個字符串是否為一個單詞,比如I love China,love 和 China很容易被程序區分開來;但中文“我愛中國”就不一樣了,電腦不知道“中國”是一個詞語還是“愛中”是一個詞語。把中文的句子切分成有意義的詞,就是中文分詞,也稱切詞。我愛中國,分詞的結果是:我 愛 中國。
3.1.2.3 Lucene自帶分詞器
l StandardAnalyzer:
單字分詞:就是按照中文一個字一個字地進行分詞。如:“我愛中國”,
效果:“我”、“愛”、“中”、“國”。
l CJKAnalyzer
二分法分詞:按兩個字進行切分。如:“我是中國人”,效果:“我是”、“是中”、“中國”“國人”。
上面兩個分詞器無法滿足需求。
l SmartChineseAnalyzer
對中文支持較好,但擴展性差,擴展詞庫,禁用詞庫和同義詞庫等不好處理
3.1.2.4 第三方產品
名稱 |
最近更新 |
速度 ( 網上情報 ) |
擴展性支持、其它 |
mmseg4j |
2013 |
complex 60W 字 /s (1200 KB/s) simple 100W 字 /s (1900 KB/s) |
使用 sougou 詞庫,也可自定義 (complex\simple\ MaxWord) |
IKAnalyzer |
2012 |
IK2012 160W 字 /s (3000KB/s) |
支持用戶詞典擴展定義、支持自定義停止詞 ( 智能 \ 細粒度 ) |
Ansj |
2014 |
BaseAnalysis 300W 字 /s hlAnalysis 40W 字 /s |
支持用戶自定義詞典,可以分析出詞性,有新詞發現功能 |
paoding |
2008 |
100W 字 /s |
支持不限制個數的用戶自定義詞庫 |
這里我們使用IK分詞器。那如何使用IK分詞器呢?
1、 解壓壓縮文件,並將該兩個配置文件放入src中。
2、 導入jar包
導入FF_u1的jar包,該版本支持4.x,而u6僅僅支持4.x之前的版本。
3、 使用該分詞器的前后對比
standardanalyzer:
IKanalyzer :
3.1.3 IndexableFiled
l LongField,分詞,有多個詞條
l StringField,建立索引時不分詞,將該內容作為一個完整的詞條Term
l TextField,建立索引時分詞,有多個詞條
l Store:YES或NO不影響是否分詞;YES,會在Document中存儲,NO,不會在Document中存儲
3.1.4 IndexWriter
Lucene3.5之后,IndexWriter的初始化有了一個IndexConfig來作為其初始化的參數,當我們在使用IndexWrier的時候一定要注意在最后把writer關閉,否則拋出異常。其實這個異常是因為lucene進入到索引目錄中,發現里面就是一個write.lock。而IndexWriter的構造函數在試圖獲取另外一個IndexWriter已經加鎖的索引目錄時就會拋出一個LockObtainFailedException。
當IndexWriter在初始化索引的時候會為這個索引加鎖,等到初始化完成之后會調用其close()方法關閉IndexWriter,在close()這個方法的內部其實也是調用了unlock()來釋放鎖,當程序結束后IndexWriter沒有正常關閉的時候這個鎖也就沒有被釋放,等待下次對同樣的索引文件創建IndexWriter的時候就會拋出該異常。
執行上面代碼,就會報如下錯誤。
編寫工具類,在使用完IndexWriter后自動關閉。
通俗一點講:就是該對象銷毀后才釋放鎖對象,因為都是將信息放入同一個索引庫中。如果指定不是同一索引庫是沒有問題的,但是需要執行commit方法,因為close方法中包含了commit方法。
3.2 基於索引庫檢索API
檢索最重要的就是根據你的Query去搜索信息,因此我們Lucene的API中提供了很多的Query對象,我們根據不同的Query對象獨有的特性去檢索我們需要的信息。
3.2.1 QueryParser
針對單一字段,解析查詢信息並分詞進行搜索。
3.2.2 MultiFiledQueryParser
針對多字段,解析查詢信息並分詞進行搜索。
3.2.3 TermQuery
根據詞條搜索,使用該對象不會在去解析查詢信息並分詞。詞條就是索引庫的最小單位,不可再繼續分詞。
3.2.4 WildcardQuery
模糊搜索:*代表0個或多個字符;?代表一個字符
3.2.5 FuzzyQuery
相似度搜索,例如,我們想搜JQuery,但是在輸入框輸入jquary。
FuzzyQuery的構造方法:
FuzzyQuery(Term term):默認支持模糊字數為2;
FuzzyQuery(Term term, int maxEdits):maxEdits:模糊字數,[0,2]之間,若為0,相當於TermQuery。
FuzzyQuery(Term term, int maxEdits, int prefixLength):prefixLength,指定要有多個前綴字母必須完全匹配。
3.2.6 NumericRangeQuery
數字范圍搜索(演示:略),最后兩個參數的含義是:minInclusive,是否最小包含,maxInclusive,是否最大包含
3.2.7 MatchAllDocsQuery
查詢所有的結果。
3.2.8 小結
使用Query對象的優先順序
1、 TermQuery,詞條搜索
2、 若輸入內容太長,可用:QueryParser,將輸入內容解析並切詞
3、 若輸入內容太短,可用:WildcardQuery,模糊查詢
4、 若輸入內容有誤,可用:FuzzyQuery,相似度查詢
3.3 BooleanQuery
BooleanQuery,組合查詢,通過該Query對象可以將上面各種Query進行任意組合。
構造方法:
add(Query query, BooleanClause.Occur occur):query,各種其他的query;occur,該變量的取值有三種,分別為:MUST(必須滿足)、MUST_NOT(必須不滿足)、SHOULD(可以滿足)。
MUST+MUST:兩個Query查詢對象的交集
MUST+MUST_NOT:兩個Query查詢對象的補集
SHOULD+SHOULD:兩個Query查詢對象的並集。
3.4 結論
詞條:就是將查詢的信息通過指定的各種Query對象的本身特有的屬性去匹配詞條;
Document:就是將匹配后的結果返回。
4 索引調優
4.1 概念
索引調優:就是在創建索引時,將我們的創建的索引庫的內容和磁盤內容加載到內存中,執行完之后,並將內存中的索引庫的內容加載到磁盤上。
RAMDirectory是內存的一個區域,當虛擬機退出后,里面的內容也會隨之消失
RAMDirectory的性能要好於FSDirectory, 因此可以結合使用,在虛擬機退出時,將RAM內容轉到FSDirectory。
4.2 代碼
索引調優代碼:
CREATE:會寫到索引庫並覆蓋原索引庫
CREATE_OR_APPEND:將內存庫信息追加到索引庫中。
5 Lucene搜索結果排名規則
5.1 結果得分
5.1.1 Lucene文檔的得分算法
idf舉例:
有很多不同的數學公式可以用來計算TF-IDF。這邊的例子以上述的數學公式來計算。詞頻 (TF) 是一詞語出現的次數除以該文件的總詞語數。假如一篇文件的總詞語數是100個,而詞語“母牛”出現了3次,那么“母牛”一詞在該文件中的詞頻就是3/100=0.03。一個計算文件頻率 (DF) 的方法是測定有多少份文件出現過“母牛”一詞,然后除以文件集里包含的文件總數。所以,如果“母牛”一詞在1,000份文件出現過,而文件總數是10,000,000份的話,其逆向文件頻率就是 lg(10,000,000 / 1,000)=4。最后的TF-IDF的分數為0.03 * 4=0.12。
5.1.2 改變boost值來改變文檔得分
boost,激勵因子,默認值是1,可以手動更改。我們可以設置boost值來改變搜索結果排名。而且設置boost值后,該信息保存在Document文檔的norm中。
5.1.2.1 在索引庫中創建100個索引
5.1.2.2 搜索索引庫中的內容
查詢的結果:
而且所有的Document中的NORM的值都是一樣。
得分一樣。那么我想讓第88條記錄排在第一位怎么辦?我們只有設置它的激勵因子(boost)值即可。
1、 設置得分
2、 結果
3、 NORM值
設置boost(激勵因子),可以改變得分以及Norm值。
5.2 結果高亮顯示
結果高亮顯示,也就是將搜索內容進行了高亮顯示。例如,百度,查詢java
所以說高亮顯示就是將搜索的信息結果通過HTML標簽進行樣式的處理。可以對標題也可以對文本進行高亮顯示。