Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Connecting Redis to ElasticSearch For Custom Scoring With Nativescripts

DZone's Guide to

Connecting Redis to ElasticSearch For Custom Scoring With Nativescripts

· Java Zone
Free Resource

Microservices! They are everywhere, or at least, the term is. When should you use a microservice architecture? What factors should be considered when making that decision? Do the benefits outweigh the costs? Why is everyone so excited about them, anyway?  Brought to you in partnership with IBM.

After connecting Redis and MongoDB to Solr, I figured it'd be interesting to do the same with ElasticSearch. Here's the result of my experiments:

We'll be implementing this using AbstractSearchScript, which is roughly ElasticSearch's version of Solr's FunctionQuery.

ES' NativeScriptFactory corresponds loosely to Solr's ValueSourceParser, and AbstractSearchScript to ValueSource.

public class RedisNativeScriptFactory implements NativeScriptFactory {
  @Override public ExecutableScript newScript(@Nullable Map<String, Object> params) {
    return new RedisScript(params);
  }
}
public class RedisScript extends AbstractFloatSearchScript {
  private String idField;
  private String redisKey;
  private String redisValue;
  private final Jedis jedis;
  private JSONObject obj;

  public RedisScript(Map<String, Object> params) {
    this.idField = (String) params.get("idField");
    this.redisKey = (String) params.get("redisKey");
    this.redisValue = (String) params.get("redisValue");
    jedis = new Jedis("localhost");
    String v = jedis.hget(redisKey, redisValue);
    if (v != null) {
      obj = (JSONObject) JSONValue.parse(v);
    } else {
      obj = new JSONObject();
    }
  }

  @Override public float runAsFloat() {
    String id = doc().field(idField).stringValue();
    Object v = obj.get(id);
    if (v != null) {
      try {
        return Float.parseFloat(v.toString());
      } catch (NumberFormatException e) {
        return 0;
      }
    }
    return 0;
  }
}

Now in config/elasticsearch.yml, add this:

script.native:
  redis.type: org.supermind.es.redis.RedisNativeScriptFactory

Change redis to whatever you want the script name to be, and change the class name accordingly too.

Now, to use this:

curl -XGET 'http://localhost:9200/electronics/product/_search' -d '{
  "query" :{
     "custom_score": {
       "query" : { "match_all": {}},
       "script" : "redis",
       "params" :{
          "idField": "id",
          "redisKey": "bar",
          "redisValue" : "500"
       },
       "lang": "native"
     }
  }
}'

PS: My implementation of RedisScript assumes a Redis hash has been populated with a json object corresponding to an idField. Here's a class populating the redis hash. JSON objects are created with the json-smart package, but you can plugin your favourite json lib:

public static void main(String[] args) {
    Jedis jedis = new Jedis("localhost");
    int num = 100000;
    Random r = new Random();
    for(int i=0;i< num;++i) {
      JSONObject o = new JSONObject();
      int numberOfEntries = r.nextInt(100);
      for(int j=0;j< numberOfEntries;++j) {
        o.put("es" + j, r.nextInt(100));
      }
      String json = o.toJSONString(JSONStyle.MAX_COMPRESS);
      jedis.hset("bar", Integer.toString(i), json);
    }
  }

Discover how the Watson team is further developing SDKs in Java, Node.js, Python, iOS, and Android to access these services and make programming easy. Brought to you in partnership with IBM.

Topics:

Published at DZone with permission of Kelvin Tan. See the original article here.

Opinions expressed by DZone contributors are their own.

THE DZONE NEWSLETTER

Dev Resources & Solutions Straight to Your Inbox

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.

X

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}