【问题标题】:Luke reveals unknown term values for numeric fields in indexLuke 揭示了索引中数字字段的未知术语值
【发布时间】:2012-08-06 15:47:24
【问题描述】:

我们使用 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  

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

未知值从何而来?

【问题讨论】:

    标签: lucene lucene.net luke


    【解决方案1】:

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

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

    NumericField documentation

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

    NumericRangeQuery documentation 中提供有关精度步长的更多详细信息:

    precisionStep 的正确值取决于使用情况和数据类型:

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

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

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

    • 对于较大的低基数字段 精确的步骤是好的。如果基数

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

    编辑

    小样本,由此生成的索引将在 luke 中显示值为 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();
    

    【讨论】:

    • "..但没有被任何文件引用。"当使用 Lukes 的“按术语浏览”功能时,它会显示很多关于这些术语的文档。实际上,它显示的文档数量与排名靠前的术语表中的排名相同。例如,对于术语 9984,它返回 19252 个文档。
    • 也许我的措辞是错误的,我的意思是查询这些值不会产生结果。我编辑了问题并添加了一个示例来演示观察到的行为
    • 谢谢!我没有意识到“按术语浏览”和“查询术语”会产生不同的结果。
    猜你喜欢
    • 2019-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-05
    • 1970-01-01
    • 2016-01-17
    • 2021-01-23
    • 1970-01-01
    相关资源
    最近更新 更多