好奇心压倒了我。这里有一个解决方案(附带警告)
完整来源如下:
https://github.com/AndyPook/SO_CustomSort-40744865
用于添加可空整数的扩展方法。NumericField使用编码来存储我不想进入的值,所以我只使用了一个sentinel值。
public static class NumericFieldExtensions
{
public static NumericField SetIntValue(this NumericField f, int? value)
{
if (value.HasValue)
f.SetIntValue(value.Value);
else
f.SetIntValue(int.MinValue);
return f;
}
}
一个“理解”哨兵的自定义同胞。这只是lucene的
IntComparator
那是
sealed
因此复制。寻找
int.MinValue
public class NullableIntComparator : FieldComparator
{
private int[] values;
private int[] currentReaderValues;
private string field;
private IntParser parser;
private int bottom; // Value of bottom of queue
private bool reversed;
public NullableIntComparator(int numHits, string field, Parser parser, bool reversed)
{
values = new int[numHits];
this.field = field;
this.parser = (IntParser)parser;
this.reversed = reversed;
}
public override int Compare(int slot1, int slot2)
{
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
// Cannot return values[slot1] - values[slot2] because that
// may overflow
int v1 = values[slot1];
int v2 = values[slot2];
if (v1 == int.MinValue)
return reversed ? -1 : 1;
if (v2 == int.MinValue)
return reversed ? 1 : -1;
if (v1 > v2)
{
return 1;
}
else if (v1 < v2)
{
return -1;
}
else
{
return 0;
}
}
public override int CompareBottom(int doc)
{
if (bottom == int.MinValue)
return reversed ? -1 : 1;
// TODO: there are sneaky non-branch ways to compute
// -1/+1/0 sign
// Cannot return bottom - values[slot2] because that
// may overflow
int v2 = currentReaderValues[doc];
if (v2 == int.MinValue)
return reversed ? 1 : -1;
if (bottom > v2)
{
return 1;
}
else if (bottom < v2)
{
return -1;
}
else
{
return 0;
}
}
public override void Copy(int slot, int doc)
{
values[slot] = currentReaderValues[doc];
}
public override void SetNextReader(IndexReader reader, int docBase)
{
currentReaderValues = FieldCache_Fields.DEFAULT.GetInts(reader, field, parser);
}
public override void SetBottom(int bottom)
{
this.bottom = values[bottom];
}
public override IComparable this[int slot] => values[slot];
}
最后,a
FieldComparatorSource
定义自定义排序
public class NullableIntFieldCompatitorSource : FieldComparatorSource
{
public override FieldComparator NewComparator(string fieldname, int numHits, int sortPos, bool reversed)
{
return new NullableIntComparator(numHits, fieldname, FieldCache_Fields.NUMERIC_UTILS_INT_PARSER, reversed);
}
}
一些测试。看看
Sort
private class DataDoc
{
public int ID { get; set; }
public int? Data { get; set; }
}
private IEnumerable<DataDoc> Search(Sort sort)
{
var result = searcher.Search(new MatchAllDocsQuery(), null, 99, sort);
foreach (var topdoc in result.ScoreDocs)
{
var doc = searcher.Doc(topdoc.Doc);
int id = int.Parse(doc.GetFieldable("id").StringValue);
int data = int.Parse(doc.GetFieldable("data").StringValue);
yield return new DataDoc
{
ID = id,
Data = data == int.MinValue ? (int?)null : data
};
}
}
[Fact]
public void SortAscending()
{
var sort = new Sort(new SortField("data", new NullableIntFieldCompatitorSource()));
var result = Search(sort).ToList();
Assert.Equal(4, result.Count);
Assert.Equal(new int?[] { 100, 300, 400, null }, result.Select(x => x.Data));
}
[Fact]
public void SortDecending()
{
var sort = new Sort(new SortField("data", new NullableIntFieldCompatitorSource(),true));
var result = Search(sort).ToList();
Assert.Equal(4, result.Count);
Assert.Equal(new int?[] { 400, 300, 100, null }, result.Select(x => x.Data));
}