Lucene 查询结果对于 long 和 double 值不正确
Lucene query results not correct for long and double values
我使用 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);
这个例子是正确的:
值:[1 比 1] 值:[0.5 到 1.0]
结果:
0.5 Double_0.5
1 Long_1
1.0 Double_1.0
这个例子是错误的
值:[0 到 1] 值:[-0.5 到 1.0]
结果:
0 Long_0
0.0 Double_0.0
1 Long_1
-1 Long_-1
-0.5 Double_-0.5
0.5 Double_0.5
1.0 Double_1.0
2 Long_2
除了正确的结果外,还返回了所有 long 值。
有人知道为什么吗?
不能在同一个字段中存储 long 和 double 值吗?
非常感谢。
BR 托拜厄斯
不,您不应该在同一字段中保留不同的数据类型。您应该将它们放在单独的字段中,或者将您的长整型转换为双精度(反之亦然),以便它们都以相同的格式编制索引。
要了解发生了什么,有助于了解数字字段的实际作用。数字字段以二进制表示形式编码,这有助于对该类型进行范围搜索。整数类型的编码和浮点类型的编码没有可比性。例如,对于数字 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 ff] - [bf f0 0 0 0 0 0 0]
其中不包括长值范围外的一些额外命中,但大多数长值在 真正 高低范围之外(你' d 需要进入 Long.MAX_VALUE/2
附近)。
我使用 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);
这个例子是正确的:
值:[1 比 1] 值:[0.5 到 1.0]
结果:
0.5 Double_0.5
1 Long_1
1.0 Double_1.0
这个例子是错误的
值:[0 到 1] 值:[-0.5 到 1.0]
结果:
0 Long_0
0.0 Double_0.0
1 Long_1
-1 Long_-1
-0.5 Double_-0.5
0.5 Double_0.5
1.0 Double_1.0
2 Long_2
除了正确的结果外,还返回了所有 long 值。
有人知道为什么吗?
不能在同一个字段中存储 long 和 double 值吗?
非常感谢。
BR 托拜厄斯
不,您不应该在同一字段中保留不同的数据类型。您应该将它们放在单独的字段中,或者将您的长整型转换为双精度(反之亦然),以便它们都以相同的格式编制索引。
要了解发生了什么,有助于了解数字字段的实际作用。数字字段以二进制表示形式编码,这有助于对该类型进行范围搜索。整数类型的编码和浮点类型的编码没有可比性。例如,对于数字 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 ff] - [bf f0 0 0 0 0 0 0]
其中不包括长值范围外的一些额外命中,但大多数长值在 真正 高低范围之外(你' d 需要进入 Long.MAX_VALUE/2
附近)。