Alex Medveshchek Alex Medveshchek - 1 year ago 87
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:

(1)

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


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

(2)

GET /_search
{
"query":{
"bool":{
"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:

@Override
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
        .prepareSearch("myindex")
        .setTypes("mytype")
        // Query all shards, DFS==calculate global words' frequencies
        .setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
        // 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
        .setFrom(0)
        // Max number of hits
        .setSize(10)
        // Explain hit score 
        .setExplain(true)
        .get();

        BytesRestResponse sr_rest = search2restResponse(sr);
        channel.sendResponse(sr_rest);
    }
}

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();
    builder.append("[");
    for (int i = 0; i < searchHits.length; i++) {
        if (i > 0) {
            builder.append(",");
        }
        builder.append(searchHits[i].getSourceAsString());
    }
    builder.append("]");
    String res_json = builder.toString();
    return new BytesRestResponse(RestStatus.OK, res_json);
}
Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download