【问题标题】:How is field length defined in Solr/Lucene?Solr/Lucene 中如何定义字段长度?
【发布时间】:2014-04-07 08:15:00
【问题描述】:

据我了解,给定文档的字段长度是在给定文档的字段中索引的术语数。但是,字段长度似乎永远不是整数。例如,我看到一个文档的内容字段中有两个术语,但 Solr 计算的内容字段长度实际上是 2.56,而不是我预期的 2。 Solr/Lucene 中的字段长度是如何计算的?

我指的是根据 BM25 相似度函数计算分数时使用的字段长度,但我认为其他排名方案正在计算字段长度。

【问题讨论】:

    标签: solr lucene


    【解决方案1】:

    正如我在 BM25Similarity 的代码中看到的:

      public final long computeNorm(FieldInvertState state) {
        final int numTerms = discountOverlaps ? state.getLength() - state.getNumOverlap() : state.getLength();
        return encodeNormValue(state.getBoost(), numTerms);
      }
    

    state#getLength() 在哪里:

      /**
       * Get total number of terms in this field.
       * @return the length
       */
      public int getLength() {
        return length;
      }
    

    实际上,它是一个整数。你能告诉我,你在哪里看到非整数值? SolrAdmin 用户界面?在哪里?

    现在,当您发布输出时,我找到了它的来源: source

    看看这个:

    private Explanation explainTFNorm(int doc, Explanation freq, BM25Stats stats, NumericDocValues norms) {
        List<Explanation> subs = new ArrayList<>();
        subs.add(freq);
        subs.add(Explanation.match(k1, "parameter k1"));
        if (norms == null) {
          subs.add(Explanation.match(0, "parameter b (norms omitted for field)"));
          return Explanation.match(
              (freq.getValue() * (k1 + 1)) / (freq.getValue() + k1),
              "tfNorm, computed from:", subs);
        } else {
          float doclen = decodeNormValue((byte)norms.get(doc));
          subs.add(Explanation.match(b, "parameter b"));
          subs.add(Explanation.match(stats.avgdl, "avgFieldLength"));
          subs.add(Explanation.match(doclen, "fieldLength"));
          return Explanation.match(
              (freq.getValue() * (k1 + 1)) / (freq.getValue() + k1 * (1 - b + b * doclen/stats.avgdl)),
              "tfNorm, computed from:", subs);
        }
      }
    

    所以,根据他们输出的字段长度:float doclen = decodeNormValue((byte)norms.get(doc));

     /** The default implementation returns <code>1 / f<sup>2</sup></code>
       * where <code>f</code> is {@link SmallFloat#byte315ToFloat(byte)}. */
      protected float decodeNormValue(byte b) {
        return NORM_TABLE[b & 0xFF];
      }
    
    /** Cache of decoded bytes. */
      private static final float[] NORM_TABLE = new float[256];
    
      static {
        for (int i = 1; i < 256; i++) {
          float f = SmallFloat.byte315ToFloat((byte)i);
          NORM_TABLE[i] = 1.0f / (f*f);
        }
        NORM_TABLE[0] = 1.0f / NORM_TABLE[255]; // otherwise inf
      }
    

    其实看wikipedia这个docLen应该是

    一个 |D|是文档 D 的单词长度

    【讨论】:

    • 我看到解释的非整数值:2.56 = fieldLength
    • @mossaab 您能否将解释的完整输出添加到您的问题中?因为通常它包含 fieldNorm 或 fieldWeigth 而不是 fieldLength。
    • 23.637165 = sum of: 10.065297 = weight(title:googl in 401658357) [BM25Similarity], result of: 10.065297 = score(doc=401658357,freq=1.0 = termFreq=1.0), product of: 7.3866553 = IDF(DOCFREQ = 414179,DOCCOUNT = 668609139)1.3626325 = TFNOMM从以下计算:1.0 = TEMFREQ = 1.0 1.2 =参数K1 0.75 =参数B 7.3254013 = AVGFIELDLENGTH 2.56 = FIELDLENGTH 13.571868 =重量(标题:401658357)[BM25SIMILLITY ],结果:13.571868 = score(doc=401658357,freq=1.0 = termFreq=1.0),乘积:[截断]
    • @mossaab 我更新了我的答案,它没有明确回答你的问题,但它至少指向代码中的位置。虽然那里没有多少 javadoc..
    【解决方案2】:

    详细说明上一个答案“fieldLength”是通过 SmallFloat 类中的复杂数学归一化(编码/解码)方程(基本上将 32 位整数压缩为 8 位以节省磁盘空间同时存储数据)计算得出的.java。

    这是 decodeNormValue() 函数的描述,它计算 BM25 中的 fieldLength:

    默认评分实现,其中 {@link encodeNormValue(float) 在存储之前将规范值编码为单个字节。搜索时 时间,从索引 {@link 读取规范字节值 org.apache.lucene.store.Directory 目录} 和 {@link decodeNormValue(long) decoded} 返回一个浮点 norm 值。 这种编码/解码,同时减少索引大小,附带 精度损失的代价——不能保证 解码(编码(x))= x。例如,decode(encode(0.89)) = 0.875

    希望这会有所帮助。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-10-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-26
      • 1970-01-01
      相关资源
      最近更新 更多