Lucene中的TFIDF计算同时限制时间范围

时间:2013-12-02 17:35:14

标签: lucene tf-idf

我在不同的时间里收到了很多文件。 现在我需要在一段时间内计算文档的tfidf。 以下是我要做的事情,例如:

我有一百万份文本文件一年,我将在一个月内将这些文件作为语料库。 我想计算每个月的tfidf,即计算一个月内的术语频率,并将剩余月份的逆文档频率乘以

使用 lucene 索引数据(文本,时间等),我只是想知道lucene是否可以促进这种情况的计算 我知道Lucene可以帮助我获得术语频率和文档频率,但是有没有用于限制计算的时间范围的API?

非常感谢。

1 个答案:

答案 0 :(得分:1)

我已经使用Lucene.Net 3.0.3和有效负载获得了解决方案。我不确定这是否是使用java-version实现此目的的最佳方法,该版本目前比.net端口领先一步。

它的工作原理是将有效负载,自定义字节数组分配给应该自定义评分的术语,以及一个自定义的相似性,它会覆盖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);
    }
}