How to properly create a Map / Reduce index for RavenDB in C #

I am working on an application that uses RavenDB on the back. This is my first time using Raven and I am struggling with Map / Reduce.

I read the doc , but unfortunately I do not get anywhere else in the process.

Basically, I have thousands of such documents.

{ ..... "Severity": { "Code": 6, "Data": "Info" }, "Facility": { "Code": 16, "Data": "Local Use 0 (local0)" }, ..... } 

And from this, I need to make one request with the output, which looks like this.

 {"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}, ... ]} 

Thus, the “key” in the “Severity / Object” array is the Data part of the above json data, and the “value” in the Severity / Facility array is a Count document for each Code type.

Example:
Using the above data as a guide,

There are 2711 documents with Info severity in my database.
There are 410 documents with Debug severity in my database.
There are 2574 documents in my database with the setting local0 .
etc.


What I would like to do is generate the appropriate indexes when the application starts (or check if they already exist), but I don’t even know where to start.

Note: the application must generate an index, this is not enough to simply manually write it to the RavenDB web interface.

+3
source share
1 answer

You will need to combine several methods to achieve this, but it is doable.

Here is an index that should work well for you.

 public class MyIndex : AbstractMultiMapIndexCreationTask<MyIndex.ReduceResult> { 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<MyDoc>(docs => from doc in docs select new { Source = "Severity", doc.Severity.Code, doc.Severity.Data, Count = 1 }); AddMap<MyDoc>(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) }; } } 

You also need a container class for the converted result:

 public class MyDocCounts { public IDictionary<string, int> Severity { get; set; } public IDictionary<string, int> Facility { get; set; } } 

You request it like this:

 var result = session.Query<MyIndex.ReduceResult, MyIndex>() .As<MyDocCounts>() .ToList().First(); 

.ToList() may seem redundant, but it is necessary because we are grouping into a transformation.

The full unit test is here . The result of which is as follows:

 { "Severity": { "AAA": 20, "BBB": 20, "CCC": 20, "DDD": 20, "EEE": 20 }, "Facility": { "FFF": 20, "GGG": 20, "HHH": 20, "III": 20, "JJJ": 20 } } 
+4
source

Source: https://habr.com/ru/post/1489783/


All Articles