高亮功能一直都是全文檢索的一項很是優秀的模塊,在一個標準的搜索引擎中,高亮的返回命中結果,幾乎是必不可少的一項需求,由於經過高亮,咱們能夠在咱們的搜索界面上快速標記出用戶的檢索關鍵詞,從而減小了用戶本身尋找想要的結果,在必定程度上大大提升了用戶的體驗性和友好度。
那麼,今天就來看下咱們在Lucene中,怎麼實現高亮,以及高亮的幾種實現方式。
首先仍是喜歡老生常談的來補充下高亮須要的熟悉的基本知識,固然若是你只是須要實現效果,而不關注它的底層API,那麼能夠忽略此部分,不過仍是要友好的提示一下,若是使用過程當中出了點小問題,不會API,但是不容易解決的,除非你願意各類google。
要使用高亮,首先就得從索引時開始,由於須要高亮的字段,須要準確的獲取位置信息,以及一些偏移量,若是信息不許確,那麼可能在結果中,就會出現一些莫名其妙的錯位,反映到網頁上就是標註了不應標註的字,沒有標註該標的內容,因此這一點仍是須要注意一下,在索引的時候,咱們須要使用項向量記錄各個token的位置信息,這很簡單,代碼以下:
html
FieldType type=new FieldType(TextField.TYPE_STORED); type.setStoreTermVectorOffsets(true);//記錄相對增量 type.setStoreTermVectorPositions(true);//記錄位置信息 type.setStoreTermVectors(true);//存儲向量信息 type.freeze();//阻止改動信息 Field field=new Field("字段名", "值", type);//示例
簡單說下,TextField的2個枚舉變量的意思
前端
變量名 | 釋義 |
TYPE_NOT_STORED | 索引,分詞,不存儲 |
TYPE_STORED | 索引,分詞,存儲 |
類 | 釋義 |
SimpleHTMLFormatter | 經常使用的格式化Html標籤器,提供一個構造函數傳入高亮顏色標籤,默認使用黑色 |
TokenSources | 提供靜態方法,支持從數據源中獲取TokenStream,進行token處理 |
Highlighter | 負責獲取匹配上的高亮片斷 |
QueryScorer | 對命中結果進行評分操做 |
Fragmenter | 將原始字符串拆分紅獨立的片斷 |
NullFragmenter | 對較短的域進行總體高亮 |
FastVectorHighlighter | 基於快速高亮 |
Encoder | 提供一些實現類,對html文本操做,如,去掉一些特殊匹配符號<,> and so on,及一些其餘的非ASCII特殊字符。 |
id:1 name: 中國是一個偉大的國家,咱們中國人都是好樣的哈哈,中國永遠是強大的 content: 你好人民 id:2 name: 咱們有一個家它的名字是中國 content: 中國的大地,富饒 id:3 name: 咱們的中國,咱們的大地都是人民的但願的 content: 若是不在片斷中生成一些字段的話 id:4 name: 2014年此時此刻你在作什麼的啊 content: 哈哈鋤禾日當午 id:5 name: 當你孤單時你會想起誰,你想不想找我的來陪 content: 我永遠不孤單啊
1,測試普通高亮的核心代碼:
java
String filed="name"; QueryParser query=new QueryParser(Version.LUCENE_44, filed, new IKAnalyzer(false)); Query q=query.parse("偉大的中國");//測試字段 TopDocs top=searcher.search(q, 100); QueryScorer score=new QueryScorer(q, filed);//傳入評分 SimpleHTMLFormatter fors=new SimpleHTMLFormatter("<span style=\"color:red;\">", "</span>");//定製高亮標籤 Highlighter highlighter=new Highlighter(fors,score);//高亮分析器 // highlighter.setMaxDocCharsToAnalyze(1);//設置高亮處理的字符個數 for(ScoreDoc sd:top.scoreDocs){ Document doc=searcher.doc(sd.doc); String name=doc.get(filed); TokenStream token=TokenSources.getAnyTokenStream(searcher.getIndexReader(), sd.doc, filed, new IKAnalyzer(true));//獲取tokenstream Fragmenter fragment=new SimpleSpanFragmenter(score); highlighter.setTextFragmenter(fragment); String str=highlighter.getBestFragment(token, name);//獲取高亮的片斷,能夠對其數量進行限制 System.out.println("高亮的片斷 =====>"+str); }
輸出結果以下ajax
高亮的片斷 =====>中國是一個<span style="color:red;">偉大</span><span style="color:red;">的</span>國家,咱們中國人都是好樣<span style="color:red;">的</span>哈哈,<span style="color:red;">中國</span>永遠是強大<span style="color:red;">的</span> 高亮的片斷 =====>咱們<span style="color:red;">的</span><span style="color:red;">中國</span>,咱們<span style="color:red;">的</span>大地都是人民<span style="color:red;">的</span>但願<span style="color:red;">的</span> 高亮的片斷 =====>咱們有一個家它<span style="color:red;">的</span>名字是<span style="color:red;">中國</span>
2,快速高亮,FastVectorHighlighter,這個類可能會消耗更多的存儲空間,來換取更好的性能,固然除了性能上提高外,它還有一個很是炫的功能,支持多種顏色標記,高亮關鍵字,除此以外還支持Ngram的域,以及智能合併相鄰高亮短語.
咱們來看下散仙快速高亮的3條測試數據: sql
id:2 name: 中國(China),位於東亞,是一個以華夏文明爲主體、中華文化爲基礎,以漢族爲主要種族的統一多民族國家,通用漢語。中國疆域內的各個民族統稱爲中華民族,龍是中華民族的象徵。 content: 中國是世界四大文明古國之一,有着悠久的歷史,距今約5000年前,以中原地區爲中心開始出現聚落組織進而成國家和朝代,後歷經屢次演變和朝代更迭,持續時間較長的朝代有夏、商、周、漢、晉、唐、宋、元、明、清等 id:1 name: 中國的自古以來就是一個很是偉大的民族 content: 中國是一個世界人口大國,擁有13億多的人口. id:3 name: 沒有根的野草,飄忽的命運 content: 誰像你當我寶,什麼也作到,舊愛數足一塊布,在這一刻寫句號,只想跟你終老.
核心代碼以下:數據庫
Query q=query.parse("偉大的中華民族"); TopDocs top=searcher.search(q, 100); //QueryScorer score=new QueryScorer(q, filed); //SimpleHTMLFormatter fors=new SimpleHTMLFormatter("<span style=\"color:red;\">", "</span>");//定製高亮標籤 //Highlighter highlighter=new Highlighter(fors,score);//高亮分析器 //FastVectorHighlighter fastHighlighter=new FastVectorHighlighter(); FragListBuilder fragListBuilder=new SimpleFragListBuilder(); //注意下面的構造函數裏,使用的是顏色數組,用來支持多種顏色高亮 FragmentsBuilder fragmentsBuilder= new ScoreOrderFragmentsBuilder(BaseFragmentsBuilder.COLORED_PRE_TAGS,BaseFragmentsBuilder.COLORED_POST_TAGS); FastVectorHighlighter fastHighlighter2=new FastVectorHighlighter(true, true, fragListBuilder, fragmentsBuilder); FieldQuery querys=fastHighlighter2.getFieldQuery(q);//reader是傳入的流 // highlighter.setMaxDocCharsToAnalyze(1);//設置高亮處理的字符個數 for(ScoreDoc sd:top.scoreDocs){ String snippt=fastHighlighter2.getBestFragment(querys, reader, sd.doc,filed,300); if(snippt!=null){ System.out.println("高亮的片斷是:"+snippt); } }
結果以下,注意有多種顏色標識:
json
高亮的片斷是:中國<b style="background:lawngreen">的</b>自古以來就是一個很是<b style="background:yellow">偉大</b><b style="background:lawngreen">的</b>民族 高亮的片斷是:中國(China),位於東亞,是一個以華夏文明爲主體、中華文化爲基礎,以漢族爲主要種族<b style="background:lawngreen">的</b>統一多民族國家,通用漢語。中國疆域內<b style="background:lawngreen">的</b>各個民族統稱爲<b style="background:aquamarine">中華民族</b>,龍是<b style="background:aquamarine">中華民族</b><b style="background:lawngreen">的</b>象徵。 高亮的片斷是:沒有根<b style="background:lawngreen">的</b>野草,飄忽<b style="background:lawngreen">的</b>命運
3.下面來着重說一下,高亮的第三種方式,前臺高亮,散仙在上文曾提過,基於高亮的字段,必須的存儲,不然沒法實現高亮標註,固然這種說法,只是對於後臺高亮而言的,那麼對於大文本狀況下,存儲到索引裏是很是浪費空間的,並且還有可能會影響到檢索速度,因此就提出了,第三種方式。
在前臺進行高亮,而後大文本字段,能夠存儲在外部其餘的數據源裏面,須要標記時,能夠直接根據ID,或者某個字段,讀取數據而後經過JS正則在前端替換檢索的關鍵詞便可,在這以前須要作的一步就是,使用ajax把檢索的關鍵詞,傳入後臺進行分詞,而後將結果返回前臺,進行對分詞後的數據,進行匹配替換,再加上顏色標記,就能夠在前臺實現高亮了,這也是前臺高亮的實現原理,這種作法,在某些業務場景下,能夠大大減小服務器壓力,經過客戶端減壓,以及不用再存儲一些向量信息,從而對系統的性能的提升,也是有很大幫助的。
下面給出一個前臺高亮的截圖,注意用的是快速高亮的索引。
數組
附上前臺高亮的核心代碼
服務器
$.ajax({ type :"post", url: "getContent", data:"str="+str, dataType:"json", async:false, success:function(msg){ // alert(msg); $("#div").empty(); $.each(msg, function(i, n) { var temp=""; for(var i=0;i<shu.length;i++){ if(shu[i]!=""){ n.name=n.name.replace(new RegExp(shu[i],'g'), "<span style=\"color:red;\">"+shu[i]+"</span>"); } } $("#div").append("[*]"+n.name+" "); $("#div").append("[*]=============================== ") }); } });
至此,有關Lucene的高亮部分的內容,散仙就總結到這裏了,若是有什麼不足之處,歡迎各位道友指出。大部分場景下,使用普通高亮就能夠完成了,固然不管使用那種方式,只要能知足咱們的業務就行了,很簡單的道理,會抓住老鼠的貓,就是好貓。app
感謝耐下心讀到此處的朋友^_^, Lucene交流羣:324714439