在Lucene搜索之后,获取文档中所有匹配单词的字符偏移量? (不只是预览片段)

时间:2015-07-02 20:31:53

标签: lucene highlight

我正在使用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获得我需要的东西?当然,我不必自己搜索这个“最后一寸”?

1 个答案:

答案 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代码。