我目前正在将搜索引擎应用程序从Lucene 3.5.0升级到版本4.10.3。版本4中发生了一些实质性的API更改,这些更改破坏了向后兼容性。我已经设法解决了大多数问题,但是仍然存在一些问题,我可以在以下方面寻求帮助:

  • “无法从分析器覆盖最终方法”

  • 原始代码扩展了Analyzer类并覆盖了tokenStream(...)。
    @Override
    public TokenStream tokenStream(String fieldName, Reader reader) {
        CharStream charStream = CharReader.get(reader);
        return
            new LowerCaseFilter(version,
                new SeparationFilter(version,
                    new WhitespaceTokenizer(version,
                        new HTMLStripFilter(charStream))));
    }
    

    但是此方法现在是最终方法,我不确定如何从更改日志中了解以下注释:

    ReusableAnalyzerBase已重命名为Analyzer。现在,所有Analyzer实施都必须使用Analyzer.TokenStreamComponents,而不是重写.tokenStream()和.reusableTokenStream()(现在已完成)。

    上面引用的方法中还有另一个问题:
  • “对于CharReader类型,未定义方法get(Reader)”

  • 这里似乎也发生了一些重大变化。
  • “TermPositionVector无法解析为类型”

  • 该类现在在Lucene 4中消失了。对此有任何简单的解决方法吗?从更改日志中:

    删除了术语向量API(TermFreqVector,TermPositionVector,TermVectorMapper),以支持上述灵活的索引API,从术语向量中呈现了文档的单文档反向索引。

    可能与此有关:
  • “未为类型IndexReader定义方法getTermFreqVector(int,String)。”

  • 例如,这两个问题都发生在这里:
    TermPositionVector termVector = (TermPositionVector) reader.getTermFreqVector(...);
    

    (“阅读器”的类型为IndexReader)

    对于这些问题的任何帮助,我将不胜感激。

    最佳答案

    我在Lucene邮件列表中找到了核心开发人员Uwe Schindlerresponse。我花了一些时间来思考新的API,所以我需要写下一些东西,然后才能忘记。

    这些说明适用于Lucene 4.10.3。

    实施分析器(1-2)

    new Analyzer() {
        @Override
        protected TokenStreamComponents createComponents(String fieldName, Reader reader) {
            Tokenizer source = new WhitespaceTokenizer(new HTMLStripCharFilter(reader));
            TokenStream sink = new LowerCaseFilter(source);
            return new TokenStreamComponents(source, sink);
        }
    };
    
  • TokenStreamComponents的构造函数带有一个源和一个接收器。该接收器是 token 流的最终结果,由Analyzer.tokenStream()返回,因此将其设置为您的过滤器链。在应用任何过滤器之前,源是 token 流。
  • HTMLStripCharFilter尽管是其名称,但实际上是java.io.Reader的子类,它删除了HTML构造,因此您不再需要CharReader。

  • 术语向量替换(3-4)

    术语向量在Lucene 4中的工作方式不同,因此没有直接的方法交换。具体答案取决于您的要求。

    如果需要位置信息,则必须首先使用位置信息来索引字段:

    Document doc = new Document();
    FieldType f = new FieldType();
    f.setIndexed(true);
    f.setStoreTermVectors(true);
    f.setStoreTermVectorPositions(true);
    doc.add(new Field("text", "hello", f));
    

    最后,为了获得文档字段的频率和位置信息,您可以像下面这样钻研新的API(改编自this answer):
    // IndexReader ir;
    // int docID = 0;
    Terms terms = ir.getTermVector(docID, "text");
    terms.hasPositions(); // should be true if you set the field to store positions
    TermsEnum termsEnum = terms.iterator(null);
    BytesRef term = null;
    // Explore the terms for this field
    while ((term = termsEnum.next()) != null) {
        // Enumerate through documents, in this case only one
        DocsAndPositionsEnum docsEnum = termsEnum.docsAndPositions(null, null);
        int docIdEnum;
        while ((docIdEnum = docsEnum.nextDoc()) != DocIdSetIterator.NO_MORE_DOCS) {
            for (int i = 0; i < docsEnum.freq(); i++) {
                System.out.println(term.utf8ToString() + " " + docIdEnum + " "
                        + docsEnum.nextPosition());
            }
        }
    }
    

    如果Terms.iterator()返回一个实际的Iterable,那就太好了。

    08-27 09:46