如何在C#中为RavenDB正确创建Map / Reduce索引
我正在开发一个在后端使用RavenDB的应用程序。 这是我第一次使用Raven,而我正在努力使用Map / Reduce。
我一直在阅读文档 ,但不幸的是我在这个过程中没有任何进展。
基本上我有成千上万的这样的文件。
{ ..... "Severity": { "Code": 6, "Data": "Info" }, "Facility": { "Code": 16, "Data": "Local Use 0 (local0)" }, ..... }
在其中,我需要使用看起来像这样的输出进行单个查询。
{"Severity": [ {"Emergency":0}, {"Alert":0}, {"Critical":0}, {"Error":0}, {"Warning":0}, {"Notice":0}, {"Info":2711}, {"Debug":410} ], "Facility": [ {"Kernel Messages":0}, {"User-Level Messages":0}, {"Mail System":0}, {"System Daemons":0}, {"Security/Authorization Messages":0}, {"Internal Syslogd Messages":0}, {"Line Printer Subsystem":2711}, {"Network News Subsystem":410}, .... {"Local Use 0 (local0)": 2574}, ... ]}
因此,Severity / Facility Array中的“Key”是上述json数据的Data
部分,Severity / Facility Array中的“value”是每个Code
类型的文档Count
。
例:
以上述数据为指导,
我的数据库中有2711个文档,其中包含
Info
严重性。
我的数据库中有410个文档,其中包含Debug
严重性。
我的数据库中有2574个文档,其中包含local0
工具。
等等…
我想做的是在应用程序启动时生成适当的索引(或检查它们是否已存在),但我甚至不知道从哪里开始。
注意:应用程序需要生成索引,仅仅手动将其写入RavenDB Web UI是不够的。
您需要结合几种技术来实现这一目标,但这是非常可行的。
这是一个应该适合你的索引。
public class MyIndex : AbstractMultiMapIndexCreationTask { public class ReduceResult { public string Source { get; set; } public string Code { get; set; } public string Data { get; set; } public int Count { get; set; } } public MyIndex() { AddMap(docs => from doc in docs select new { Source = "Severity", doc.Severity.Code, doc.Severity.Data, Count = 1 }); AddMap (docs => from doc in docs select new { Source = "Facility", doc.Facility.Code, doc.Facility.Data, Count = 1 }); Reduce = results => from result in results group result by new { result.Source, result.Code } into g select new { g.Key.Source, g.Key.Code, g.First().Data, Count = g.Sum(x => x.Count) }; TransformResults = (database, results) => from result in results group result by 0 into g select new { Severity = g.Where(x => x.Source == "Severity") .ToDictionary(x => x.Data, x => x.Count), Facility = g.Where(x => x.Source == "Facility") .ToDictionary(x => x.Data, x => x.Count) }; } }
您还需要一个用于转换结果的容器类:
public class MyDocCounts { public IDictionary Severity { get; set; } public IDictionary Facility { get; set; } }
您可以这样查询:
var result = session.Query() .As() .ToList().First();
.ToList()
似乎是多余的,但它是必要的,因为我们在转换中进行分组。
这里有完整的unit testing。 输出如下:
{ "Severity": { "AAA": 20, "BBB": 20, "CCC": 20, "DDD": 20, "EEE": 20 }, "Facility": { "FFF": 20, "GGG": 20, "HHH": 20, "III": 20, "JJJ": 20 } }