4

我们使用 Lucene.net 进行索引。我们索引的字段之一是一个数值字段,其值为 1 到 6,9999 表示未设置。

在使用Luke探索索引时,我们会看到我们不认识的术语。该索引共包含 38673 个文档,Luke 显示了该领域的以下排名靠前的术语:

Term | Rank  | Field | Text | Text (decoded as numeric-int)
 1   | 38673 | Axis  | x    | 0  
 2   | 38673 | Axis  | p    | 0  
 3   | 38673 | Axis  | t    | 0  
 4   | 38673 | Axis  | |    | 0  
 5   | 19421 | Axis  | l    | 0  
 6   | 19421 | Axis  | h    | 0  
 7   | 19421 | Axis  | d@   | 0  
 8   | 19252 | Axis  | `  N | 9999  
 9   | 19252 | Axis  | l    | 8192
10   | 19252 | Axis  | h  ' | 9984
11   | 19252 | Axis  | d@ p | 9984 
12   | 18209 | Axis  | `    | 4  
13   |   950 | Axis  | `    | 1  
14   |   116 | Axis  | `    | 5  
15   |   102 | Axis  | `    | 6  
16   |    26 | Axis  | `    | 3  
17   |    18 | Axis  | `    | 2  

我们发现其他数字字段的模式相同。

未知值从何而来?

4

1 回答 1

4

NumericFields 使用trie结构进行索引。您看到的术语是其中的一部分,但如果您查询它们,则不会返回结果。

尝试使用 Int32.MaxValue 的精度步长索引 NumericField,这些值将消失。

NumericField 文档

...在 Lucene 中,每个数值都被索引为一个 trie 结构,其中每个术语在逻辑上分配给越来越大的预定义括号(它们只是值的低精度表示)。每个连续括号之间的步长称为precisionStep,以位为单位。较小的precisionStep 值会导致更多的括号,这会在索引中消耗更多的磁盘空间,但可能会导致更快的范围搜索性能。选择默认值 4 是为了合理权衡磁盘空间消耗与性能。如果您想更改值,可以使用专家构造函数 NumericField(String,int,Field.Store,boolean)。请注意,您还必须在创建 NumericRangeQuery 或 NumericRangeFilter 时指定一个全等值。对于低基数场,较大的精度步长是好的。如果基数 < 100,则使用 Integer.MAX_VALUE 是公平的,每个值产生一个术语。...

有关NumericRangeQuery 文档中提供的精度步骤的更多详细信息:

PrecisionStep 的良好值取决于使用情况和数据类型:

• 所有数据类型的默认值为4,当没有给出precisionStep 时使用。

• 大多数情况下,64 位数据类型(long、double)的理想值是 6 或 8。

• 大多数情况下,32 位数据类型(int、float)的理想值为 4。

• 对于低基数字段,较大的精度步长是好的。如果基数 < 100,使用 •Integer.MAX_VALUE 是公平的(见下文)。

• long/double 的步数≥64,int/float 的步数≥32,在索引中为每个值生成一个标记,查询与传统的 TermRangeQuery 一样慢。但它可用于生成仅用于排序的字段(在这种情况下,只需使用 Integer.MAX_VALUE 作为precisionStep)。使用 NumericFields 进行排序是理想的,因为构建字段缓存比使用纯文本数字快得多。这些字段每个值都有一个术语,因此也可以与术语枚举一起使用以构建不同的列表(例如要搜索的构面/预选值)。使用上述precisionSteps之一也可以对范围查询优化字段进行排序。

编辑

小样本,由此产生的索引将在卢克中显示值为 8192、9984、1792 等的术语,但使用将它们包含在查询中的范围不会产生结果:

NumericField number = new NumericField("number", Field.Store.YES, true);
Field regular = new Field("normal", "", Field.Store.YES, Field.Index.ANALYZED);

IndexWriter iw = new IndexWriter(FSDirectory.GetDirectory("C:\\temp\\testnum"), new StandardAnalyzer(), true);

Document doc = new Document();
doc.Add(number);
doc.Add(regular);

number.SetIntValue(1);
regular.SetValue("one");
iw.AddDocument(doc);

number.SetIntValue(2);
regular.SetValue("one");
iw.AddDocument(doc);

number.SetIntValue(13);
regular.SetValue("one");
iw.AddDocument(doc);

number.SetIntValue(2000);
regular.SetValue("one");
iw.AddDocument(doc);

number.SetIntValue(9999);
regular.SetValue("one");
iw.AddDocument(doc);

iw.Commit();

IndexSearcher searcher = new IndexSearcher(iw.GetReader());

NumericRangeQuery rangeQ = NumericRangeQuery.NewIntRange("number", 1, 2, true, true);
var docs = searcher.Search(rangeQ);
Console.WriteLine(docs.Length().ToString()); // prints 2

rangeQ = NumericRangeQuery.NewIntRange("number", 13, 13, true, true);
docs = searcher.Search(rangeQ);
Console.WriteLine(docs.Length().ToString()); // prints 1

rangeQ = NumericRangeQuery.NewIntRange("number", 9000, 9998, true, true);
docs = searcher.Search(rangeQ);
Console.WriteLine(docs.Length().ToString()); // prints 0

Console.ReadLine();
于 2012-08-09T19:26:50.427 回答