17

UsersRavenDB からデータ コレクション全体をフェッチし、取得した結果セットを別のデータ セットと比較する必要があるという要件があります。この特定のコレクションには 4000 近くのレコードがあります。

Raven はデフォルトで安全であるため、例外が発生し続けるかNumber of requests per session exceeded、最大 128 レコードが返されます。

Session.Advanced.MaxNumberOfRequestsPerSessionプロパティをより高い値に設定したくありません。

すべてのレコードの数を取得するには、どのクエリを使用すればよいですか? この状況に対処するための理想的なアプローチは何ですか?

4

6 に答える 6

21

ページングを使用して、この 1024 項目を一度に読み取ります。

int start = 0;
while(true)
{
   var current = session.Query<User>().Take(1024).Skip(start).ToList();
   if(current.Count == 0)
          break;

   start+= current.Count;
   allUsers.AddRange(current);

}
于 2012-06-30T08:21:30.170 に答える
13

この質問は、この機能が RavenDB で利用可能になる前に投稿されましたが、他の誰かがこれに出くわした場合に備えて...

これを行うには、ストリーミング APIを使用することをお勧めします。RavenDB クライアントはストリームをバッチ処理して、サーバーとの間の要求/応答を自動的に「ページング」できるようにします。ストリーミング API の使用を選択した場合、クライアントは、ユーザーが「何をしているかを理解している」と想定し、通常のクエリに使用される 128/1024/30 の制限をチェックしません。

var query = session.Query<User>();
 
using (var enumerator = session.Advanced.Stream(query)) {
    while (enumerator.MoveNext()) {
        allUsers.Add(enumerator.Current.Document);
    }
}

var count = allUsers.Count;

ヒント: これは問題を解決するための推奨される方法ですが... 一般的なルールとして、最初はこの状況を避けるのが最善です。100 万件のレコードがある場合はどうなるでしょうか。そのallUsersリストは膨大になるでしょう。ユーザー/プロセスに実際に表示する必要があるデータを除外するために、最初にインデックスまたは変換を実行できますか? これはレポート目的ですか?おそらく RavenDB は、レポート サービスを備えた SQL サーバーに自動的にエクスポートする必要がありますか? 等...

于 2014-10-12T22:55:54.227 に答える
1

@capaj の投稿を少しひねりました。すべてのドキュメント ID を文字列のリストとして取得する一般的な方法を次に示します。を使用してAdvanced.LuceneQuery<T>(idPropertyName)、物事を一般的にすることに注意してください。デフォルトでは、指定されたプロパティが有効であると想定されます(99.999% の確率でそうなるはずです)。他のプロパティがある場合は、それを渡すこともできます。SelectFields<T>(idPropertyName)GetProperty(idPropertyName)"Id"<T>Id

public static List<string> getAllIds<T>(DocumentStore docDB, string idPropertyName = "Id") {
   return getAllIdsFrom<T>(0, new List<string>(), docDB, idPropertyName);
}

public static List<string> getAllIdsFrom<T>(int startFrom, List<string> list, DocumentStore docDB, string idPropertyName ) {
    var allUsers = list;

    using (var session = docDB.OpenSession())
    {
        int queryCount = 0;
        int start = startFrom;
        while (true)
        {
            var current = session.Advanced.LuceneQuery<T>().Take(1024).Skip(start).SelectFields<T>(idPropertyName).ToList();
            queryCount += 1;
            if (current.Count == 0)
                break;

            start += current.Count;
            allUsers.AddRange(current.Select(t => (t.GetType().GetProperty(idPropertyName).GetValue(t, null)).ToString()));

            if (queryCount >= 28)
            {
                return getAllIdsFrom<T>(start, allUsers, docDB, idPropertyName);
            }
        }
    }
    return allUsers;
}

これを使用する場所/方法の例はPatchRequest、セッションを使用して RavenDb で を作成する場合BulkInsertです。場合によっては、何十万ものドキュメントがあり、パッチ操作のためにそれらを再度反復するためだけにすべてのドキュメントをメモリにロードする余裕がない可能性があります...したがって、それらの文字列 ID のみをロードしてPatch指図。

void PatchRavenDocs()
{
    var store = new DocumentStore
    {
        Url = "http://localhost:8080",
        DefaultDatabase = "SoMeDaTaBaSeNaMe"
    };

    store.Initialize();

    // >>>here is where I get all the doc IDs for a given type<<<
    var allIds = getAllIds<SoMeDoCuMeNtTyPe>(store);    

    // create a new patch to ADD a new int property to my documents
    var patches = new[]{ new PatchRequest { Type = PatchCommandType.Set, Name = "SoMeNeWPrOpeRtY" ,Value = 0 }};

    using (var s = store.BulkInsert()){
        int cntr = 0;
        Console.WriteLine("ID Count " + allIds.Count);
        foreach(string id in allIds)
        {
            // apply the patch to my document
            s.DatabaseCommands.Patch(id, patches);

            // spit out a record every 2048 rows as a basic sanity check
            if ((cntr++ % 2048) == 0)
                Console.WriteLine(cntr + " " + id);
        }
    }
}

それが役に立てば幸い。:)

于 2014-08-22T22:11:24.240 に答える