2012-04-06 8 views
26

wiem warianty tej kwestii zostały poproszone przed (nawet mnie), ale ja nadal nie rozumiem, co nieco na ten temat ...Prawidłowe sposób odzyskać ponad 128 dokumentów z RavenDB

It było moje zrozumienie, że można odzyskać więcej dokumentów niż ustawienie 128 domyślnej w ten sposób:

session.Advanced.MaxNumberOfRequestsPerSession = int.MaxValue; 

a ja dowiedziałem się, że klauzula WHERE powinno być ExpressionTree zamiast Func, tak że jest on traktowany jako Queryable zamiast of Enumerable. Pomyślałem, że to powinno zadziałać:

public static List<T> GetObjectList<T>(Expression<Func<T, bool>> whereClause) 
{ 
    using (IDocumentSession session = GetRavenSession()) 
    { 
     return session.Query<T>().Where(whereClause).ToList();     
    } 
} 

Jednak zwraca tylko 128 dokumentów. Czemu?

Uwaga, tutaj jest kod, który wywołuje powyższą metodę:

RavenDataAccessComponent.GetObjectList<Ccm>(x => x.TimeStamp > lastReadTime); 

Jeśli dodać Take (n), to mogę dostać jak najwięcej dokumentów, jak mi się podoba. Na przykład, to zwraca 200 dokumentów:

return session.Query<T>().Where(whereClause).Take(200).ToList(); 

oparciu o to wszystko, wydaje się, że właściwym sposobem, aby pobrać tysiące dokumentów jest ustawiony MaxNumberOfRequestsPerSession i używać Take() w zapytaniu. Czy to prawda? Jeśli nie, to jak to zrobić?

Do mojej aplikacji potrzebuję pobrać tysiące dokumentów (które zawierają bardzo mało danych). Przechowujemy te dokumenty w pamięci i wykorzystujemy je jako źródło danych dla wykresów.

** EDIT **

Próbowałem za pomocą int.MaxValue w moim Take():

return session.Query<T>().Where(whereClause).Take(int.MaxValue).ToList(); 

i że wraca 1024. Argh. Jak uzyskać więcej niż 1024?

** EDIT 2 - Przykładowy dokument przedstawiający dane **

{ 
    "Header_ID": 3525880, 
    "Sub_ID": "120403261139", 
    "TimeStamp": "2012-04-05T15:14:13.9870000", 
    "Equipment_ID": "PBG11A-CCM", 
    "AverageAbsorber1": "284.451", 
    "AverageAbsorber2": "108.442", 
    "AverageAbsorber3": "886.523", 
    "AverageAbsorber4": "176.773" 
} 
+0

Czy myślisz o umieszczeniu wszystkich 10000 punktów w jednym dokumencie jako kolekcji? – SteadyEddi

Odpowiedz

20

Funkcja Take(n) tylko daje do 1024 domyślnie. Można jednak zmienić to ustawienie domyślne w Raven.Server.exe.config:

<add key="Raven/MaxPageSize" value="5000"/> 

Aby uzyskać więcej informacji, zobacz: http://ravendb.net/docs/intro/safe-by-default

+0

Dzięki, Mike. Myślę, że to ostatecznie będzie akceptowana odpowiedź, ale chciałbym zobaczyć, czy ktoś inny ma na to inny punkt widzenia. –

5

Ilość żądanie jednej sesji jest odrębną koncepcję następnie liczba dokumentów pobranych za rozmowę. Sesje są krótkotrwałe i oczekuje się, że będzie ich niewiele.

Jeśli otrzymujesz ponad 10 sztuk ze sklepu (jeszcze mniej niż domyślnie 128) do spożycia przez ludzi, oznacza to, że coś jest nie tak lub Twój problem wymaga innego myślenia, niż załadowanie ciężarów dokumentów pochodzących ze składnicy danych.

Indeksowanie RavenDB jest dość wyrafinowane. Dobry artykuł na temat indeksowania here i aspektów here.

Jeśli zachodzi potrzeba przeprowadzenia agregacji danych, utwórz mapę/zmniejsz indeks, co spowoduje gromadzenie danych np.:

Index:

from post in docs.Posts 
    select new { post.Author, Count = 1 } 

    from result in results 
    group result by result.Author into g 
    select new 
    { 
     Author = g.Key, 
     Count = g.Sum(x=>x.Count) 
    } 

Zapytanie:

session.Query<AuthorPostStats>("Posts/ByUser/Count")(x=>x.Author)(); 
+1

Jak rozwiązać ten problem? Firma chce zobaczyć wykres pokazujący ostatnie 24 godziny wartości punktów danych. Każdy dokument jest punktem danych, a jest ich 10 000 w ciągu ostatnich 24 godzin. Jak to sporządzić, bez doprowadzania wszystkich danych? –

+0

Myślę, że możesz to osiągnąć, tworząc indeksy lub [aspekty] (http://ravendb.net/docs/client-api/faceted-search). –

+0

Właśnie zauważyłem, że "każdy dokument jest punktem danych" - czy możesz pokazać przykład tego dokumentu? –

16

Take (n) funkcja będzie tylko dać do 1024 domyślnie. Jednak można go używać w parze z SKIP (N), aby uzyskać wszystkie

 var points = new List<T>(); 
     var nextGroupOfPoints = new List<T>(); 
     const int ElementTakeCount = 1024; 
     int i = 0; 
     int skipResults = 0; 

     do 
     { 
      nextGroupOfPoints = session.Query<T>().Statistics(out stats).Where(whereClause).Skip(i * ElementTakeCount + skipResults).Take(ElementTakeCount).ToList(); 
      i++; 
      skipResults += stats.SkippedResults; 

      points = points.Concat(nextGroupOfPoints).ToList(); 
     } 
     while (nextGroupOfPoints.Count == ElementTakeCount); 

     return points; 

RavenDB Paging

+1

Ta metoda jest zdecydowanie lepszym podejściem. – Matt

+4

Uwaga na ograniczenie liczby żądań serwera. Zgodnie z ustawieniami "Bezpiecznie domyślnie" Ravena, będzie to tylko do 30 podróży w obie strony do serwera, więc jeśli pętla będzie musiała wykonać więcej, to się nie powiedzie, ponieważ każda iteracja pętli jest kolejnym żądaniem serwera. –

34

Warto zauważyć, że od wersji 2.5, RavenDB ma „nieograniczone” wyniki API umożliwiający strumieniowe. W przykładzie z docs pokazuje, jak korzystać z tego:

var query = session.Query<User>("Users/ByActive").Where(x => x.Active); 
using (var enumerator = session.Advanced.Stream(query)) 
{ 
    while (enumerator.MoveNext()) 
    { 
     User activeUser = enumerator.Current.Document; 
    } 
} 

Jest wsparcie dla standardowych zapytań RavenDB, zapytań Lucence i nie jest też wsparcie asynchroniczny.

Dokumentację można znaleźć pod numerem here. Artykuł na blogu wprowadzającym Ayende można znaleźć pod adresem here.

+1

+1 za wskazówkę. Dzięki! –

+3

Pamiętaj, że podczas wysyłania zapytań za pomocą interfejsu API strumieniowania indeks musi już istnieć. Jeśli uruchomisz zapytanie za pomocą zwykłego interfejsu API sesji, a indeks dopasowania nie istnieje, zostanie utworzony indeks dynamiczny. Ale w strumieniowym API indeks dynamiczny nie jest tworzony, a serwer narzeka, że ​​indeks nie został znaleziony. –

+0

Mike - to interesujące zachowanie, brzmi jak błąd. Czy omawiałeś to w grupie RavenDB? –

0

Można również użyć predefiniowanego indeksu przy użyciu metody Stream. Możesz użyć klauzuli Where na indeksowanych polach.

var query = session.Query<User, MyUserIndex>(); 
var query = session.Query<User, MyUserIndex>().Where(x => !x.IsDeleted); 

using (var enumerator = session.Advanced.Stream<User>(query)) 
{ 
    while (enumerator.MoveNext()) 
    { 
     var user = enumerator.Current.Document; 
     // do something 
    } 
} 

Przykład indeksu:

public class MyUserIndex: AbstractIndexCreationTask<User> 
{ 
    public MyUserIndex() 
    { 
     this.Map = users => 
      from u in users 
      select new 
      { 
       u.IsDeleted, 
       u.Username, 
      }; 
    } 
} 

Dokumentacja: What are indexes? Session : Querying : How to stream query results?


Ważna uwaga: metoda Stream nie będzie śledzić obiektów. W przypadku zmiany obiektów uzyskanych z tej metody, SaveChanges() nie będzie świadomy żadnych zmian.


Inne uwagi: możesz uzyskać następujący wyjątek, jeśli nie określisz indeksu do użycia.

InvalidOperationException: StreamQuery nie obsługuje kwerend dynamicznych indeksowania. Został zaprojektowany do użycia z dużymi zestawami danych i prawdopodobnie nie zwróci całego zestawu danych po 15 sekundach indeksowania, tak jak robi to Query().