Search code examples
javaregexredisredisearch

Java ResiSearch FT.SEARCH results to json


I am new to RedisSearch. I have a Java client. What is the easiest way to parse this sample FT.SEARCH result into JSON or POJO or something more useful?

Sample result from FT.SEARCH (actually a string):

[
  3,
  movie_json: 1, [$, { "id": 1, "title": "Game of Thrones" } ],
  movie_json: 3, [$, { "id": 3, "title": "Looking for Sugarman" } ],
  movie_json: 2, [$, { "id": 2, "title": "Inception" } ]
]

Something like this would be useful:

{
  "count": 3,
  "docs": [
    { "id": 1, "title": "Game of Thrones" },
    { "id": 3, "title": "Looking for Sugarman" },
    { "id": 2, "title": "Inception" }
  ]
}

The most obvious is a RegEx matcher as below (I am no regex expert).

This is the code generated by the https://regex101.com/ site where I can get the right groups on their site as long as I use a global flag - but it seems that Java doesn't have a GLOBAL pattern / flag! Is that true?

The code the site generated is below and sure enough matcher.find() shows no match, presumably due to the absence of the global flag.

final String regex = "(?<=\\[\\$, ).*?(?= \\])";
final String string = respContent; // The rediSearch result string shown above

final Pattern pattern = Pattern.compile(regex);
final Matcher matcher = pattern.matcher(string);

while (matcher.find()) {
  System.out.println("Full match: " + matcher.group(0));

  for (int i = 1; i <= matcher.groupCount(); i++) {
    System.out.println("Group " + i + ": " + matcher.group(i));
  }
}

I could use the String.split() dance too.

However, is there an existing solution that is probably more robust for multiple FT.SEARCH results use-cases?

I imagined someone would have written a RedisSearch results parser by now but I cannot find one.

Thanks, Murray


Solution

  • The high level Redis API for Quarkus only exposes the plain Redis commands as a set of java APIs. To handle Redis extensions, you can always refer to the low-level API: https://quarkus.io/guides/redis-reference

    Once you choose the low-level API, you are, in fact, using the underlying driver that Quarkus uses. This is Vert.x Redis client.

    In this mode, you can use any Redis extension and work with JSON directly, for example:

    // set a JSON value
    lowLevelClient
      .send(cmd(Command.create("JSON.SET")).arg("foo").arg(".").arg("\"bar\""))
      .compose(response -> {
        // OK
        // get a JSON value
        return lowLevelClient.send(cmd(Command.create("JSON.GET")).arg("foo"));
      })
      .compose(response -> {
        // verify that it is correct
        should.assertEquals("\"bar\"", response.toString());
    
        // do another call...
        return lowLevelClient.send(cmd(Command.create("JSON.TYPE")).arg("foo").arg("."));
      })
      .compose(response -> {
        should.assertEquals("string", response.toString());
        return Future.succeededFuture();
      })
      .onFailure(should::fail)
      .onSuccess(v -> {
        test.complete();
      });
    

    While this mode is much more verbose, it gives you full control to the Redis extension you're using.

    If the response can be mapped to JSON or is JSON already, you can get the content from its holder directly without need to parse the response, for example:

    response.getKeys(); // returns the set of keys
    response.get("key1"); // returns the JSON value for key "key1"
    response.get(0); // returns the JSON value for array index 0
    ...