LuceneQueryHighlighter implements Highlighter { @Override public Map<Integer, NavigableSet<HighlightTerm>> highlight(Set<Integer> docIds) { try { IndexReader reader = indexSearcher.getIndexReader(); IndexReaderContext readerContext = reader.getContext(); List<LeafReaderContext> leaves = readerContext.leaves(); Map<Integer, NavigableSet<HighlightTerm>> termMap = new HashMap<>(); Map<Integer, Map<String, List<HighlightPassage>>> docPassages = new HashMap<>(); for (int docId : docIds) { termMap.put(docId, new TreeSet<HighlightTerm>()); Map<String, List<HighlightPassage>> fieldPassages = new HashMap<>(); docPassages.put(docId, fieldPassages); for (String field : fields) { fieldPassages.put(field, new ArrayList<>()); } } Map<Integer, Document> luceneIdToLuceneDocMap = new HashMap<>(); Map<Integer, Set<Integer>> myLeaves = new HashMap<>(); for (int docId : docIds) { Document luceneDoc = indexSearcher.doc(docId); luceneIdToLuceneDocMap.put(docId, luceneDoc); int leaf = ReaderUtil.subIndex(docId, leaves); Set<Integer> docsPerLeaf = myLeaves.get(leaf); if (docsPerLeaf == null) { docsPerLeaf = new HashSet<>(); myLeaves.put(leaf, docsPerLeaf); } docsPerLeaf.add(docId); } Query query = jochreQuery.getLuceneTextQuery(); List<Weight> weights = new ArrayList<>(); List<TermsEnumExtractor> extractors = new ArrayList<>(); this.extractWeights(query, weights, extractors); for (int leaf : myLeaves.keySet()) { if (LOG.isTraceEnabled()) LOG.trace("Searching leaf " + leaf); Set<Integer> docsPerLeaf = myLeaves.get(leaf); LeafReaderContext subContext = leaves.get(leaf); LeafReader atomicReader = subContext.reader(); for (int docId : docsPerLeaf) { Map<String, List<HighlightPassage>> fieldPassages = docPassages.get(docId); for (Weight weight : weights) { Set<Term> terms = new HashSet<>(); weight.extractTerms(terms); Matches matches = weight.matches(subContext, docId - subContext.docBase); if (matches != null) { for (String field : fields) { List<HighlightPassage> passages = fieldPassages.get(field); MatchesIterator iMatches = matches.getMatches(field); while (iMatches.next()) { HighlightPassage passage = new HighlightPassage(iMatches.startOffset(), iMatches.endOffset(), terms); passages.add(passage); } } } } } for (String field : fields) { if (LOG.isTraceEnabled()) LOG.trace("Field : " + field); Terms atomicReaderTerms = atomicReader.terms(field); if (atomicReaderTerms == null) { continue; } for (TermsEnumExtractor extractor : extractors) { if (LOG.isTraceEnabled()) LOG.trace("Matching extractor " + (extractor.getTerm() == null ? "" : extractor.getTerm().utf8ToString()) + " in field " + field); TermsEnum extractorEnum = extractor.getTermsEnum(atomicReaderTerms); BytesRef nextBytesRef = extractorEnum.next(); while (nextBytesRef != null) { List<HighlightTerm> highlights = this.findHighlights(field, extractorEnum, subContext, luceneIdToLuceneDocMap, docsPerLeaf); for (HighlightTerm highlightTerm : highlights) { termMap.get(highlightTerm.getDocId()).add(highlightTerm); } nextBytesRef = extractorEnum.next(); } } for (int docId : docsPerLeaf) { List<HighlightPassage> fieldPassages = docPassages.get(docId).get(field); if (fieldPassages != null) { for (HighlightPassage passage : fieldPassages) { if (LOG.isTraceEnabled()) LOG.trace("Checking passage: " + passage); int termCounter = 0; TermsEnum termsEnum = atomicReaderTerms.iterator(); for (Term term : passage.terms) { termCounter++; if (LOG.isTraceEnabled()) LOG.trace("Searching for term " + termCounter + ": " + term.bytes().utf8ToString() + " in field " + field); if (!termsEnum.seekExact(term.bytes())) { continue; } Set<Integer> singleDocIdSet = new HashSet<>(); singleDocIdSet.add(docId); List<HighlightTerm> highlights = this.findHighlights(field, termsEnum, subContext, luceneIdToLuceneDocMap, singleDocIdSet); for (HighlightTerm highlightTerm : highlights) { if (highlightTerm.getStartOffset() >= passage.start && highlightTerm.getEndOffset() <= passage.end) { if (LOG.isTraceEnabled()) LOG.trace("Adding term: " + highlightTerm); termMap.get(highlightTerm.getDocId()).add(highlightTerm); } else { if (LOG.isTraceEnabled()) LOG.trace("Term out of range: " + highlightTerm); } } } } } } } } this.logHighlightTerms(termMap); return termMap; } catch (IOException e) { LOG.error("Failed find lucene highlights in docIds " + docIds, e); throw new RuntimeException(e); } } LuceneQueryHighlighter(JochreQuery jochreQuery, IndexSearcher indexSearcher, Set<String> fields); @Override Map<Integer, NavigableSet<HighlightTerm>> highlight(Set<Integer> docIds);  }
@Test public void testFindSnippets() throws IOException { System.setProperty("config.file", "src/test/resources/test.conf"); ConfigFactory.invalidateCaches(); String configId = "yiddish"; JochreIndexBuilder builder = new JochreIndexBuilder(configId, false); builder.updateIndex(); JochreSearchManager manager = JochreSearchManager.getInstance(configId); IndexSearcher indexSearcher = manager.getManager().acquire(); try { JochreQuery query = new JochreQuery(configId, "קײנער"); JochreIndexSearcher searcher = new JochreIndexSearcher(indexSearcher, configId); Pair<TopDocs, Integer> results = searcher.search(query, 0, 100); int docId = results.getLeft().scoreDocs[0].doc; Set<Integer> docIds = new HashSet<>(); docIds.add(docId); Set<String> fields = new HashSet<>(); fields.add(JochreIndexField.text.name()); LuceneQueryHighlighter highlighter = new LuceneQueryHighlighter(query, indexSearcher, fields); Map<Integer, NavigableSet<HighlightTerm>> terms = highlighter.highlight(docIds); NavigableSet<HighlightTerm> myTerms = terms.get(docId); assertEquals(1, myTerms.size()); int i = 0; for (HighlightTerm term : myTerms) { LOG.debug(term.toString()); if (i == 0) { assertEquals(20, term.getPosition()); assertEquals(108, term.getStartOffset()); assertEquals(114, term.getEndOffset()); } i++; } HighlightManager highlightManager = new HighlightManager(indexSearcher, fields, configId); Map<Integer, Either<List<Snippet>, Exception>> snippets = highlightManager.findSnippets(docIds, terms, 2); List<Snippet> mySnippets = snippets.get(docId).getLeft(); assertEquals(1, mySnippets.size()); for (Snippet snippet : mySnippets) { LOG.debug(snippet.toString()); assertEquals(1, snippet.getHighlightTerms().size()); String text = highlightManager.displaySnippet(snippet); LOG.debug(text); ImageSnippet imageSnippet = highlightManager.getImageSnippet(snippet); LOG.debug(imageSnippet.getRectangle().toString()); assertEquals(new Rectangle(658, 2264, 2383, 363), imageSnippet.getRectangle()); BufferedImage image = imageSnippet.getImage(); assertEquals(2383, image.getWidth()); assertEquals(363, image.getHeight()); } } finally { manager.getManager().release(indexSearcher); } }