2016-11-16 22 views
1

В примере II Indexing Related Documents индекс строится над авторами по имени и названию книги. Соответствующие организации выглядят следующим образом:Как индексировать связанные документы в обратном направлении в Ravendb

public class Book { 
    public string Id { get; set; } 
    public string Name { get; set; } 
} 

public class Author { 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public IList<string> BookIds { get; set; } 
} 

I.e. только Author содержит информацию об отношении. Эта информация используется при построении указанного индекса.

Но как бы я построил индекс над книгами авторов (предполагая, что книга может иметь несколько авторов)?

Edit:

Книга/автор аналогия идет только до сих пор. Я сделаю пример, который ближе к моей реальной пользы дела:

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

public class Location { 
    public string Id { get; set; } 
    public double Latitude { get; set; } 
    public double Longitude { get; set; } 
} 

public class Task { 
    public string Id { get; set; } 
    public string Name { get; set; } 
    public string LocationId { get; set; } 
    public Status TaskStatus { get; set; } 
} 

у меня есть конечная точка, где подают Locations как GeoJSON на вид карты в клиент. Я хочу покрасить местоположения в зависимости от статуса связанных с ними задач. Карта обычно показывает 500-2000 мест.

Запрос местоположений реализован как потоковый запрос.

Использование запроса-метод, указанный в первоначальном ответе Ayende, я мог бы сделать что-то вроде:

foreach (var location in locationsInView) 
{ 
    var completedTaskIds = await RavenSession.Query<Task>() 
     .Where(t => t.LocationId == location.Id && t.TaskStatus == Status.Completed) 
     .ToListAsync(); 

    // 
    // Construct geoJson from location and completedTaskIds 
    // 
} 

Это приводит к 500-2000 запросов выполняется против RavenDB, что не кажется правильным. Вот почему я изначально думал, что мне нужен индекс для построения моего результата.

С тех пор я прочитал, что RavenDB кэширует все по умолчанию, так что это может быть не проблема. С другой стороны, реализовав этот подход, я получаю сообщение об ошибке («... максимальное количество запросов (30), разрешенных для этого сеанса ...»).

Что это за хороший способ крепления?

+0

У вас может быть что-то вроде этого? '.Where (t => locationsInView.Any (x => x.Id == t.LocationId) && ....' вместо foreach? – TryingToImprove

+0

Я пробовал это. Но нет. Я думаю, потому что Ворон не может выполнить произвольный C# внутри, поэтому 'locationsInView.Any (...)' не работает. – AdamAL

ответ

0

Вы можете сделать это, используя multi map/reduce index. (Result). Это сопоставление затем уменьшает группировку по Id и сохраняет только соответствующие фрагменты, создавая «слияние» истин относительно каждого объекта (Book в этом случае). Поэтому, используя пример книги/автора, в котором несколько авторов могли внести вклад в одну и ту же книгу, вы могли бы сделать что-то вроде следующего.

Обратите внимание, что на карте и этапах уменьшения должен выводиться один и тот же тип объекта, поэтому author.Id завернут в список во время сопоставления с автором.

Author.Name s исключаются для краткости, но могут быть включены точно так же, как Author.Id.

public class BooksWithAuthors : AbstractMultiMapIndexCreationTask<BooksWithAuthors.Result> 
{ 
    public class Result 
    { 
     string Id; 
     string Title; 
     IEnumerable<string> AuthorIds; 
    } 

    public BooksWithAuthors() 
    { 
     AddMap<Book>(book => from book in books 
          select new 
          { 
           Id = book.Id, 
           Title = book.Title, 
           AuthorIds = null; 
          }); 

     AddMap<Author>(author => from author in authors 
           from bookId in author.bookIds 
           select new 
           { 
            Id = bookId, 
            Title = null, 
            AuthorIds = new List<string>(){ author.Id }; 
           }); 

     Reduce = results => from result in results 
          group result by result.Id 
          into g 
          select new 
          { 
           Id = g.Key, 
           Title = g.Select(r => r.Title).Where(t => t != null).First(), 
           AuthorIds = g.Where(r => r.AuthorIds != null).SelectMany(r => r.AuthorIds) 
          }; 
    } 
} 
1

Вы не можете индексировать их таким образом. Но вам также не нужно.

Если вы хотите найти все книги автора, вы загружаете автора, и у вас есть полный список.

+0

Спасибо за ваш ответ, Айенде! Я, вероятно, не был достаточно конкретным. Я обновил вопрос. – AdamAL

+0

Теперь я реализовал индекс akin на «LocationsWithTaskIds», используя индекс с несколькими картами/уменьшением. Кажется, он работает нормально, но, поскольку вы сказали, что это невозможно, я задаюсь вопросом, считаете ли вы его плохой практикой. Не могли бы вы уточнить? – AdamAL