我需要一些RxJava的帮助。我有一个昂贵的网络调用,它返回一个Observable(来自elasticsearch的广告流)。我想缓存每个发出项目(广告)的ID属性10分钟(在Redis中),以便后续10分钟内的后续调用使用Cache中的ID从Elasticsearch获取广告。
我已经获得了一些代码 - 这在某种程度上可以实现预期的结果,(归功于以下博客...... http://blog.danlew.net/2015/06/22/loading-data-from-multiple-sources-with-rxjava/)
它可以缓存流中的每个发出项,我需要的是将流中这些项的所有ID缓存为1个缓存条目
到目前为止的代码https://github.com/tonymurphy/rxjava适用于任何感兴趣的人,
下面的代码段@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;
}
根据我的理解,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;
}
答案 0 :(得分:0)
我要做的是使用过滤器来确保不会发出缓存的旧内容,以便concat跳转到网络调用:
Stream imageStream = picture.GetImage();
using (var memoryStream = new MemoryStream())
{
imageStream.CopyTo(memoryStream);
byte[] buffer = memoryStream.ToArray();
// this is the Base64 string you are looking for
string base64String = Convert.ToBase64String(buffer);
}
答案 1 :(得分:0)
好的,我认为我有一个适合我的解决方案。我可能忽略了一些东西,但它应该很容易吗?
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;
}