是否可以通过键从 Ignite 缓存中获取多个值,并在一次操作中在服务器端应用额外的过滤?
Is it possible to get multiple values from an Ignite cache by their keys, applying additional filtering server-side, in one operation?
我有一个 Ignite 缓存:
IgniteCache<String, Record> cache;
给出了这个缓存的键集合。我需要执行以下操作:
- 获取具有指定键的记录
- ... 但另外通过一些动态定义的逻辑过滤它们(如 'where field
name
has value John
')
- ...尽快完成
- ...下一笔交易
我尝试的一种方法是使用 getAll()
方法并在我这边应用过滤:
cache.getAll(keys).values().stream()
.filter(... filter logic...)
.collect(toList());
这可行,但如果附加过滤器具有高选择性(即拒绝大量数据),我们将浪费大量时间通过网络发送不需要的数据。
另一个选项是使用扫描:
cache.query(new ScanQuery<>(new IsKeyIn(keys).and(new CustomFilter())))
这使得所有的过滤工作都在服务器节点端进行,但它是一个全扫描,如果缓存中有很多条目,而输入键只占其中的一小部分,很多时间又浪费了,这次浪费在不需要的扫描上。
还有 invokeAll()
允许在服务器节点端进行过滤:
cache.invokeAll(new TreeSet<>(keys), new AdditionalFilter())
.values().stream()
.map(EntryProcessorResult::get)
.collect(toList());
哪里
private static class AdditionalFilter implements CacheEntryProcessor<String, Record, Record> {
@Override
public Record process(MutableEntry<String, Record> entry,
Object... arguments) throws EntryProcessorException {
if (... record matches the filter ...) {
return entry.getValue();
}
return null;
}
}
它通过键找到条目,它在服务器节点端执行过滤逻辑,但在我的数据上它比扫描解决方案还要慢。我想(但不确定)这是由于 invokeAll()
可能是一个更新操作,所以(根据它的 Javadoc)它锁定了相应的键。
我希望能够通过给定的键找到条目,在服务器节点端应用额外的过滤,而不是为额外的锁付费(因为在我的情况下,这是一个只读操作)。
可能吗?
我的缓存分布在3个服务器节点,原子性TRANSACTIONAL_SNAPSHOT
。读取在事务下完成。
SQL 是最简单的解决方案,并且可能是最快的,给定适当的索引。
IgniteCompute#broadcast
+ IgniteCache#localPeek
:
Collection<Key> keys = ...;
Collection<Collection<Value>> results = compute.broadcast(new LocalGetter(), keys);
...
class LocalGetter implements IgniteClosure<Collection<Key>, Collection<Value>>
{
@Override public Collection<Value> apply(Collection<Key> keys) {
IgniteCache<Key, Value> cache = ...;
Collection<Value> res = new ArrayList<>(keys.size());
for (Key key : keys) {
Value val = cache.localPeek(key, CachePeekMode.PRIMARY);
if (val != null && filterMatches(val)) {
res.add(val);
}
}
return res;
}
}
通过这种方式,我们可以通过键高效地检索缓存条目,然后在本地应用过滤器,并且只通过网络发回匹配的条目。只有 N 次网络调用,其中 N 是服务器节点数。
我有一个 Ignite 缓存:
IgniteCache<String, Record> cache;
给出了这个缓存的键集合。我需要执行以下操作:
- 获取具有指定键的记录
- ... 但另外通过一些动态定义的逻辑过滤它们(如 'where field
name
has valueJohn
') - ...尽快完成
- ...下一笔交易
我尝试的一种方法是使用 getAll()
方法并在我这边应用过滤:
cache.getAll(keys).values().stream()
.filter(... filter logic...)
.collect(toList());
这可行,但如果附加过滤器具有高选择性(即拒绝大量数据),我们将浪费大量时间通过网络发送不需要的数据。
另一个选项是使用扫描:
cache.query(new ScanQuery<>(new IsKeyIn(keys).and(new CustomFilter())))
这使得所有的过滤工作都在服务器节点端进行,但它是一个全扫描,如果缓存中有很多条目,而输入键只占其中的一小部分,很多时间又浪费了,这次浪费在不需要的扫描上。
还有 invokeAll()
允许在服务器节点端进行过滤:
cache.invokeAll(new TreeSet<>(keys), new AdditionalFilter())
.values().stream()
.map(EntryProcessorResult::get)
.collect(toList());
哪里
private static class AdditionalFilter implements CacheEntryProcessor<String, Record, Record> {
@Override
public Record process(MutableEntry<String, Record> entry,
Object... arguments) throws EntryProcessorException {
if (... record matches the filter ...) {
return entry.getValue();
}
return null;
}
}
它通过键找到条目,它在服务器节点端执行过滤逻辑,但在我的数据上它比扫描解决方案还要慢。我想(但不确定)这是由于 invokeAll()
可能是一个更新操作,所以(根据它的 Javadoc)它锁定了相应的键。
我希望能够通过给定的键找到条目,在服务器节点端应用额外的过滤,而不是为额外的锁付费(因为在我的情况下,这是一个只读操作)。
可能吗?
我的缓存分布在3个服务器节点,原子性TRANSACTIONAL_SNAPSHOT
。读取在事务下完成。
SQL 是最简单的解决方案,并且可能是最快的,给定适当的索引。
IgniteCompute#broadcast
+IgniteCache#localPeek
:
Collection<Key> keys = ...;
Collection<Collection<Value>> results = compute.broadcast(new LocalGetter(), keys);
...
class LocalGetter implements IgniteClosure<Collection<Key>, Collection<Value>>
{
@Override public Collection<Value> apply(Collection<Key> keys) {
IgniteCache<Key, Value> cache = ...;
Collection<Value> res = new ArrayList<>(keys.size());
for (Key key : keys) {
Value val = cache.localPeek(key, CachePeekMode.PRIMARY);
if (val != null && filterMatches(val)) {
res.add(val);
}
}
return res;
}
}
通过这种方式,我们可以通过键高效地检索缓存条目,然后在本地应用过滤器,并且只通过网络发回匹配的条目。只有 N 次网络调用,其中 N 是服务器节点数。