我正在使用lucene为大量HTML文档创建搜索引擎。
我知道我可以使用PostingsHighlighter
和朋友来显示片段,使用粗体字,类似于Google搜索结果,也类似于this random lucene-based example。
然而,与这些示例不同,我需要一种解决方案,即使在用户打开匹配的文档之后,也会保留突出显示的字词,类似于Google图书。
有些单词是连字符,格式为<div> ... an inter-</div><div...>national audience ...</div>
我认为我需要先将这些单词转换为纯文本,然后编写一些代码来合并连字的单词,然后再发送给lucene。
一旦用户打开了生成的文档,我希望我可以使用lucene来获取文档中每个匹配单词的字符偏移量。
我必须将纯文本中的偏移量交叉引用回原始HTML,并根据所述偏移量编写代码以突出显示<b>
这些单词。
<div> ... an <b>inter-</b></div><div...><b>national</b> audience ...</div>
如何从lucene获得我需要的东西?当然,我不必自己搜索这个“最后一寸”?
答案 0 :(得分:2)
好的,我想出了一些我可以开始的东西。 :)
索引:
StandardAnalyzer analyzer - new StandardAnalyzer()
Directory index = FSDirectory.open(new File("...").toPath());
IndexWriterConfig config = new IndexWriterConfig(analyzer);
addDoc(writer, "...", "...");
addDoc(writer, "...", "...");
addDoc(writer, "...", "...");
// documents need to be read from the data source..
// only add once, or else your docs will be duplicated as you continue to use the system
writer.close();
指定要存储的偏移以突出显示
private static final FieldType typeOffsets;
static {
typeOffsets = new FieldType(textField.TYPE_STORED);
typeOffsets.setIndexOptions(IndexOptions.DOCS_AND_FREQS_AND_POSITIONS_AND_OFFSETS);
}
方法addDoc
void addDoc(IndexWriter writer, String title, String body) {
Document doc = new Document();
doc.add(new Field("title", body, typeOffsets));
doc.add(new Field("body", body, typeOffsets));
// you can also add an store a TextField that does not have offsets,
// like a file ID that you wouldn't search on, just need to reference original doc.
writer.addDocument(doc);
}
执行首次搜索
String q = "...";
String[] fields = new String[] {"title", "body"};
QueryParser parser = new MultiFieldQueryParser(fields, analyzer)
Query query = parser.parse(q)
IndexSearcher searcher = new IndexSearcher(DirectoryReader.open(index));
PostingsHighlighter highlighter = new PostingsHighlighter();
TopDocs topDocs = searcher.search(query, 10, Sort.RELEVANCE);
使用highlighter.highlightFields(fields, query, searcher, topDocs)
获取突出显示的摘要。您可以迭代结果。
如果要突出显示结束文档(即搜索完成后用户选择结果),请使用this solution(需要进行少量编辑)。它的工作原理是使用NullFragmenter
将整个内容转换为一个代码段。
public static String highlight(String pText, String pQuery) throws Exception
{
Analyzer analyzer = new StandardAnalyzer(Version.LUCENE_30);
QueryParser parser = new QueryParser(Version.LUCENE_30, "", analyzer);
Highlighter highlighter = new Highlighter(new QueryScorer(parser.parse(pQuery)));
highlighter.setTextFragmenter(new NullFragmenter());
String text = highlighter.getBestFragment(analyzer, "", pText);
if (text != null)
{
return text;
}
return pText;
}
修改:您实际上可以使用PostingsHighlighter
代替Highlighter
,但是您必须覆盖getBreakIterator
,然后覆盖您的BreakIterator
以便它认为整个文件是一个文件。
修改:您可以覆盖getFormatter
以捕获偏移,而不是尝试解析<b>
正常输出的PostingsHighlighter
代码。