4

从 Lucene 4.0 升级到 4.1 后,我的解决方案的性能下降了一个数量级以上。直接原因是存储字段的无条件压缩。现在我要恢复到 4.0,但这显然不是前进的方向;我希望找到一种不同的方法来解决我的问题。

我使用 Lucene 作为数据库索引,这意味着我存储的字段很短:最多只有几个词。

我使用CustomScoreQuerywhereCustomScoreProvider#customScore最终加载所有候选文档并对查询执行详细的单词相似度评分。我采用了两个启发式方法来缩小候选文档集(基于Dice 的系数),但在最后一步中,我需要将每个查询词与每个文档词进行匹配(它们的顺序可能不同)并计算总分基于最佳单词匹配的总和。

我如何以不同的方式处理这个问题并以一种避免在查询评估期间加载压缩字段的陷阱的方式进行计算?

4

2 回答 2

2

在 中IndexWriterConfig,您可以传入一个Codec,它定义了索引要使用的存储方法。这只会在构造时生效IndexWriter(即构造后更改配置将不起作用)。你会想要使用Lucene40Codec.

就像是:

//You could also simply pass in Version.LUCENE_40 here, and not worry about the Codec
//(though that will likely affect other things as well)
IndexWriterConfig config = new IndexWriterConfig(Version.LUCENE_41, analyzer);
config.setCodec(new Lucene40Codec());
IndexWriter writer = new IndexWriter(directory, config);

您还可以Lucene40StoredFieldsFormat直接使用来获取旧的、未压缩的存储字段格式,并将其从自定义 Codec 实现传回。您可能可以从 中获取大部分代码Lucene41Codec,然后替换该storedFieldFormat()方法。可能是更有针对性的方法,但有点复杂,我不确定您是否会遇到其他问题。

关于创建自定义编解码器的进一步说明,API 指示您应该完成此操作的方式是扩展 FilterCodec,并稍微修改它们的示例以适应:

公共最终类 CustomCodec 扩展 FilterCodec {

 public CustomCodec() {
   super("CustomCodec", new Lucene41Codec());
 }

 public StoredFieldsFormat storedFieldsFormat() {
   return new Lucene40StoredFieldsFormat();
 }

}


当然,我想到的另一个实现:

我认为您也很清楚,问题就在于“我最终加载了所有候选文档”。我不会对我没有完整细节或理解的评分实现进行过多评论,但这听起来像是你在与 Lucene 的架构作斗争以使其做你想做的事。一般来说,存储字段不应该用于评分,您可以预期性能会因使用 4.0 存储字段格式而受到非常明显的影响,尽管程度要小一些。是否有更好的实现,无论是在评分算法方面,还是在文档结构方面,这将消除基于存储字段对文档进行评分的要求?

于 2013-02-13T17:34:08.870 回答
0

使用 Lucene 3.x 我有这个:

new CustomScoreQuery(bigramQuery, new FieldScoreQuery("bigram-count", Type.BYTE)) {
  protected CustomScoreProvider getCustomScoreProvider(IndexReader ir) {
    return new CustomScoreProvider(ir) {
      public double customScore(int docnum, float bigramFreq, float docBigramCount) {
         ... calculate Dice's coefficient using bigramFreq and docBigramCount...
         if (diceCoeff >= threshold) {
           String[] stems = ir.document(docnum).getValues("stems");
           ... calculate document similarity score using stems ...
         }
      }
    };
  }
}

这种方法可以有效地从存储字段中检索缓存float值,我用它来获取文档的二元计数;它不允许检索字符串,因此我需要加载文档以获取计算文档相似度分数所需的内容。在 Lucene 4.1 更改为压缩存储字段之前,它工作正常。

利用 Lucene 4 中的增强功能的正确方法是这样参与DocValues

new CustomScoreQuery(bigramQuery) {
  protected CustomScoreProvider getCustomScoreProvider(ReaderContext rc) {
    final AtomicReader ir = ((AtomicReaderContext)rc).reader();
    final ValueSource 
       bgCountSrc = ir.docValues("bigram-count").getSource(),
       stemSrc = ir.docValues("stems").getSource();
    return new CustomScoreProvider(rc) {
      public float customScore(int docnum, float bgFreq, float... fScores) {
        final long bgCount = bgCountSrc.getInt(docnum);
        ... calculate Dice's coefficient using bgFreq and bgCount ...
        if (diceCoeff >= threshold) {
          final String stems = 
             stemSrc.getBytes(docnum, new BytesRef())).utf8ToString();
          ... calculate document similarity score using stems ...
        }
      }
    };
  }
}

这导致性能从 16 毫秒(Lucene 3.x)提高到 10 毫秒(Lucene 4.x)。

于 2013-02-17T15:03:29.700 回答