一.高亮簡介
大多數的搜索應用都存在類似的情況,那就是搜索結果顯示的屏幕空間有限。如果文檔很短並可以在結果列表中顯示全部內容,對屏幕空間顯示就不會構成太大的問題。但大多數情況下都只能顯示每個結果文檔的一小部分。這就提出了一個問題:如何決定結果文檔中顯示哪一部分?理想情況下,應該是基於各片段與用戶查詢的匹配程度來決定。為查詢結果選擇最佳片段進行顯示,這是Solr高亮框架提供的核心功能。
二.高亮工作原理
1.基本高亮

請注意,Solr返回的高亮片段在一個單獨的元素中:<lst name="highlighting">。因此,客戶端應用程序必須處理這些信息,才能對其進行顯示。
2.每個結果生成多個高亮片段
在某些情況下,每個結果高亮顯示一個片段,這可能還不足以為用戶提供足夠的上下文信息,讓用戶判斷這個結果是否值得進一步研究。使用hl.snippets參數在該文檔和結果中的其他文檔中梳理出更多的上下文。hl.snippets=2代表允許每個文檔最多高亮顯示兩個片段的顯示結果。

正如搜索結果的其他高亮效果那樣,設置hl.snippets=2並不能保證每個文檔總能生成兩個高亮片段。若結果中只有一個滿足搜索條件,則只返回一個高亮片段。參數hl.snippets的值應被視為每個結果返回高亮片段的數量上限。
三.查詢全流程分析

四.高亮內核分析
solrconfig.xml文件中定義了一個名為highlight的搜索組件,給出了高亮搜索組件的簡要定義。
<!-- Highlighting Component http://wiki.apache.org/solr/HighlightingParameters --> <searchComponent class="solr.HighlightComponent" name="highlight"> <highlighting> <!-- Configure the standard fragmenter --> <!-- This could most likely be commented out in the "default" case --> <fragmenter name="gap" default="true" class="solr.highlight.GapFragmenter"> <lst name="defaults"> <int name="hl.fragsize">100</int> </lst> </fragmenter> <!-- A regular-expression-based fragmenter (for sentence extraction) --> <fragmenter name="regex" class="solr.highlight.RegexFragmenter"> <lst name="defaults"> <!-- slightly smaller fragsizes work better because of slop --> <int name="hl.fragsize">70</int> <!-- allow 50% slop on fragment sizes --> <float name="hl.regex.slop">0.5</float> <!-- a basic sentence pattern --> <str name="hl.regex.pattern">[-\w ,/\n\"']{20,200}</str> </lst> </fragmenter> <!-- Configure the standard formatter --> <formatter name="html" default="true" class="solr.highlight.HtmlFormatter"> <lst name="defaults"> <str name="hl.simple.pre"><![CDATA[<em>]]></str> <str name="hl.simple.post"><![CDATA[</em>]]></str> </lst> </formatter> <!-- Configure the standard encoder --> <encoder name="html" class="solr.highlight.HtmlEncoder" /> <!-- Configure the standard fragListBuilder --> <fragListBuilder name="simple" class="solr.highlight.SimpleFragListBuilder"/> <!-- Configure the single fragListBuilder --> <fragListBuilder name="single" class="solr.highlight.SingleFragListBuilder"/> <!-- Configure the weighted fragListBuilder --> <fragListBuilder name="weighted" default="true" class="solr.highlight.WeightedFragListBuilder"/> <!-- default tag FragmentsBuilder --> <fragmentsBuilder name="default" default="true" class="solr.highlight.ScoreOrderFragmentsBuilder"> <!-- <lst name="defaults"> <str name="hl.multiValuedSeparatorChar">/</str> </lst> --> </fragmentsBuilder> <!-- multi-colored tag FragmentsBuilder --> <fragmentsBuilder name="colored" class="solr.highlight.ScoreOrderFragmentsBuilder"> <lst name="defaults"> <str name="hl.tag.pre"><![CDATA[ <b style="background:yellow">,<b style="background:lawgreen">, <b style="background:aquamarine">,<b style="background:magenta">, <b style="background:palegreen">,<b style="background:coral">, <b style="background:wheat">,<b style="background:khaki">, <b style="background:lime">,<b style="background:deepskyblue">]]></str> <str name="hl.tag.post"><![CDATA[</b>]]></str> </lst> </fragmentsBuilder> <boundaryScanner name="default" default="true" class="solr.highlight.SimpleBoundaryScanner"> <lst name="defaults"> <str name="hl.bs.maxScan">10</str> <str name="hl.bs.chars">.,!? 	 </str> </lst> </boundaryScanner> <boundaryScanner name="breakIterator" class="solr.highlight.BreakIteratorBoundaryScanner"> <lst name="defaults"> <!-- type should be one of CHARACTER, WORD(default), LINE and SENTENCE --> <str name="hl.bs.type">WORD</str> <!-- language and country are used when constructing Locale object. --> <!-- And the Locale object will be used when getting instance of BreakIterator --> <str name="hl.bs.language">en</str> <str name="hl.bs.country">US</str> </lst> </boundaryScanner> </highlighting> </searchComponent>
高亮組件位於查詢處理鏈的下游,因此,高亮組件每次只能對一頁搜索結果進行高亮處理。如果頁面較大,比如1000,那么每次請求中高亮組件的處理量很大,這會對查詢響應時間造成負面影響。
當需要使用多字段時,例如,數據包含title和body兩個字段,並且打算在這兩個字段上高亮顯示查詢詞項。在這種情況下,需要設定hl.fl=title,body,這樣就能在title和body字段上都進行高亮顯示。
對於hl.fl列表的每個字段,高亮組件將根據hl.snippets參數來決定生成多少個高亮片段,該參數的默認值為1。Solr高亮組件的主要組成如下:

1.文本分析
在Solr高亮顯示結果之前,它需要訪問原始文本並將其存儲起來。當Solr得到該字段的原始文本之后,它需要使用配置好的索引階段分析器進行重新分析。對文檔的原始文本重新進行分析主要有兩個原因。首先,片段中的詞項必須能與查詢詞項相比較。其次,Solr需要知道原始文本中詞項的位置偏移量,以便它在片段中高亮顯示詞項。我們不希望Solr生成的高亮片段漏掉raining的結尾ing。因此,Solr需要知道原始文本中raining開始和結束的位置。位置偏移量很重要,通過它Solr才能知道什么時候該高亮顯示一個短語,而不是短語的一部分。詞項分析器如下:

2.分段
分段是選擇文本字段中零個或多個子片段進行高亮顯示的過程。基於這一點,使用片段表示已排名和格式化的片段,這些片段得分足夠高,在結果中得以返回。Solr把文本分隔成片段,每個片段產生一個分數,得分最高的前N個片段作為高亮顯示片段被返回,這里的N由參數hl.snippets設定。
Solr有兩個基本方法來實現分段,分別是GapFragmenter和RegexFragmenter。默認方式是GapFragmenter,它基於一個目標長度來選擇片段。默認情況下,目標片段長度為100,也可以使用hl.fragsize參數進行修改。RegexFragmenter不會拆分分詞來產生固定長度的片段,而GapFragmenter會在分詞邊界上創建片段。GapFragmenter得名於,它避免了在跨越較大位置間隔上創建片段。例如,在schema.xml文件中字段定義的positionIncrementGap屬性上設置多值字段不同值之間的間隔。
RegexFragmenter通過正則表達式在文本中選擇片段。
3.評分
分段組件使用了評分組件的子組件為片段評分。默認評分組件的實現方法【QueryScorer】會計算每個分段中出現了多少個查詢詞項。
4.編碼與格式
hl.formatter參數指定了一個格式化組件,用來對詞項進行高亮顯示。默認格式化組件【hl.formatter=simple】將每個詞項包含在任意一段文本中。這種方法適用於HTML標簽來高亮顯示查詢詞項。默認情況下,simple格式化組件將詞項放在<em>標簽中,也可以使用hl.simple.pre和hl.simple.post參數覆蓋默認值。例如,如果想要使用層疊樣式表對高亮詞項進行格式化,在查詢中添加一下參數即可:
hl.simple.pre=<span class="foo">&
hl.simple.post=</span>
在每個片段傳遞給格式化組件之前,編碼組件需要對特殊字符進行編碼。當生成一個HTML高亮片段時,HTML編碼器將特殊字符轉義為HTML字符實體引用。
五.優化高亮顯示結果
1.與分面一起使用

2.高亮顯示短語
在后台,hl.usePhraseHighlighter參數控制這個行為,默認情況下它是啟用狀態。如果設置hl.usePhraseHighlighter=false,那么Solr可能返回單獨高亮顯示詞項blue或fireball的片段。關鍵之處在於,Solr在高亮顯示查詢短語時處理得當。
3.高亮顯示多值字段
略
4.高亮參數小結


5.字段級覆寫
很多高亮組件的參數都可以進行字段級覆寫。例如,搜索應用有title和body兩個字段。標題總是很短,因而只要求產生一個片段;但是若想在較長的body字段上生成三個片段,只需要設置f.body.hl.snippets=3來覆寫body字段的默認值1即可。一般情況下,在參數前添加f.fieldname對任意參數應用字段級覆寫。
