使用Rx

时间:2015-11-03 17:17:46

标签: reactive-programming rx-java observable

我为Rx专家提出了一个有趣的问题。我有一个关系表来保存有关事件的信息。事件由id,类型和时间组成。在我的代码中,我需要在某个可能很宽的时间范围内获取所有事件。

SELECT * FROM events WHERE event.time > :before AND event.time < :after ORDER        BY time LIMIT :batch_size

为了提高可靠性并处理大型结果集,我分批查询大小的记录:batch_size。现在,我想写一个函数,给定:before和:after,将返回一个代表结果集的Observable。

Observable<Event> getEvents(long before, long after);

在内部,该函数应该批量查询数据库。沿着时间尺度的事件分布是未知的。因此,解决批处理的自然方法是:     获取前N条记录     如果结果不为空,请将最后一条记录的时间用作新的&#39;之前的&#39;参数,并获取下N个记录;否则终止     如果结果不为空,请将最后一条记录的时间用作新的&#39;之前的&#39;参数,并获取下N个记录;否则终止     ......等等(这个想法应该清楚)

我的问题是:

有没有办法用更高级别的Observable基元(filter / map / flatMap / scan / range等)来表达这个函数,而不明确地使用订阅者?

到目前为止,我没有做到这一点,而是提出以下简单的代码:

private void observeGetRecords(long before, long after, Subscriber<? super Event> subscriber) {
    long start = before;
    while (start < after) {
        final List<Event> records;
        try {
            records = getRecordsByRange(start, after);
        } catch (Exception e) {
            subscriber.onError(e);
            return;
        }
        if (records.isEmpty()) break;
        records.forEach(subscriber::onNext);
        start = Iterables.getLast(records).getTime();
    }

    subscriber.onCompleted();
}

public Observable<Event> getRecords(final long before, final long after) {
        return Observable.create(subscriber -> observeGetRecords(before, after, subscriber));
}

这里,getRecordsByRange使用DBI实现SELECT查询并返回List。这段代码工作正常,但缺乏高级Rx结构的优雅。

注意:我知道我可以在DBI中通过SELECT查询返回Iterator。但是,我不想这样做,而是更喜欢运行多个查询。此计算不必是原子的,因此事务隔离问题无关紧要。

1 个答案:

答案 0 :(得分:0)

虽然我不完全理解为什么你想要这样的时间重用,但我是这样做的:

BehaviorSubject<Long> start = BehaviorSubject.create(0L);

start
.subscribeOn(Schedulers.trampoline())
.flatMap(tstart -> 
    getEvents(tstart, tstart + twindow)
    .publish(o -> 
         o.takeLast(1)
         .doOnNext(r -> start.onNext(r.time))
         .ignoreElements()
         .mergeWith(o)
    )
)
.subscribe(...)