2013-02-25 2 views
3

Я работаю над приложением, которое использует RavenDB на задней панели. Это мой первый опыт использования Raven, и я борюсь с Map/Reduce.Как правильно создать индекс карты/уменьшения для RavenDB в C#

Я был reading the doc's, но, к сожалению, я не получаю нигде в этом процессе.

В основном у меня есть тысячи таких документов.

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

Причем «ключ» в массиве Серьезность/Facility является Data часть приведенных выше данных JSON, и «значение» в массиве Серьезность/Facility является документом Count для каждого типа Code.

Пример:
Используя приведенные выше данные, в качестве ориентира,

Есть 2711 документов в моей базе данных с Info тяжести.
В моей базе данных 410 документов с серьезностью Debug.
В моей базе данных 2574 документа с объектом local0.
и т.д ...


То, что я хотел бы сделать, это генерировать соответствующие индексы, когда приложение запускается (или проверить, если они уже существуют), но я даже не знаю, где начать.

Примечание: приложение должно сгенерировать индекс, этого недостаточно, чтобы просто вручную записать его в веб-интерфейс RavenDB.

+0

Нужны ли свойства 'Code' для индекса? –

+0

«Код» и «Данные» всегда совпадают. IE: 'Код: 6' =' Данные: Информация' каждый раз. –

+0

Хорошо, но вы не включаете их в вывод, поэтому они по сути не имеют отношения к этой задаче, не так ли? Или существует риск столкновения, что два разных кода будут иметь одну и ту же строку данных? –

ответ

4

Для достижения этого вам необходимо объединить несколько приемов, но это вполне выполнимо.

Вот индекс, который должен хорошо работать для вас.

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) 
          }; 
    } 
} 

Вы также нужен класс-контейнер для преобразованного результата:

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

Вы бы запросить его так:

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

.ToList() может показаться излишним, но это необходимо, потому что мы группируются в преобразовании.

Полный блок испытаний here. Выход которого выглядит следующим образом:

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

Итак, у меня была возможность попробовать это, однако мне интересно, как я называю это так, что индекс построен на запуске приложения. В настоящее время выполняется запрос следующего исключения: «Нет индекса с именем: MyIndex' –

+0

nm, я получил его ...« IndexCreation.CreateIndexes (typeof (SyslogDocumentCountIndex) .Assembly, DataDocumentStore.DocumentStore); ' –

+1

Это нормально, но это создаст все индексы, которые вы определили где угодно в своей сборке. См. Тестовый блок, на который я ссылаюсь, если вы хотите создать только один индекс. –

Смежные вопросы