2016-07-04 5 views
0

システムのすべてのユーザーからWeb API検索機能を作成する必要があります。信頼できる辞書で検索

Qは、検索フィールドに入力した文字列のユーザーである
HTTP 1.1 GET http://sf.cluster:80/ 
Path /search/users?q=Aa&take=10 

:(電話を使用して) クライアントは、エンドポイントを使用して要求を私に送信します。 take - 電話機が表示したい項目数。

私は信頼できる辞書にAzure Storage Tableの89000項目をアップロードしました。

public async Task<IEnumerable<UserInfo>> Search(string q, int take) 
    { 
     var usersDictionary = await GetUsersDictionary(); 

     IEnumerable<UserInfo> results; 
     using (var tx = StateManager.CreateTransaction()) 
     { 
      var searchResults = (from r in (await usersDictionary.CreateEnumerableAsync(tx)).ToEnumerable() 
          where r.Value.StartsWith(q, StringComparison.InvariantCultureIgnoreCase) 
          select new UserInfo() 
          { 
           Id = r.Key, 
           Name = r.Value 
          }).Take(take); 

      results = new List<UserInfo>(searchResults); 

      await tx.CommitAsync(); 
     } 

     return results; 
    } 

問題:

IReliableDictionary<Guid, string> 

私の検索方法は、次のようになります。これは、構造を有し、それは携帯電話上での素敵な作品を、私は私が期待したものです。しかし、私のエンドポイントに多数の要求(約60スレッドが同時にSoap UIツールを使用して)を開始すると、タイムアウトが1秒から35秒に上がりました!どこかで間違いを犯したり、間違った検索方法を選択したようです。

誰かがこのような機能を実装していたのですか?誰でも正しい検索方法を手助けできますか?

UPD:私はList<string>を名前で保存し、同じものをそれらの(リストを通して検索する)ステートレスサービスを実装しました。結果:150-300ms。

答えて

3

あなたのToEnumerableメソッドの実装方法はわかりませんが、私が見たほとんどのものはかなりです非同期の列挙型を取り出し、それをリストにコピーするだけの怠惰な実装です。今、890,000エレムの信頼できる辞書で、それは非常に非効率的です。また、トランザクションはミューテックスのように動作するので、この巨大なリストをコピーしている間は、基になるコレクションをロックしています。 AsyncEnumerable linqの実装をthis libraryにチェックすることをお勧めします。これは、サービスファブリックAsyncEnumerableでlinqを使用する効率的な方法を実装するためです。あなたは、トランザクションをコミットする必要はありませんどのような方法で基になるコレクションを変更していないことから、サイドノートとして、また

using (var tx = StateManager.CreateTransaction()) 
    { 
     var enumerable = await usersDictionary.CreateEnumerableAsync(tx); 
     results = await enumerable.Where(kvp=>kvp.Value.StartsWith(q, StringComparison.InvariantCultureIgnoreCase)) 
      .Select(kvp=> new UserInfo() 
        { 
         Id = r.Key, 
         Name = r.Value 
        }) 
      .Take(take) 
      .ToListAsync(tx); 
    } 

:あなたの検索は次のようになります、という使い方。トランザクションをコミットすることは、あなたが状態を変更したことを状態マネージャに伝える方法であり、変更を完了した後、変更された値をセカンダリに伝播します。このメソッドをセカンダリで呼び出すこともできますが、これは読み込み量の重い状態ですが、書き込みはまだ伝播していない可能性があることに注意してください。

1

ReliableDictionaryは一部の値をページアウトするため、ReliableDictinonaryはIAsyncEnumerableを返します。これは、ディスクIOが一部の値を読み取る必要があることを意味します。 IAsyncEnumerableを使用すると、スレッドをできるだけブロックすることができます。

読み取りレイテンシが問題になる場合は、通知を使用して完全なメモリ内セカンダリインデックスを構築できます。プレフィックス一致検索の効率を上げるために、セカンダリインデックスを値で順序付けることもできます。以下は、関連するドキュメントです。

pdylanrossのマイナーな修正:CreateEnumerableAsyncは、コレクションをロックしないmvccモデルを使用してスナップショット分離を行います。したがって、スナップショット読み取りトランザクションが実行されている間、他のトランザクションは読み取りおよび書き込み操作を継続できます。隔離レベルの詳細については、https://docs.microsoft.com/en-us/azure/service-fabric/service-fabric-reliable-services-reliable-collections

希望します。

関連する問題