Alex Medveshchek Alex Medveshchek - 5 months ago 42
Java Question

Elasticsearch custom plugin: Add extra query parameter before search

I'm new with Elasticsearch, so don't know how to start properly with the following task.

I have an index with documents that contain 2 types of fields:

  • address: the string including city and street;

  • houses: the list of houses' numbers (integers).

In usual case I could search this documents by followin query:


GET /_search
"should": [
{"match": {"address": "Gotham Fourteenth street"}},
{"match": {"houses": 33}}

My goal is to match such records by single string, like:


GET /_search
"should": [
{"match": {"address": "Gotham Fourteenth street 33"}}

or even:

curl -X GET 'http://localhost:9200/_search?q=Gotham+Fourteenth+street+33'

i.e. convert the query (2) to (1), that is cut the house number '33' from 'address' and put it as 'houses' match-parameter to the same query before search performed.

I think I could create a plugin in Java that would extract house number from 'address' (parsing is not a problem) and add an extra parameter 'houses' with this value.

Thus my problem is:

  1. how in my plugin I can programmatically add an extra match-parameter 'houses' to my query before search performed?

  2. how to cut the trailing house-number token from 'address' parameter?

Answer Source

In the end I've developed a plugin for ElasticSearch 2.4.2 and added a REST-action class (derived from BaseRestHandler) with the following handleRequest() method:

protected void handleRequest(RestRequest request, RestChannel channel, final Client client) throws Exception {
    // Get the address parameter
    String address = request.param("address");

    // ... Code that parses address and extracts house number ...
    int house = ...

    // Now send both parameters as query to search engine
    SearchResponse sr = client
        // Query all shards, DFS==calculate global words' frequencies
        // Address string without (cutted) house number   
        .setQuery(QueryBuilders.matchQuery("address", address))
        // And extracted house number as second filtering parameter
        .setPostFilter(QueryBuilders.termQuery("houses", house))
        // Starting position of the first returning hit
        // Max number of hits
        // Explain hit score 

        BytesRestResponse sr_rest = search2restResponse(sr);

The method search2restResponse() mentioned above converts SearchResponse to REST-response and looks as following:

private BytesRestResponse search2restResponse(SearchResponse sr) {
    SearchHit[] searchHits = sr.getHits().getHits();
    StringBuilder builder = new StringBuilder();
    for (int i = 0; i < searchHits.length; i++) {
        if (i > 0) {
    String res_json = builder.toString();
    return new BytesRestResponse(RestStatus.OK, res_json);