Lucene荧光笔课:突出不同颜色的不同单词

时间:2014-02-23 18:41:27

标签: lucene highlighting

大多数阅读标题的人都可能对Lucene有所了解,不需要进一步解释。 NB我使用Jython但我认为大多数Java用户都会理解Java等价物......

这是一个经典的事情:你的搜索字符串中有多个术语......在Lucene术语中,这会返回一个BooleanQuery。然后你使用类似这样的代码突出显示(NB我是一个Lucene新手,这都是从网络示例中调整的):

yellow_highlight = SimpleHTMLFormatter( '<b style="background-color:yellow">', '</b>' )
green_highlight = SimpleHTMLFormatter( '<b style="background-color:green">', '</b>' )

...

stream = FrenchAnalyzer( Version.LUCENE_46 ).tokenStream( "both", StringReader( both ) )
scorer = QueryScorer( fr_query, "both" )
fragmenter = SimpleSpanFragmenter(scorer)
highlighter = Highlighter( yellow_highlight, scorer )
highlighter.setTextFragmenter(fragmenter)
best_fragments = highlighter.getBestTextFragments( stream, both, True, 5 )
if best_fragments:
    for best_frag in best_fragments:
        print "=== best frag: %s, type %s" % ( best_frag, type( best_frag ))
        html_text += "&bull %s<br>\n" % unicode( best_frag )

...然后将html_text放在JTextPane中。

但是,如何使查询中的第一个单词以黄色背景突出显示,第二个单词以绿色背景突出显示?我试图理解org.apache.lucene.search中的各种类......无济于事。所以我唯一的学习方式是谷歌搜索。我找不到任何线索......

1 个答案:

答案 0 :(得分:0)

四年前我问过这个问题......当时我确实设法使用javax.swing.text.html.HTMLDocument来实现解决方案。标准Java库中还有接口org.w3c.dom.html.HTMLDocument。这种方式很难。

但对于任何有兴趣的人来说,这是一个更简单的解决方案。利用Lucene的SimpleHTMLFormatter返回最简单的“标记”文本的事实:选择的单词用HTML B标记突出显示。而已。它甚至不是一个“正确”的HTML片段,只有一个String,其中包含<B></B>

多字查询会生成BooleanQuery ...您可以通过TermQuery ... booleanQuery.clauses()

从中提取多个getQuery()

我在Groovy工作。我想要应用的着色是控制台代码,根据BASH(或Cygwin)。其他类型的着色可以在这个模型上得到解决。

所以你先设置一张地图来保存你的“标记细节”:

def markupDetails = [:]

然后对于每个TermQuery,您每次使用相同的text参数调用此参数,为每个术语规定不同的colour参数。 NB我正在使用Lucene 6.

def createHighlightAndAnalyseMarkup( TermQuery tq, String text, String colour ) {
    def termQueryScorer = new QueryScorer( tq )
    def termQueryHighlighter = new Highlighter( formatter, termQueryScorer )
    TokenStream stream = TokenSources.getTokenStream( fieldName, null, text, analyser, -1 )
    String[] frags = termQueryHighlighter.getBestFragments( stream, text, 999999 )
    // not sure under what circs you get > 1 fragment...
    assert frags.size() <= 1
    // NB you don't always get all terms in all returned LDocuments... 
    if( frags.size() ) {
        String highlightedFrag = frags[ 0 ]
        Matcher boldTagMatcher = highlightedFrag =~ /<\/?B>/
        def pos = 0
        def previousEnd = 0
        while( boldTagMatcher.find()) {
            pos += boldTagMatcher.start() - previousEnd
            previousEnd =  boldTagMatcher.end()
            markupDetails[  pos ] = boldTagMatcher.group() == '<B>'? colour : ConsoleColors.RESET
        }
    }
}

正如我所说,我想要控制台输出。此处方法中的colour参数是根据找到的控制台颜色代码here。例如。黄色是\033[033mConsoleColors.RESET\033[0m,用于标记每个彩色文本位置停止的位置。

...在您完成所有TermQuery之后,您将获得一张漂亮的地图,告诉您各个颜色的开始和结束位置。您从文本末尾向后工作,以便在String的正确位置插入“标记”。在这里注意text是原始的无标记的String

    markupDetails.sort().reverseEach{ pos, markup ->
        String firstPart = text.substring( 0, pos )
        String secondPart = text.substring( pos )
        text = firstPart + markup + secondPart
    }

...最后text包含您标记的String:打印到控制台。可爱。