我正在尝试使用RedisConnection执行"scan"命令。我不明白为什么下面的代码抛出NoSuchElementException
RedisConnection redisConnection = redisTemplate.getConnectionFactory().getConnection();
Cursor c = redisConnection.scan(scanOptions);
while (c.hasNext()) {
c.next();
}
异常:java.util。NoSuchElementException,java.util.Collections EmptyIterator.next美元(Collections.java: 4189)org.springframework.data.redis.core.ScanCursor.moveNext (ScanCursor.java: 215)在org.springframework.data.redis.core.ScanCursor.next (ScanCursor.java: 202)
是的,我已经尝试过这个,在1.6.6。释放spring-data-redis.version。没有问题,下面简单的while循环代码就足够了。并且我已经将计数值设置为100(更大的值)以节省往返时间。
RedisConnection redisConnection = null;
try {
redisConnection = redisTemplate.getConnectionFactory().getConnection();
ScanOptions options = ScanOptions.scanOptions().match(workQKey).count(100).build();
Cursor c = redisConnection.scan(options);
while (c.hasNext()) {
logger.info(new String((byte[]) c.next()));
}
} finally {
redisConnection.close(); //Ensure closing this connection.
}
我使用spring-data-redis 1.6.0-RELEASE和Jedis 2.7.2;我确实认为ScanCursor的实现在这个版本上处理这种情况时有点缺陷——尽管我没有检查过以前的版本。
So:解释起来相当复杂,但在ScanOptions对象中有一个需要设置的"count"字段(默认为10)。该字段包含搜索的"意图"或"预期"结果。正如这里所解释的(恕我直言,不是很清楚),您可以在每次调用时更改count的值,特别是在没有返回结果的情况下。我理解这是"一个工作意图",所以如果你没有得到任何回报,也许你的"键空间"是巨大的,扫描命令没有"足够努力"。显然,只要你能得到结果,你就不需要增加这个值。
一个"简单但危险"的方法是有一个非常大的计数(例如100万或更多)。这将使REDIS离开,试图搜索你庞大的键空间,以找到"至少或接近"你的大计数。不要忘记- REDIS 是单线程的所以你只是牺牲了你的性能。用一个有12M个键的REDIS试试这个,你会看到,尽管SCAN可能会很高兴地返回具有非常高计数值的结果,但在搜索期间,它绝对不会做更多的。
解决你的问题:
ScanOptions options = ScanOptions.scanOptions().match(pattern).count(countValue).build();
boolean done = false;
// the while-loop below makes sure that we'll get a valid cursor -
// by looking harder if we don't get a result initially
while (!done) {
try(Cursor c = redisConnection.scan(scanOptions)) {
while (c.hasNext()) {
c.next();
}
done = true; //we've made it here, lets go away
} catch (NoSuchElementException nse) {
System.out.println("Going for "+countValue+" was not hard enough. Trying harder");
options = ScanOptions.scanOptions().match(pattern).count(countValue*2).build();
}
}
请注意,Spring Data REDIS的ScanCursor实现将正确地遵循SCAN指令并正确循环,尽可能多地根据需要,按照文档到达循环的末尾。我还没有找到一种方法来改变同一光标内的扫描选项-所以可能有这样的风险,如果您得到一半的结果,并得到一个NoSuchElementException,您将重新开始(基本上做一些工作两次)。
当然,更好的解决方案总是受欢迎的:)
我的旧代码
ScanOptions.scanOptions().match("*" + query + "*").count(10).build();
工作代码
ScanOptions.scanOptions().match("*" + query + "*").count(Integer.MAX_VALUE).build();