在Rx.NET中,如何从(异步/可观察)查找中丰富值

时间:2014-02-03 12:27:17

标签: system.reactive

假设我有一系列出价 - 我想用投标人名称来丰富它:

[
  { bidder: 'user/7', bet: 20  },
  { bidder: 'user/8', bet: 21 }, 
  { bidder: 'user/7', bet: 25  }, 
  /*...., 2 seconds later */
  { bidder: 'user/8', bet: 25  },
  { bidder: 'user/9', bet: 30  },
  ...

投标人姓名来自网络服务:

GET '/users?id=7&id=8' =>
[{ user: 'user/7', name: 'Hugo Boss'}, { user: 'user/8', name: "Karl Lagerfeld"}

我将其包装成反应式直读缓存:

IObservable<User> Users(IObservable<string> userIds);

撰写

现在我想将其组成以下输出:

[
  { bidder: 'user/7', bet: 20, name: 'Hugo Boss'  },
  { bidder: 'user/8', bet: 21, name: 'Karl Lagerfeld' }, 
  { bidder: 'user/7', bet: 25, name: 'Hugo Boss'  }, 
  /*...., 2 seconds later */
  { bidder: 'user/8', bet: 25, name: 'Karl Lagerfeld'  },
  { bidder: 'user/9', bet: 30, name: 'Somebody else'  },
  ...

第1步

我想我需要将出价流投影到用户ID流。简单Select。然后在read-throug-cache内部,我将它以Buffer(TimeSpan, int)分块。

现在我有一个出价流和一个用户。

第2步

但现在,如何将两者结合起来?

提示:对于BID来说,保持订单是有意义的 - 但在我的真实代码中,我并不关心订单。所以我想要一个不依赖于用户缓存按正确顺序返回用户的解决方案。然后Zip可以完成这项工作。

我希望在获得用户信息后立即将所有出价发布到我的结果流中。

解?

我很确定我需要以某种方式维护一些临时状态(window / buffer / ...)。但我不知道在哪里以及如何。 也许这应该作为自定义运算符实现;或者也许那里有一个?

有什么想法吗?

编辑:似乎无法在流上实际构建此内容。相反,我需要为userid-&gt;用户函数获取一个承诺(任务或IObservable),并在合适的情况下承诺批量加载和/或缓存用户。

2 个答案:

答案 0 :(得分:1)

以下内容应该有效。将缓存表示为ISubject,并且您具有异步缓存。在缓存内部,您可以在一个时间窗口上缓冲查询并批量请求它们到服务器。

一些虚拟课程

public struct User
{
    public string id;
}

public struct Bid
{
    public string userId;
    public int bid;
}

缓存对象本身

/// <summary>
/// Represent the cache by a subject that get's notified of
/// user requests and produces users. Internally this can
/// be buffered and chunked to the server. 
/// </summary>
public static ISubject<string, User> UsersCacheSubject;

向数据库分派和异步查询的方法

public static Task<User> UsersCache(string id)
{
    var r = UsersCacheSubject
        .Where(user=>user.id==id)
        .Replay(1)
        .Take(1);


    UsersCacheSubject.OnNext(id);

    return r.FirstAsync().ToTask();
}

尝试一下

 public void TryItOut()
{
    IObservable<Bid> bidderObservable = Observable.Repeat(new Bid());
     var foo = from bidder in bidderObservable
              from user in UsersCache(bidder.userId)
              where bidder.userId == user.id
              select new {bidder, user};
 }

答案 1 :(得分:0)

这不就像执行以下操作一样简单吗?

var query =
    from b in bids
    from u in Users(Observable.Return(b.Bidder))
    select new
    {
        b.Bidder,
        b.Bet,
        u.Name
    };