ElasticSearch Plugin Development – A Tutorial

In this tutorial, we will create a plugin to take two parameters field name and a numeric factor and multiply them together. Then, we will use the output of this plugin as a custom scorer.

Codebase

Each ElasticSearch Plugin should contain (at least) two classes: A factory class and a class to implement the functionality

└── src
    └── myplugin
        ├── MyPluginFactory.java
        └── MyPlugin.java

Sample code for the factory class:

package myplugin;

import java.util.Map;

import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.NativeScriptFactory;

public class MyPluginFactory implements NativeScriptFactory{

  @Override
  public ExecutableScript newScript(Map<String, Object> params) {
    return new MyPlugin(params);
  }
}

Sample code for the implementation class:

package myplugin;

import java.util.Map;

import org.elasticsearch.script.AbstractDoubleSearchScript;
import org.elasticsearch.index.fielddata.ScriptDocValues;

public class MyPlugin extends AbstractDoubleSearchScript{

  Double factor;
  String fieldName;

  public MyPlugin(Map<String, Object> params){
    factor     = Double.parseDouble( (String) params.get("factor"));
    fieldName  =(String) params.get("field");
  }

  @Override
  public double runAsDouble() {
    Double fieldVal = this.docFieldDoubles(fieldName).getValue();
    return factor * fieldVal;
  }
}

Install plugin to ElasticSearch

#compile and package
javac -cp /usr/share/elasticsearch/lib/elasticsearch-1.0.1.jar -d bin/ src/myplugin/*.java;
cd bin; jar cf ../my-example-plugin.jar myplugin/*.class; cd ..;
tree
├── my-example-plugin.jar
├── bin
│   └── myplugin
│       ├── MyPlugin.class
│       └── MyPluginFactory.class
└── src
    └── myplugin
        ├── MyPluginFactory.java
        └── MyPlugin.java

#create plugin folder and move the jar to it
#RUN AS ROOT
mkdir /usr/share/elasticsearch/plugins/myplugin;
cp my-example-plugin.jar /usr/share/elasticsearch/plugins/myplugin;

#register the plugin to make it visible to elasticsearch
echo " 
script.native.myplugin.type: myplugin.MyPluginFactory" >> /etc/elasticsearch/elasticsearch.yml

#restart ElasticSearch to re-load the plugin
service elasticsearch restart

Sample Request

curl -XPOST 'http://localhost:9200/items/_search?fields=_score,popularity' -H 'Content-Type: application/x-www-form-urlencoded' --data '{
  "query": {
    "function_score": {
      "script_score": {
        "script": "myplugin",
        "lang": "native",
        "params": {
          "field": "popularity",
          "factor": "3.0" 
        }
      }
    }
  }
}'

Expected output:
Notice that score is 3* popularity

{
  "took": 6,
  "timed_out": false,
  "_shards": {
    "total": 5,
    "successful": 5,
    "failed": 0
  },
  "hits": {
    "total": 1,
    "max_score": 2.97159,
    "hits": [
      {
        "_index": "items",
        "_type": "269183",
        "_id": "_update",
        "_score": 1.5,
        "fields": {
          "popularity": [
            0.5
          ]
        }
      }
    ]
  }
}

Useful Links

Leave a Reply

Your email address will not be published. Required fields are marked *