RavenDB OrderByDescending и Take - неверные результаты

Этот запрос работал у меня до недавнего времени. Теперь у меня в RavenDB 135 документов InstallationSummary. Вместо того, чтобы получать самые свежие документы по времени начала, он в основном работает, но последняя пара, самые последние документы не отображаются из этого запроса. Я неправильно запрашиваю? Есть ли другой способ сделать OrderByDescending и Take с RavenDB, о котором я должен знать? Есть ли ограничение на количество документов, которое я могу правильно запросить?

Примечание. Я отладил это, и запрос действительно возвращает то, что мы видим в сетке. Между моментом выполнения запроса и тем, что отображается в пользовательском интерфейсе, не выполняется никаких преобразований.

IEnumerable<InstallationSummary> installationSummaries =
  QueryAndCacheEtags(session => session.Advanced.LuceneQuery<InstallationSummary>()
  .Include(x => x.ApplicationServerId)
  .Include(x => x.ApplicationWithOverrideVariableGroup.ApplicationId)
  .Include(x => x.ApplicationWithOverrideVariableGroup.CustomVariableGroupId)
  .OrderByDescending(summary => summary.InstallationStart)
  .Take(numberToRetrieve)).Cast<InstallationSummary>().ToList();

В этой сетке должно появиться еще несколько строк со временем начала больше, чем 19.01.2012 18:33:51:

введите описание изображения здесь

Изменить: я удалил Take (numberToRetrieve) из запроса, и я получаю только 128 из 160 документов InstallationSummary. Я вижу все 160 в RavenDB Studio, но только 128 возвращается из запроса. 128 ... 128 ... степень двойки ... Я достиг какого-то предела?

Ладно, похоже, я достиг предела в 128: http://www.blogcoward.com/archive/2010/05/21/RavenDB-and-a-brief-design-philosophy-discussion-with-Ayende.aspx http://codeofrob.com/archive/2010/05/12/ravendb-basic-usage-considerations.aspx

Но почему? У меня там есть метод Take (). Как мне получить 50 самых свежих документов?

В качестве небольшого взлома приведенный ниже запрос покажет, по крайней мере, самый последний. Это не совсем то, что я хочу, потому что мне нужны самые последние 50, независимо от даты. Если с даты начала осталось не более 50, по крайней мере будут отображаться самые последние элементы.

using Raven.Client.Linq;

DateTime startDate = new DateTime(2012, 1, 18);

IEnumerable<InstallationSummary> installationSummaries =
QueryAndCacheEtags(session => session.Query<InstallationSummary>()
.Include(x => x.ApplicationServerId)
.Include(x => x.ApplicationWithOverrideVariableGroup.ApplicationId)
.Include(x => x.ApplicationWithOverrideVariableGroup.CustomVariableGroupId)                        
.Where(x => x.InstallationStart > startDate)
.OrderByDescending(summary => summary.InstallationStart)                        
.Take(numberToRetrieve)
).Cast<InstallationSummary>().ToList();

Мне пришлось перейти от LuceneQuery к просто Query, и мне пришлось добавить предложение Where.


person Bob Horn    schedule 19.01.2012    source источник
comment
Кроме того, что такое QueryAndCacheEtags? Это кажется очень странным, тем более, что RavenDB уже делает это за вас.   -  person Ayende Rahien    schedule 20.01.2012
comment
QueryAndCacheEtags () выполняет запрос и сохраняет etags в кеше на случай, когда объекты будут сохранены позже. Поскольку я не держу сеанс открытым в течение всего времени существования приложения, и пользователь может сэкономить несколько часов после его получения, я сохраняю etags для дальнейшего использования. Это единственный способ заставить это работать. Я все еще изучаю Рэйвен.   -  person Bob Horn    schedule 20.01.2012
comment
Какая сигнатура метода QueryAndCacheEtags () - это Expression ‹Func‹ ... ›› или просто Func ‹..›?   -  person Matt Warren    schedule 27.01.2012
comment
защищенный статический IEnumerable ‹EntityBase› QueryAndCacheEtags (Func ‹IDocumentSession, IEnumerable ‹EntityBase›› func)   -  person Bob Horn    schedule 27.01.2012
comment
Проблема в том, что вы изменили форму запроса IQueryable на IEnumerable, поэтому OrderByDescending не отправляется в RavenDB. По сути, запрос, который вы просите ravenDB выполнить, - это просто session.Query<InstallationSummary>(). Все остальное делается в памяти после того, как было извлечено 128 документов (без применения упорядочения или фильтрации).   -  person Matt Warren    schedule 27.01.2012
comment
Поэтому измените подпись метода на IQueryable<EntityBase> QueryAndCacheEtags(Expression<Func<IDocumentSession, IEnumerable<EntityBase>>> expFunc), и это должно позволить RavenDB использовать предложение Where и части запроса OrderbyDescending.   -  person Matt Warren    schedule 27.01.2012
comment
Я бы порекомендовал использовать Fiddler или просмотреть журнал консоли сервера RavenDB, чтобы вы могли видеть запрос, выполняемый на сервере. Тогда все это будет иметь немного больше смысла.   -  person Matt Warren    schedule 27.01.2012
comment
Отличное предложение, Мэтт. Я только что сделал то, что вы предложили, и, похоже, он работает правильно. Если вы хотите опубликовать это как ответ, я его приму. Хотя я не использовал Expression ‹›. Это необходимо?   -  person Bob Horn    schedule 27.01.2012
comment
Если вы не используете выражение, запрос превратится в IEnumerable ‹T›, а это не то, что вам нужно. Если вы закомментируете / раскомментируете строку QueryAndCacheEtags(..) и наведете указатель мыши на остальную часть вызова функции, Intellisense покажет вам разницу. Все, что не является IQueryable ‹T›, RavenDB не выполняет на сервере.   -  person Matt Warren    schedule 29.01.2012
comment
Поразмыслив еще немного, не уверен, что именно бит IQueryable решил проблему в вашем случае. В любом случае, рад, что у вас это работает   -  person Matt Warren    schedule 29.01.2012
comment
Я изменил подпись QueryAndCacheEtags, чтобы вернуть IQueryable ‹T›. Кажется, сейчас все работает, поэтому я не уверен, что Expression ‹T› необходимо. В любом случае, я поиграю с этим и посмотрю. Еще раз спасибо.   -  person Bob Horn    schedule 29.01.2012


Ответы (2)


Наконец-то проработал реальную проблему.

IEnumerable<InstallationSummary> installationSummaries =
    QueryAndCacheEtags(session => session.Query<InstallationSummary>()
       .Include(x => x.ApplicationServerId)
       .Include(x => x.ApplicationWithOverrideVariableGroup.ApplicationId)
       .Include(x => x.ApplicationWithOverrideVariableGroup.CustomVariableGroupId)                        
       .Where(x => x.InstallationStart > startDate)
       .OrderByDescending(summary => summary.InstallationStart)                        
       .Take(numberToRetrieve))
       .Cast<InstallationSummary>()
       .ToList();

Сигнатура функции QueryAndCacheEtags (..) - Func<T>, а не Expression<Func<T>>. И он возвращает IEnumerable<T>, а не IQueryable<T>

В этой точке оператор преобразуется из IQueryable<T> в IEnumerable<T>. Это означает, что сервер RavenDB обрабатывает только первую часть запроса, в которой нет фильтрации или упорядочивания.

Остальные операторы затем применяются в памяти к 128 возвращаемым элементам. Следовательно, вы не видите заказанный или отфильтрованный элемент должным образом.

Дополнительная информация содержится здесь и здесь

Обычно вам не нужно беспокоиться о разнице между Func<T> и Expression<Func<T>>, компилятор сделает это за вас. Но если вы вводите свой собственный вызов функции в оператор LINQ, вам нужно сделать это правильно.

person Matt Warren    schedule 29.01.2012
comment
В качестве теста я снова изменил код на IEnumerable, и все, похоже, все еще работает. В консоли Raven я вижу pageSize = 50, поэтому я предполагаю, что Take () отправляется на сервер Raven. Теперь мне интересно, есть ли разница между session.Query и session.Advanced.LuceneQuery. Я пытаюсь сделать так, чтобы это больше не работало, чтобы лучше понять, но это все еще работает. Гррр ... - person Bob Horn; 29.01.2012
comment
Лучше всего использовать Intellisense и навести указатель мыши, чтобы Visual Studio сообщила вам, какая версия функции вызывается. Сделайте это с помощью функций .Where (..) и .OrderBy (..). Также неплохо было бы посмотреть на консоль Raven (как вы уже делаете) - person Matt Warren; 29.01.2012
comment
Да, даже при использовании IEnumerable OrderByDescending () - это IRavenQueryable, а Take () - IQueryable. Так что я предполагаю, что все это время дело было не только в IEnumerable и IQueryable. Похоже, мне нужен IQueryable только при использовании LuceneQuery. - person Bob Horn; 30.01.2012
comment
Теперь мне интересно, возможно ли это сделать с помощью LuceneQuery. При попытке использовать LuceneQuery OrderByDescending () является методом расширения в IEnumerable, а Take () не будет работать, потому что компилятор не может преобразовать IEnumerable в IQueryable. - person Bob Horn; 30.01.2012

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

Добавьте в свой запрос строку ниже (или один из ее вариантов):

  .Customize(x => x.WaitForNonStaleResultsAsOfNow())
person Matt Warren    schedule 20.01.2012
comment
Спасибо, Мэтт. В какой-то момент я смогу попробовать это сегодня. Я дам вам знать, если это сработает. - person Bob Horn; 20.01.2012
comment
Ах, Мэтт, я думал, что QueryAndCacheEtags - это какой-то секретный продвинутый метод RavenDb. Не нестандартный: P (Потому что я думал о том же ответе, что и вы): P - person Pure.Krome; 20.01.2012
comment
Мэтт, это работает для LuceneQuery? Я не могу заставить Customize () отображаться в intellisense. - person Bob Horn; 20.01.2012
comment
Кроме того, эта проблема все еще существует на следующий день, когда запущен новый экземпляр пользовательского интерфейса. Я думаю, что все, что было устаревшим, к настоящему времени уже было свежим. Все еще расследуем ... - person Bob Horn; 20.01.2012
comment
Хорошо, с запросом Lucene мне просто нужно было сделать это: .WaitForNonStaleResultsAsOfNow () (без настройки) Но он все еще не показывает самые последние данные. Почему-то прекращается с 19.01.2012 18:33:54. - person Bob Horn; 20.01.2012