在Lucene的org.apache.lucene.search.highlight包中提供了關於高亮顯示檢索關鍵字的工具。我們在使用百度、Google搜索的時候,檢索結果顯示的時候,在摘要中實現與關鍵字相同的詞條進行高亮顯示,百度和Google指定紅色高亮顯示。
有了Lucene提供的高亮顯示的工具,可以很方便地實現高亮顯示的功能。
高亮顯示,就是根據用戶輸入的檢索關鍵字,檢索找到該關鍵字對應的檢索結果文件,提取對應於該文件的摘要文本,然後根據設置的高亮格式,將格式寫入到摘要文本中對應的與關鍵字相同或相似的詞條上,在網頁上顯示出來,該摘要中的與關鍵字有關的文本就會以高亮的格式顯示出來。
高亮顯示模塊需要兩個獨立的輸入:完整的原始文本以用來提供操作數據,以及來源於該文本的一個TokenStream。爲了創建TokenStream,你必須對文本進行重新分析,此時需要使用與索引期間相同的分析器進行。
Highlighter依賴於詞彙單元流中每個詞彙單元的起始和結束位置偏移量來將原始輸入文本中的字符片段進行精確定位,來用於高亮顯示。
高亮處理的相關概念:
Fragmenter
作用是將原始字符串拆分成獨立的片段。
NullFragmenter 是該接口的一個具體實現類,它將整個字符串作爲單個片段返回,這適合於處理title域和前臺文本較短的域,而對於這些域來說,我們是希望在搜索結果中全部展示。
SimpleFragmenter 是負責將文本拆分封固定字符長度的片段,但它並處理子邊界。你可以指定每個片段的字符長度(默認情況100)但這類片段有點過於簡單,在創建片段時,他並不限制查詢語句的位置,因此對於跨度的匹配操作會輕易被拆分到兩個片段中;
SimpleSpanFragmenter 是嘗試將讓片段永遠包含跨度匹配的文檔。
如果不Highlighter實例中設置Fragmenter,那麼它會默認的SimpleFragmenter。
Scorer
Fragmenter輸出的是文本片段序列,而Highlighter必須從中挑選出最適合的一個或多個片段呈現給客戶,爲了做到這點,Highlighter會要求Java接口Scorer來對每個片段進行評分。
Highlighter提供了兩個Scorer具體實現類:QueryTermScorer和QueryScorer
QueryTermScorer 基於片段中對應Query的項數進行評分。
QueryScorer只對促成文檔匹配的實際項進行評分。
Encoder
他的目的很簡單,將初始文本編碼成外部格式。該接口實現有兩個:
DefaultEncoder:默認情況下供Hightlighter使用,它並不對文本進行任何操作。
SimpleHTMLEncoder:負責將文本編碼成HTML,並忽略一些如< 、>以及其它非ASCII等特殊字符。一旦完成編碼,最後一步就是對片段進行格式化處理向用戶展現。
Formatter
它負責將片段轉換成String形式,以及將被高亮顯示的項一起用於搜索結果展示以及高亮顯示。
-
public class Demo {
-
-
-
-
-
-
-
public void buildDocs(IndexWriter writer)throws Exception {
-
writer.deleteAll();
-
List<User> list = DataUtil.getUsers_more();
-
System.out.println("buildDocs()->總人數爲 :"+list.size());
-
for(User user :list){
-
Document doc = new Document();
-
doc.add(new Field("id",String.valueOf(user.getId()),Store.YES,Index.NO));
-
doc.add(new Field("name",user.getName(),Store.YES,Index.ANALYZED));
-
doc.add(new Field("age",String.valueOf(user.getAge()),Store.YES,Index.ANALYZED));
-
doc.add(new Field("sex",user.getSex(),Store.YES,Index.ANALYZED));
-
doc.add(new Field("birthday",String.valueOf(user.getBirthday()),Store.YES,Index.ANALYZED));
-
writer.addDocument(doc);
-
}
-
int count =writer.numDocs();
-
writer.forceMerge(100);
-
writer.close();
-
System.out.println("buildDocs()->存入索引庫的數量:"+count);
-
}
-
-
}
-
public class HighlighterDemo extends Demo {
-
-
-
-
-
-
-
-
-
public void searToHighlighter(Analyzer analyzer,IndexSearcher searcher) throws IOException, InvalidTokenOffsetsException, ParseException{
-
-
-
QueryParser parser = new QueryParser(Version.LUCENE_36,"sex", analyzer);
-
Query query = parser.parse("男生");
-
-
-
TopDocs docs =searcher.search(query,null, 10);
-
System.out.println("searcherDoc()->男生人數:"+docs.totalHits);
-
-
QueryScorer scorer=new QueryScorer(query);
-
Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);
-
Highlighter highlight=new Highlighter(scorer);
-
highlight.setTextFragmenter(fragmenter);
-
-
int seq=0;
-
for(ScoreDoc doc:docs.scoreDocs){
-
seq++;
-
int docID=doc.doc;
-
Document document =searcher.doc(docID);
-
String str="序號:"+seq+",ID:"+document.get("id")+",姓名:"+document.get("name")+",性別:" ;
-
String value =document.get("sex");
-
if (value != null) {
-
TokenStream tokenStream = analyzer.tokenStream("sex", new StringReader(value));
-
String str1 = highlight.getBestFragment(tokenStream, value);
-
str=str+str1;
-
}
-
System.out.println("查詢出人員:"+str);
-
}
-
}
-
-
-
-
-
-
-
-
-
public void searToHighlighterCss(Analyzer analyzer,IndexSearcher searcher) throws IOException, InvalidTokenOffsetsException{
-
Term term =new Term("sex", "男生");
-
TermQuery query =new TermQuery(term);
-
TopDocs docs =searcher.search(query, 10);
-
System.out.println("searcherDoc()->男生人數:"+docs.totalHits);
-
-
-
SimpleHTMLFormatter formatter = new SimpleHTMLFormatter("<span class=\"hightlighterCss\">","</span>");
-
-
QueryScorer scorer=new QueryScorer(query);
-
-
Fragmenter fragmenter = new SimpleSpanFragmenter(scorer);
-
Highlighter highlight=new Highlighter(formatter,scorer);
-
highlight.setTextFragmenter(fragmenter);
-
-
int seq=0;
-
for(ScoreDoc doc:docs.scoreDocs){
-
seq++;
-
int docID=doc.doc;
-
Document document =searcher.doc(docID);
-
String str="序號:"+seq+",ID:"+document.get("id")+",姓名:"+document.get("name")+",性別:" ;
-
String value =document.get("sex");
-
if (value != null) {
-
TokenStream tokenStream = analyzer.tokenStream("sex", new StringReader(value));
-
String str1 = highlight.getBestFragment(tokenStream, value);
-
str=str+str1;
-
}
-
System.out.println("查詢出人員:"+str);
-
}
-
}
-
}
-
public class TestHighlighter {
-
private IndexWriter writer=null;
-
private Directory directory=null;
-
private IndexReader reader = null;
-
private IndexSearcher searcher=null;
-
private HighlighterDemo demo =new HighlighterDemo();
-
private Analyzer analyzer =null;
-
-
@Before
-
public void setUp() throws Exception {
-
directory = new SimpleFSDirectory(new File("F:/luc_dir"));
-
analyzer =new IKAnalyzer();
-
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_36,analyzer);
-
writer = new IndexWriter(directory,config);
-
}
-
-
@Test
-
public void testSearToHighlighter()throws Exception {
-
-
demo.buildDocs(writer);
-
-
-
reader = IndexReader.open(directory);
-
searcher =new IndexSearcher(reader);
-
demo.searToHighlighter(analyzer,searcher);
-
}
-
-
@Test
-
public void testSearToHighlighterCss()throws Exception {
-
-
demo.buildDocs(writer);
-
-
-
reader = IndexReader.open(directory);
-
searcher =new IndexSearcher(reader);
-
demo.searToHighlighterCss(new IKAnalyzer(),searcher);
-
}
-
}
testSearToHighlighter測試結果:
-
buildDocs()->總人數爲 :100
-
buildDocs()->存入索引庫的數量:100
-
searcherDoc()->男生人數:66
-
查詢出人員:序號:1,ID:1,姓名:張三1,性別:我是<B>男生</B>
-
查詢出人員:序號:2,ID:2,姓名:張三2,性別:我是<B>男生</B>
-
查詢出人員:序號:3,ID:4,姓名:張三4,性別:我是<B>男生</B>
-
查詢出人員:序號:4,ID:5,姓名:張三5,性別:我是<B>男生</B>
-
查詢出人員:序號:5,ID:7,姓名:張三7,性別:我是<B>男生</B>
-
查詢出人員:序號:6,ID:8,姓名:張三8,性別:我是<B>男生</B>
-
查詢出人員:序號:7,ID:10,姓名:張三10,性別:我是<B>男生</B>
-
查詢出人員:序號:8,ID:11,姓名:張三11,性別:我是<B>男生</B>
-
查詢出人員:序號:9,ID:13,姓名:張三13,性別:我是<B>男生</B>
-
查詢出人員:序號:10,ID:14,姓名:張三14,性別:我是<B>男生</B>
testSearToHighlighterCss 測試結果
-
buildDocs()->總人數爲 :100
-
buildDocs()->存入索引庫的數量:100
-
searcherDoc()->男生人數:66
-
查詢出人員:序號:1,ID:1,姓名:張三1,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:2,ID:2,姓名:張三2,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:3,ID:4,姓名:張三4,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:4,ID:5,姓名:張三5,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:5,ID:7,姓名:張三7,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:6,ID:8,姓名:張三8,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:7,ID:10,姓名:張三10,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:8,ID:11,姓名:張三11,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:9,ID:13,姓名:張三13,性別:我是<span class="hightlighterCss">男生</span>
-
查詢出人員:序號:10,ID:14,姓名:張三14,性別:我是<span class="hightlighterCss">男生</span>