Index: lucene/highlighter/src/test/org/apache/lucene/search/postingshighlight/TestPostingsHighlighter.java =================================================================== --- lucene/highlighter/src/test/org/apache/lucene/search/postingshighlight/TestPostingsHighlighter.java (revision 1457566) +++ lucene/highlighter/src/test/org/apache/lucene/search/postingshighlight/TestPostingsHighlighter.java (working copy) @@ -18,20 +18,24 @@ */ import java.io.BufferedReader; +import java.io.IOException; import java.io.InputStreamReader; import java.util.Map; import org.apache.lucene.analysis.Analyzer; import org.apache.lucene.analysis.MockAnalyzer; import org.apache.lucene.analysis.MockTokenizer; +import org.apache.lucene.document.BinaryDocValuesField; import org.apache.lucene.document.Document; import org.apache.lucene.document.Field; import org.apache.lucene.document.FieldType; import org.apache.lucene.document.StringField; import org.apache.lucene.document.TextField; +import org.apache.lucene.index.BinaryDocValues; import org.apache.lucene.index.FieldInfo.IndexOptions; import org.apache.lucene.index.IndexReader; import org.apache.lucene.index.IndexWriterConfig; +import org.apache.lucene.index.MultiDocValues; import org.apache.lucene.index.RandomIndexWriter; import org.apache.lucene.index.Term; import org.apache.lucene.search.BooleanClause; @@ -43,6 +47,7 @@ import org.apache.lucene.search.TermQuery; import org.apache.lucene.search.TopDocs; import org.apache.lucene.store.Directory; +import org.apache.lucene.util.BytesRef; import org.apache.lucene.util.LuceneTestCase.SuppressCodecs; import org.apache.lucene.util.LuceneTestCase; @@ -465,4 +470,52 @@ ir.close(); dir.close(); } + + public void testCustomFieldValueSource() throws Exception { + Directory dir = newDirectory(); + IndexWriterConfig iwc = newIndexWriterConfig(TEST_VERSION_CURRENT, new MockAnalyzer(random(), MockTokenizer.SIMPLE, true)); + iwc.setMergePolicy(newLogMergePolicy()); + RandomIndexWriter iw = new RandomIndexWriter(random(), dir, iwc); + + FieldType offsetsType = new FieldType(TextField.TYPE_NOT_STORED); + offsetsType.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS); + Field body = new Field("body", "", offsetsType); + Field bodyDV = new BinaryDocValuesField("bodyDV", new BytesRef()); + + Document doc = new Document(); + doc.add(body); + doc.add(bodyDV); + + String text = "This is a test. Just highlighting from postings. This is also a much sillier test. Feel free to test test test test test test test."; + body.setStringValue(text); + bodyDV.setBytesValue(new BytesRef(text)); + iw.addDocument(doc); + + IndexReader ir = iw.getReader(); + iw.close(); + + IndexSearcher searcher = newSearcher(ir); + final BinaryDocValues bodyDVs = MultiDocValues.getBinaryValues(searcher.getIndexReader(), "bodyDV"); + + PostingsHighlighter highlighter = new PostingsHighlighter(10000, null, new PassageScorer(), new PassageFormatter()) { + @Override + protected void loadFieldValues(IndexSearcher searcher, String[][] contents, String[] fields, int[] docids, int maxLength) throws IOException { + BytesRef scratch = new BytesRef(); + for(int i=0;itest. Just highlighting from postings. This is also a much sillier test. Feel free to test test test test test test test.", snippets[0]); + + ir.close(); + dir.close(); + } } Index: lucene/highlighter/src/java/org/apache/lucene/search/postingshighlight/PostingsHighlighter.java =================================================================== --- lucene/highlighter/src/java/org/apache/lucene/search/postingshighlight/PostingsHighlighter.java (revision 1457566) +++ lucene/highlighter/src/java/org/apache/lucene/search/postingshighlight/PostingsHighlighter.java (working copy) @@ -81,7 +81,7 @@ * This is thread-safe, and can be used across different readers. * @lucene.experimental */ -public final class PostingsHighlighter { +public class PostingsHighlighter { // TODO: maybe allow re-analysis for tiny fields? currently we require offsets, // but if the analyzer is really fast and the field is tiny, this might really be @@ -257,15 +257,8 @@ Arrays.sort(fields); // pull stored data: - LimitedStoredFieldVisitor visitor = new LimitedStoredFieldVisitor(fields, maxLength); String contents[][] = new String[fields.length][docids.length]; - for (int i = 0; i < docids.length; i++) { - searcher.doc(docids[i], visitor); - for (int j = 0; j < fields.length; j++) { - contents[j][i] = visitor.getValue(j).toString(); - } - visitor.reset(); - } + loadFieldValues(searcher, contents, fields, docids, maxLength); Map highlights = new HashMap(); for (int i = 0; i < fields.length; i++) { @@ -285,6 +278,24 @@ } return highlights; } + + /** Loads the String values for each field X docID to be + * highlighted. By default this loads from stored + * fields, but a subclass can change the source. This + * method should fill in the provided contents array; + * primary dimension is fields.length and secondary + * dimension is docids.length. Note that the returned + * Strings must be identical to what was indexed. */ + protected void loadFieldValues(IndexSearcher searcher, String[][] contents, String[] fields, int[] docids, int maxLength) throws IOException { + LimitedStoredFieldVisitor visitor = new LimitedStoredFieldVisitor(fields, maxLength); + for (int i = 0; i < docids.length; i++) { + searcher.doc(docids[i], visitor); + for (int j = 0; j < fields.length; j++) { + contents[j][i] = visitor.getValue(j).toString(); + } + visitor.reset(); + } + } private Map highlightField(String field, String contents[], BreakIterator bi, Term terms[], int[] docids, List leaves, int maxPassages) throws IOException { Map highlights = new HashMap();