我有一个使用 Lucene.Net 3.0.3 和有效负载的解决方案。我不确定这是否是使用当前比 .net 端口领先的 java 版本完成此任务的最佳方法。
它的工作原理是为应该自定义评分的术语分配一个有效负载、一个自定义字节数组,以及一个覆盖 ScorePayload 的自定义相似度来解析字节数组以进行自定义过滤。 (这需要调用此方法的查询,例如 PayloadTermQuery)。
这个高度人为的示例代码将根据 (id % 3) 对术语进行评分。 (三的倍数为零)。您可以将其与 PositiveScoresOnlyCollector 结合使用,以忽略得分为零的匹配项。
using System;
using System.IO;
using Lucene.Net.Analysis;
using Lucene.Net.Analysis.Tokenattributes;
using Lucene.Net.Documents;
using Lucene.Net.Index;
using Lucene.Net.Search;
using Lucene.Net.Search.Payloads;
using Lucene.Net.Store;
public static class Program {
public static void Main() {
var directory = new RAMDirectory();
// Initialization; create 50 documents with payload
var writer = new IndexWriter(directory, new KeywordAnalyzer(), true, IndexWriter.MaxFieldLength.UNLIMITED);
for (var i = 0; i < 50; ++i) {
AddDocument(writer, i, "lorem ipsum etc blah blah");
}
writer.Commit();
var searcher = new IndexSearcher(directory, readOnly: true);
searcher.Similarity = new ShazaamPayloadSimilarity();
// The term we'll be looking for. This should match all documents.
var term = new Term("Data", "lorem");
var query = new PayloadTermQuery(term, new MaxPayloadFunction());
var topDocs = searcher.Search(query, 40);
// This is a bad example of a FieldCache usage.
var iValues = FieldCache_Fields.DEFAULT.GetStrings(searcher.IndexReader, "Id");
foreach (var scoreDoc in topDocs.ScoreDocs) {
Console.WriteLine("Score: {0:0.0000} i={1}", scoreDoc.Score, iValues[scoreDoc.Doc]);
}
Console.ReadLine();
}
public static void AddDocument(IndexWriter writer, Int32 id, String data) {
var payload = BitConverter.GetBytes(id);
var analyzer = new ShazaamPayloadAnalyzer(payload);
var textReader = new StringReader(data);
var document = new Document();
document.Add(new Field("Id", id.ToString(), Field.Store.NO, Field.Index.NOT_ANALYZED));
document.Add(new Field("Data", analyzer.TokenStream(null, textReader)));
writer.AddDocument(document);
}
}
public class ShazaamPayloadAnalyzer : Analyzer {
private readonly Byte[] _value;
public ShazaamPayloadAnalyzer(Byte[] value) {
_value = value;
}
public override TokenStream TokenStream(String fieldName, TextReader reader) {
TokenStream result = new WhitespaceTokenizer(reader);
result = new ShazaamPayloadFilter(result, _value);
return result;
}
}
public class ShazaamPayloadFilter : TokenFilter {
private readonly byte[] _payload;
private readonly IPayloadAttribute _payloadAttr;
public ShazaamPayloadFilter(TokenStream input, Byte[] payload)
: base(input) {
_payload = payload;
_payloadAttr = AddAttribute<IPayloadAttribute>();
}
public override Boolean IncrementToken() {
if (input.IncrementToken()) {
_payloadAttr.Payload = new Payload(_payload);
return true;
}
return false;
}
}
public class ShazaamPayloadSimilarity : DefaultSimilarity {
public override Single ScorePayload(Int32 docId, String fieldName, Int32 start, Int32 end, Byte[] payload, Int32 offset, Int32 length) {
var originalValue = BitConverter.ToInt32(payload, startIndex: 0);
// Advanced logic ahead!
return (originalValue % 3);
}
}