Lucene 查询结果对于 long 和 double 值不正确

Posted

技术标签:

【中文标题】Lucene 查询结果对于 long 和 double 值不正确【英文标题】:Lucene query results not correct for long and double values 【发布时间】:2017-11-03 12:38:51 【问题描述】:

我使用 Lucene 6.1.0 来索引具有名称和值的元素。 例如

<documents>
    <Document>
        <field name="NAME" value="Long_-1"/>
        <field name="VALUE" value="-1"/>
    </Document>
    <Document>
        <field name="NAME" value="Double_-1.0"/>
        <field name="VALUE" value="-1.0"/>
    </Document>
    <Document>
        <field name="NAME" value="Double_-0.5"/>
        <field name="VALUE" value="-0.5"/>
    </Document>
    <Document>
        <field name="NAME" value="Long_0"/>
        <field name="VALUE" value="0"/>
    </Document>
    <Document>
        <field name="NAME" value="Double_0.0"/>
        <field name="VALUE" value="0.0"/>
    </Document>
    <Document>
        <field name="NAME" value="Double_0.5"/>
        <field name="VALUE" value="0.5"/>
    </Document>
    <Document>
        <field name="NAME" value="Long_1"/>
        <field name="VALUE" value="1"/>
    </Document>
    <Document>
        <field name="NAME" value="Double_1.0"/>
        <field name="VALUE" value="1.0"/>
    </Document>
    <Document>
        <field name="NAME" value="Double_1.5"/>
        <field name="VALUE" value="1.5"/>
    </Document>
    <Document>
        <field name="NAME" value="Long_2"/>
        <field name="VALUE" value="2"/>
    </Document>
</documents>

根据文档,我使用 LongPoint 和 DoublePoint 来构建索引。

public static void addLongField(String name, long value, Document doc) 
    doc.add(new LongPoint(name, value));
    // since Lucene6.x a second field is required to store the values. 
    doc.add(new StoredField(name, value));


public static void addDoubleField(String name, double value, Document doc) 
    doc.add(new DoublePoint(name, value));
    // since Lucene6.x a second field is required to store the values. 
    doc.add(new StoredField(name, value));

由于我对 long 和 double 值使用相同的字段,如果最小值和最大值有不同的符号,我的 RangeQuery 会得到奇怪的结果。

LongPoint.newRangeQuery(field, minValue, maxValue);
DoublePoint.newRangeQuery(field, minValue, maxValue);

这个例子是正确的:VALUE:[1 TO 1] VALUE:[0.5 TO 1.0]

结果:0.5     Double_0.51        Long_11.0     Double_1.0

这个例子是错误的VALUE:[0 TO 1] VALUE:[-0.5 TO 1.0]

结果:0        Long_00.0     Double_0.01        Long_1 -1       Long_-1-0.5    Double_-0.50.5     Double_0.51.0     Double_1.0 em>2        Long_2

除了正确的结果外,所有长值都会返回。

有人知道为什么吗? 不能在同一个字段中存储 long 和 double 值吗? 非常感谢。

BR托比亚斯

【问题讨论】:

【参考方案1】:

不,您不应该在同一个字段中保留不同的数据类型。您应该将它们放在单独的字段中,或者将您的 long 转换为双精度(反之亦然),以便它们都以相同的格式索引。


要了解发生了什么,了解数字字段的实际作用会有所帮助。数字字段以二进制表示形式编码,便于对该类型进行范围搜索。整数类型的编码和浮点类型的编码没有可比性。例如,对于数字 1:

long 1 = lucene BytesRef: [80 0 0 0 0 0 0 1] double 1.0 = lucene BytesRef: [bf f0 0 0 0 0 0 0]

这些 BytesRef 二进制表示是 实际上 正在搜索的内容。由于您的查询的一部分是从双 -0.5 到 1.0,因此您正在有效地运行查询:

编码值:[40 1f ff ff ff ff ff ff] - [bf f0 0 0 0 0 0 0]

其中不包括超出长值范围的几个额外命中,而是真正高和低范围之外的大多数长值(你需要得到进入Long.MAX_VALUE/2附近)。

【讨论】:

这确实解释了我的问题。非常感谢您的详细解释!

以上是关于Lucene 查询结果对于 long 和 double 值不正确的主要内容,如果未能解决你的问题,请参考以下文章

将查询部分与 Lucene 和数据库中的部分(MySQL)相结合

探秘ElasticSearch -lucene引擎搜索分析

倒排索引,正排索引与lucene

Lucene查询中的顺序是否会影响结果?

在Alfresco的Lucene查询搜索给出了奇怪的结果

Neo4j,在返回可分页结果的同时查询多个 lucene 索引