How to use SCAN commands in Jedis
Asked Answered
C

4

23

I was using redis and jedis for quite some time and never needed the SCAN commands so far. Now however I need to use the SCAN commands, particularly hscan. I understand how it works on the redis level, but the jedis Java wrapper side is confusing to me. There are ScanResults and ScanParameter classes flowing around and I have no clear concept of how to use them properly. The documentation for this feature is non-existent or at least hard to find. Can anyone point out where to find decent examples of how to iterate over a hash using hscan with jedis?

Sorry to have no code, but what I tried so far just makes no sense whatsoever.

Conney answered 21/11, 2015 at 10:2 Comment(2)
Try looking in Jedis' sources, specifically the tests - they usually give a clue: github.com/xetorthio/jedis/blob/master/src/test/java/redis/…Kristopher
thank you for that pointer. However, the tests do not seem to really iterate over a hash. I can see only one call to hscan for example. I am still missing the concept of the current cursor as String.Conney
C
35

In the good tradition of answering own questions, here is what I found out:

String key = "THEKEY";
ScanParams scanParams = new ScanParams().count(100);
String cur = redis.clients.jedis.ScanParams.SCAN_POINTER_START; 
boolean cycleIsFinished = false;
while(!cycleIsFinished) {
  ScanResult<Entry<String, String>> scanResult = 
        jedis.hscan(key, cur, scanParams);
  List<Entry<String, String>> result = scanResult.getResult();

  //do whatever with the key-value pairs in result

  cur = scanResult.getStringCursor();
  if (cur.equals("0")) {
    cycleIsFinished = true;
  }                 
}

The important part is that cur is a String variable and it is "0" if the scan is complete.

With the help of ScanParams I was able to define the approximate size of each chunk to get from the hash. Approximate, because the hash might change during the scan, so it may be that an element is returned twice in the loop.

Conney answered 23/11, 2015 at 18:52 Comment(0)
P
24

I don't like flag variables

Jedis jedis = new Jedis("localhost");

ScanParams scanParams = new ScanParams().count(10).match("*");
String cur = SCAN_POINTER_START;
do {
    ScanResult<String> scanResult = jedis.scan(cur, scanParams);

    // work with result
    scanResult.getResult().stream().forEach(System.out::println);
    cur = scanResult.getStringCursor();
} while (!cur.equals(SCAN_POINTER_START));
Paisano answered 30/10, 2017 at 11:9 Comment(0)
G
4

A suggestion to the example above. You can specify the key match within the scanParams class. See below.

ScanParams scanParams = new ScanParams();
    scanParams.match("*");

    String cursor = redis.clients.jedis.ScanParams.SCAN_POINTER_START;
    boolean cycleIsFinished = false;
    while (!cycleIsFinished) {

        ScanResult<String> scanResult = jedisRead.scan(cursor, scanParams);
        List<String> result = scanResult.getResult();

        /*
         * do what you need to do with the result
         */



        cursor = scanResult.getStringCursor();
        if (cursor.equals("0")) {
            cycleIsFinished = true;
        }
    }
Gastropod answered 10/12, 2016 at 11:30 Comment(0)
P
0

(late to the party, I know) I am the developer of a library called InterruptingJedisLocks, located on github.

My class ScanIterable/ScanIterator are iterators that use a SCAN operation under the hood; making it easier to operate in Java, hidding complexity. The ScanUtils class also is a good helper.

Feel free to use it with the library or only the Java classes

Pamphlet answered 24/11, 2021 at 9:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.