【问题标题】:Lucene - Sorting Date as NumericFieldLucene - 将日期排序为 NumericField
【发布时间】:2016-07-18 17:03:37
【问题描述】:

在尝试对日期时间(长)数字字段进行排序时,我总是得到一个 FormatException。

将字符串转换为日期时间时,解析字符串以获取 将每个变量放入 DateTime 对象之前的日期。

添加数字字段:

doc.Add(new NumericField("creationDate",  Field.Store.YES, true)
   .SetLongValue(DateTime.UtcNow.Ticks);

添加排序:

// boolean query    
var sortField = new SortField("creationDate", SortField.LONG, true);
var inverseSort = new Sort(sortField);
var results = searcher.Search(query, null, 100, inverseSort); // exception thrown here

检查索引,我可以验证“creationDate”字段是否存储“长”值。什么可能导致此异常?

编辑:

查询

var query = new BooleanQuery();
foreach (var termQuery in incomingProps.Select(p => new TermQuery(new Term(kvp.Key, kvp.Value.ToLowerInvariant()))
{
  query.Add(new BooleanClause(termQuery , Occur.Must));
}

return query;

版本:Lucene.Net 3.0.3

更新:

这个问题再次出现,现在是 INT 值。 我下载了 Lucene.Net 源代码并调试了问题。

所以它在 FieldCache 中的某个地方,当尝试将值“`\b\0\0\0”解析为 Integer 时,这似乎有点奇怪。

我将这些值添加为数字字段:

doc.Add(new NumericField(VersionNum, int.MaxValue, Field.Store.YES, 
true).SetIntValue(VersionValue));

当我应该得到至少 1 次回击时,我得到了例外。 检查索引后,我看到该字段的术语如下:

字段文本为:

编辑:

我硬编码了一个 int 值并添加了一些段:

doc.Add(new Field(VersionNum, NumericUtils.IntToPrefixCoded(1), Field.Store.YES, Field.Index.NOT_ANALYZED_NO_NORMS));

这导致将版本字段存储为:

而且,当我尝试排序时,我得到了解析错误:

var sortVersion = new SortField(VersionNum, SortField.INT, true);

对于每个异常,Lucene 都会尝试解析“ \b\0\0\0 ”。 查看存储为字符串的前缀编码,我猜 1 将转换为“ \b\0\0\0\1 ”?

Lucene 是否可能在 FieldCache 中留下一些垃圾?

【问题讨论】:

  • 你能说明“查询”是如何创建的吗?
  • @AndyPook 刚刚编辑了问题并添加了“查询”。如果我按 DOC 排序,效果很好。
  • 查询中不包含日期字段,仅用于排序。假设我只查询一个自定义字段 ID,该字段被授予返回一组结果。
  • 你为什么使用 NumericUtils 而不是 NumericField?
  • 我不是,只是尝试不同的选择。我使用的是 NumericField。

标签: string lucene lucene.net numeric


【解决方案1】:

这是一个单元测试,它试图捕捉您的要求。测试通过。你能解释一下你的代码有什么区别吗? (发布完整的失败测试将有助于我们了解您在做什么:-))

using System;
using System.Linq;
using System.Collections.Generic;
using Microsoft.VisualStudio.TestTools.UnitTesting;

using Lucene.Net.Search;
using Lucene.Net.Index;
using Lucene.Net.Analysis.Standard;
using Lucene.Net.QueryParsers;
using Lucene.Net.Documents;
using Lucene.Net.Store;

namespace SO_answers
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestShopping()
        {
            var item = new Dictionary<string, string>
            {
                {"field1", "value1" },
                {"field2", "value2" },
                {"field3", "value3" }
            };

            var writer = CreateIndex();
            Add(writer, item);
            writer.Flush(true, true, true);

            var searcher = new IndexSearcher(writer.GetReader());
            var result = Search(searcher, item);

            Assert.AreEqual(1, result.Count);

            writer.Dispose();
        }

        private List<string> Search(IndexSearcher searcher, Dictionary<string, string> values)
        {
            var query = new BooleanQuery();
            foreach (var termQuery in values.Select(kvp => new TermQuery(new Term(kvp.Key, kvp.Value.ToLowerInvariant()))))
                query.Add(new BooleanClause(termQuery, Occur.MUST));

            return Search(searcher, query);
        }

        private List<string> Search(IndexSearcher searcher, Query query)
        {
            var sortField = new SortField("creationDate", SortField.LONG, true);
            var inverseSort = new Sort(sortField);
            var results = searcher.Search(query, null, 100, inverseSort); // exception thrown here


            var result = new List<string>();
            var matches = results.ScoreDocs;
            foreach (var item in matches)
            {
                var id = item.Doc;
                var doc = searcher.Doc(id);
                result.Add(doc.GetField("creationDate").StringValue);
            }
            return result;
        }

        IndexWriter CreateIndex()
        {
            var directory = new RAMDirectory();

            var analyzer = new StandardAnalyzer(Lucene.Net.Util.Version.LUCENE_30);
            var writer = new IndexWriter(directory, analyzer, new IndexWriter.MaxFieldLength(1000));

            return writer;
        }
        void Add(IndexWriter writer, IDictionary<string, string> values)
        {
            var document = new Document();
            foreach (var kvp in values)
                document.Add(new Field(kvp.Key, kvp.Value.ToLowerInvariant(), Field.Store.YES, Field.Index.ANALYZED));
            document.Add(new NumericField("creationDate", Field.Store.YES, true).SetLongValue(DateTime.UtcNow.Ticks));

            writer.AddDocument(document);
        }
    }
}

【讨论】:

  • 感谢您的回答,您一直是一个很大的帮助。然而,在这种情况下,我有一个“被遗忘”的文档,其中有数千个日期值不正确。我会将您的答案标记为已接受。谢谢
  • 阿罗哈,我已将您的答案标记为已接受。这个问题是随机发生的,我不知道发生了什么。但是,我有一些新发现可能会导致根本原因。
  • 您发现问题了吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2010-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多