Caching 来自流的网络调用ID的RxJava缓存结果(Redis或类似缓存解决方案)

Caching 来自流的网络调用ID的RxJava缓存结果(Redis或类似缓存解决方案),caching,rx-java,observable,Caching,Rx Java,Observable,我需要一些关于RxJava的帮助。我有一个昂贵的网络呼叫,它返回一个可观察的(elasticsearch的广告流)。我希望将每个发出的项目(广告)的ID属性缓存10分钟(在Redis中),以便接下来10分钟内的后续调用使用缓存中的ID从Elasticsearch获取广告 我有一些代码-这在某种程度上有助于实现预期的结果(归功于下面的博客.)。。 ) 它可以缓存流中每个发出的项,我需要的是将流中这些项的所有ID缓存为一个缓存条目 到目前为止,所有感兴趣的人都可以看到下面的代码片段 @Compone

我需要一些关于RxJava的帮助。我有一个昂贵的网络呼叫,它返回一个可观察的(elasticsearch的广告流)。我希望将每个发出的项目(广告)的ID属性缓存10分钟(在Redis中),以便接下来10分钟内的后续调用使用缓存中的ID从Elasticsearch获取广告

我有一些代码-这在某种程度上有助于实现预期的结果(归功于下面的博客.)。。 )

它可以缓存流中每个发出的项,我需要的是将流中这些项的所有ID缓存为一个缓存条目

到目前为止,所有感兴趣的人都可以看到下面的代码片段

@Component
public class CachingObservable {

    private final Logger logger = LoggerFactory.getLogger(CachingObservable.class);

    @Autowired
    private AdvertService advertService;

    // Each "network" response is different
    private Long requestNumber = 0L;

    public Observable<Advert> getAdverts(final String location) {

        Observable<Advert> memory = memory(location);
        Observable<Advert> network = network(location);

        Observable<Advert> networkWithSave = network.doOnNext(new Action1<Advert>() {
            @Override
            public void call(Advert advert) {
                List<Long> ids = new ArrayList<Long>();
                ids.add(advert.getId());
                advertService.cache(location, ids);
            }
        });

        // Retrieve the first source with data - concat checks in order
        Observable<Advert> source = Observable.concat(memory,
                networkWithSave)
                .first();

        return source;
    }
@组件
公共类CachingObservable{
私有最终记录器Logger=LoggerFactory.getLogger(CachingObservable.class);
@自动连线
私人广告服务;
//每个“网络”响应都是不同的
专用长请求编号=0L;
公共可观察的getAdverts(最终字符串位置){
可观察记忆=记忆(位置);
可观测网络=网络(位置);
Observable networkWithSave=network.doOnNext(新操作1(){
@凌驾
公共无效呼叫(广告){
列表ID=新的ArrayList();
add(advert.getId());
advertService.cache(位置、ID);
}
});
//使用数据检索第一个源-按顺序进行concat检查
可观测源=可观测的concat(内存,
网络(带存储)
.first();
返回源;
}
从我的理解来看,concat方法对我的用例并没有真正的用处。我需要知道网络可观察性是否/何时完成,我需要获取返回的广告id列表,并将它们存储在缓存中。我可以订阅网络可观察性-但我希望它是惰性的-只有在缓存中找不到数据时才调用。所以以下更新的代码不起作用..有什么想法吗

public Observable<Advert> getAdverts(final String location) {

    Observable<Advert> memory = memory(location);
    Observable<Advert> network = network(location);

    Observable<Advert> networkWithSave = network.doOnNext(new Action1<Advert>() {
        @Override
        public void call(Advert advert) {
            List<Long> ids = new ArrayList<Long>();
            ids.add(advert.getId());
            advertService.cache(location, ids);
        }
    });

    // Retrieve the first source with data - concat checks in order
    Observable<Advert> source = Observable.concat(memory,
            networkWithSave)
            .first();

    Observable<List<Advert>> listObservable = networkWithSave.toList();
    final Func1<List<Advert>, List<Long>> transformer = new Func1<List<Advert>, List<Long>>() {
        @Override
        public List<Long> call(List<Advert> adverts) {
            List<Long> ids = new ArrayList<Long>();
            for (Advert advert : adverts) {
                ids.add(advert.getId());
            }
            return ids;
        }
    };

    listObservable.map(transformer).subscribe(new Action1<List<Long>>() {
        @Override
        public void call(List<Long> ids) {
            logger.info("ids {}", ids);
        }
    });

    return source;
}
公共可观察的getAdverts(最终字符串位置){
可观察记忆=记忆(位置);
可观测网络=网络(位置);
Observable networkWithSave=network.doOnNext(新操作1(){
@凌驾
公共无效呼叫(广告){
列表ID=新的ArrayList();
add(advert.getId());
advertService.cache(位置、ID);
}
});
//使用数据检索第一个源-按顺序进行concat检查
可观测源=可观测的concat(内存,
网络(带存储)
.first();
Observable listObservable=networkWithSave.toList();
最终Func1转换器=新Func1(){
@凌驾
公共列表电话(列表广告){
列表ID=新的ArrayList();
用于(广告:广告){
add(advert.getId());
}
返回ID;
}
};
listObservable.map(transformer.subscribe)(新操作1(){
@凌驾
公共作废调用(列表ID){
logger.info(“ids{}”,ids);
}
});
返回源;
}

我要做的是使用filter来确保缓存的旧内容不会被释放,以便concat跳转到网络调用:

Subject<Pair<Long, List<Advert>>, Pair<Long, List<Advert>>> cache = 
    BehaviorSubject.create().toSerialized();
static final long RETENTION_TIME = 10L * 60 * 1000;

Observable<Advert> memory = cache.filter(v -> 
    v.first + RETENTION_TIME > System.currentTimeMillis()).flatMapIterable(v -> v);

Observable<Advert> network = ...

Observable<Advert> networkWithSave = network.toList().doOnNext(v -> 
    cache.onNext(Pair.of(System.currentTimeMillis(), v)).flatMapIterable(v -> v)
);

return memory.switchIfEmpty(network);
主题缓存=
BehaviorSubject.create().toSerialized();
静态最终长保留时间=10L*60*1000;
可观察内存=缓存.过滤器(v->
v、 first+RETENTION\u TIME>System.currentTimeMillis()).flatMapIterable(v->v);
可观测网络=。。。
Observable networkWithSave=network.toList().doOnNext(v->
cache.onNext(一对(System.currentTimeMillis(),v)).flatMapIterable(v->v)
);
返回内存。开关为空(网络);

好的,我想我有一个适合我的解决方案。我可能忽略了一些东西,但应该很简单吧

public Observable<Advert> getAdverts(final String location) {

    Observable<Advert> memory = memory(location);
    final Observable<Advert> network = network(location);

    final Func1<List<Advert>, List<Long>> advertToIdTransformer = convertAdvertsToIds();

    memory.isEmpty().subscribe(new Action1<Boolean>() {
        @Override
        public void call(Boolean aBoolean) {
            if (aBoolean.equals(Boolean.TRUE)) {
                Observable<List<Long>> listObservable = network.toList().map(advertToIdTransformer);
                listObservable.subscribe(new Action1<List<Long>>() {
                    @Override
                    public void call(List<Long> ids) {
                        logger.info("Caching ids {}", ids);
                        advertService.cache(location, ids);
                    }
                });
            }
        }
    });

    // Retrieve the first source with data - concat checks in order
    Observable<Advert> source = Observable.concat(memory,
            network)
            .first();


    return source;
}
公共可观察的getAdverts(最终字符串位置){
可观察记忆=记忆(位置);
最终可观测网络=网络(位置);
final Func1 advertoidTransformer=convertAdvertoids();
memory.isEmpty().subscribe(新操作1()){
@凌驾
公共无效调用(布尔aBoolean){
if(aBoolean.equals(Boolean.TRUE)){
Observable listObservable=network.toList().map(AdvertoidTransformer);
listObservable.subscribe(新操作1(){
@凌驾
公共作废调用(列表ID){
info(“缓存id{}”,ids);
advertService.cache(位置、ID);
}
});
}
}
});
//使用数据检索第一个源-按顺序进行concat检查
可观测源=可观测的concat(内存,
(网络)
.first();
返回源;
}