#c# #ravendb
#c# #ravendb
Вопрос:
У меня есть следующий тест:
public class ListingEventTest
{
public ListingEventTest()
{
Artists = new List<ArtistTest>();
}
public List<ArtistTest> Artists { get; set; }
public string Id { get; set; }
public string Name { get; set; }
public double Popularity { get; set; }
}
public class ArtistTest
{
public string Id { get; set; }
public Stat Stats { get; set; }
}
public class Stat
{
public double Popularity { get; set; }
}
public class ArtistsWithStats_ByName : AbstractIndexCreationTask<ListingEventTest>
{
public ArtistsWithStats_ByName()
{
Map = listingEvents => from listingEvent in listingEvents
let artists = LoadDocument<ArtistTest>(listingEvent.Artists.Select(x => x.Id))
select new
{
Popularity = artists.Average(x => x.Stats.Popularity),
listingEvent.Name
};
}
}
[TestFixture]
public class IndexCanDoSums
{
[Test]
public async void WhenListingEventArtistsHaveStatsIndexReturnsPopularity()
{
var store = new EmbeddableDocumentStore
{
UseEmbeddedHttpServer = true,
Configuration =
{
RunInUnreliableYetFastModeThatIsNotSuitableForProduction = true,
RunInMemory = true,
}
}.Initialize();
IndexCreation.CreateIndexes(typeof(ArtistsWithStats_ByName).Assembly, store);
using (var session = store.OpenAsyncSession())
{
for (int i = 0; i < 10; i )
{
var le = new ListingEventTest
{
Name = "test-" i
};
await session.StoreAsync(le);
for (int j = 0; j < 2; j )
{
var artist = new ArtistTest
{
Stats = new Stat
{
Popularity = 0.89d
}
};
await session.StoreAsync(artist);
le.Artists.Add(artist);
}
await session.SaveChangesAsync();
}
}
Thread.Sleep(2000);
using (var session = store.OpenAsyncSession())
{
var query = session
.Advanced.AsyncLuceneQuery<ListingEventTest>("ArtistsWithStats/ByName");
var result = await query.ToListAsync();
result.First().Popularity.Should().NotBe(0);
}
}
}
Когда я запрашиваю, этот индекс Popularity
всегда равен 0.
Есть идеи?
Комментарии:
1. Приведите небольшой, полный пример, демонстрирующий проблему, которую мы действительно можем попробовать.
2. Но это должно работать правильно?
3. Ну нет, код, который вы ввели, даже не будет компилироваться, потому что после него нет запятой
.Name
. Говорить о том, что он должен или не должен делать, — это моральный вопрос; вы утверждаете, что он делает определенную вещь; демонстрация правильности утверждения — первый шаг к его пониманию. Возможно, вы допустили больше опечаток, и это объясняет неожиданный результат. Возможно, у рассматриваемого исполнителя статистика равна нулю.4. Я настрою неудачный тест
5. @EricLippert обновил q с помощью неудачного теста
Ответ №1:
Здесь происходят некоторые забавные вещи.
Во-первых, вы сохраняете ArtistTest в документе ListingEventTest, а не как отдельные документы, поэтому в вашем индексе нет необходимости вызывать LoadDocument, вы могли бы просто сделать:
from listingEvent in listingEvents
from artist in listingEvent.Artists
select ...
Во-вторых, индекс только для отображения очень похож на индекс SQL, где вы просто вызываете столбцы, к которым хотите иметь возможность запрашивать. Здесь вы выполняете вычисления для набора скрытых свойств, и у вас есть свойство верхнего уровня, в котором вы хотите сохранить эту информацию, но в итоге получается так, что ваше вычисленное значение свойства попадает в индекс Lucene (чтобы вы могли запрашивать по популярности, если хотите), но данныето, что возвращается, прямо из неизмененного документа. Карта определяет, что входит в Lucene, что указывает на идентификатор документа, а затем хранилище документов возвращает документы в качестве результатов.
Это можно было бы несколько изменить, вызвав Store(x => x.Popularity)
конструктор индекса, который сохранит значение, которое будет вызвано позже, но, честно говоря, я не уверен, выиграет ли ваше вычисленное значение или значение документа (которое равно нулю).
Учитывая это, становится довольно запутанным иметь свойство document с единственной целью — попытаться заполнить его во время индексации, поэтому обычно лучше иметь класс, который представляет отображенное состояние, а затем реализовать AbstractIndexCreationTask<TDocument, TReduceResult>
, где TReduceResult
класс будет содержать только результат вашего сопоставления, а именнои Name
Popularity
столбцы.
Затем, когда вы запрашиваете from , вы можете использовать .ProjectFromIndexFieldsInto<T>()
для получения результатов из сохраненных результатов индекса, а не из хранилища документов.
Комментарии:
1. Извините — это должно быть DenormalizedReference<ArtistTest>
2. Но это выглядит правильно — спасибо, что нашли время 🙂
3. Хммм — я не могу использовать ProjectFromIndexFieldsInto в lucenequery