После дальнейшего изучения это, похоже, ошибка в коде подсветки Lucene.Как вы можете видеть здесь:
public class TokenGroup {
...
protected boolean isDistinct() {
return offsetAtt.startOffset() >= endOffset;
}
...
Код пытается определить, отличается ли группа токенов, проверяя, является ли начальное смещение большим, чем предыдущее конечное смещение.Проблема с этим подходом иллюстрируется этой проблемой.Если бы вам пришлось пройти по токенам, вы бы увидели, что они выглядят следующим образом:
0-4: 'test', 'test'
5-6: '1', '1'
7-10: '500', '500'
5-10: '1500', '1,500'
11-15: 'this', 'this'
Из этого вы можете видеть, что третий токен начинается после окончания второго, но четвертый запускает тот жеместо как второе.Предполагаемый результат - сгруппировать токены 2, 3 и 4, но согласно этой реализации токен 3 рассматривается отдельно от 2, поэтому 2 отображается сам по себе, затем 3 и 4 группируются, оставляя этот результат:
Expected: 'test <b>1,500</b> this'
Observed: 'test 1<b>1,500</b> this'
Я не уверен, что это может быть достигнуто без 2 проходов, один для получения всех индексов и второй для их объединения.Кроме того, я не уверен, какие последствия будут за пределами этого конкретного случая.У кого-нибудь есть здесь идеи?
РЕДАКТИРОВАТЬ
Вот окончательный исходный код, который я придумал.Это сгруппирует вещи правильно.Это также кажется НАМНОГО проще, чем реализация Lucene Highlighter, но по общему признанию не обрабатывает различные уровни скоринга, поскольку моему приложению нужно только да / нет относительно того, выделен ли фрагмент текста.Стоит также отметить, что я использую их QueryScorer для оценки текстовых фрагментов, которые имеют слабую ориентацию на термин, а не на фразу, что означает, что строка поиска «грамматическая или орфографическая» в конечном итоге будет выделена примерно так: »1014 * грамматическое или правописание"как или, скорее всего, будет отброшено вашим анализатором.Во всяком случае, вот мой источник:
public TextFragments<E> getTextFragments( TokenStream tokenStream,
String text,
Scorer scorer )
throws IOException, InvalidTokenOffsetsException {
OffsetAttribute offsetAtt = (OffsetAttribute) tokenStream.addAttribute( OffsetAttribute.class );
TermAttribute termAtt = (TermAttribute) tokenStream.addAttribute( TermAttribute.class );
TokenStream newStream = scorer.init( tokenStream );
if ( newStream != null ) {
tokenStream = newStream;
}
TokenGroups tgs = new TokenGroups();
scorer.startFragment( null );
while ( tokenStream.incrementToken() ) {
tgs.add( offsetAtt.startOffset(), offsetAtt.endOffset(), scorer.getTokenScore() );
if ( log.isTraceEnabled() ) {
log.trace( new StringBuilder()
.append( scorer.getTokenScore() )
.append( " " )
.append( offsetAtt.startOffset() )
.append( "-" )
.append( offsetAtt.endOffset() )
.append( ": '" )
.append( termAtt.term() )
.append( "', '" )
.append( text.substring( offsetAtt.startOffset(), offsetAtt.endOffset() ) )
.append( "'" )
.toString() );
}
}
return tgs.fragment( text );
}
private class TokenGroup {
private int startIndex;
private int endIndex;
private float score;
public TokenGroup( int startIndex, int endIndex, float score ) {
this.startIndex = startIndex;
this.endIndex = endIndex;
this.score = score;
}
}
private class TokenGroups implements Iterable<TokenGroup> {
private List<TokenGroup> tgs;
public TokenGroups() {
tgs = new ArrayList<TokenGroup>();
}
public void add( int startIndex, int endIndex, float score ) {
add( new TokenGroup( startIndex, endIndex, score ) );
}
public void add( TokenGroup tg ) {
for ( int i = tgs.size() - 1; i >= 0; i-- ) {
if ( tg.startIndex < tgs.get( i ).endIndex ) {
tg = merge( tg, tgs.remove( i ) );
}
else {
break;
}
}
tgs.add( tg );
}
private TokenGroup merge( TokenGroup tg1, TokenGroup tg2 ) {
return new TokenGroup( Math.min( tg1.startIndex, tg2.startIndex ),
Math.max( tg1.endIndex, tg2.endIndex ),
Math.max( tg1.score, tg2.score ) );
}
private TextFragments<E> fragment( String text ) {
TextFragments<E> fragments = new TextFragments<E>();
int lastEndIndex = 0;
for ( TokenGroup tg : this ) {
if ( tg.startIndex > lastEndIndex ) {
fragments.add( text.substring( lastEndIndex, tg.startIndex ), textModeNormal );
}
fragments.add(
text.substring( tg.startIndex, tg.endIndex ),
tg.score > 0 ? textModeHighlighted : textModeNormal );
lastEndIndex = tg.endIndex;
}
if ( lastEndIndex < ( text.length() - 1 ) ) {
fragments.add( text.substring( lastEndIndex ), textModeNormal );
}
return fragments;
}
@Override
public Iterator<TokenGroup> iterator() {
return tgs.iterator();
}
}