0
votes

I've developed a REST API entry with Spring which conducts a search in Elasticsearch and now I want to return whatever results ES has found as the response. I don't care about the search results and I don't know the JSON structure in it. I just want to return it back to the client.

I was hoping something like this would work:

@RequestMapping(value = "/search/{index:.*}", method = RequestMethod.GET)
public void search(@PathVariable String index, @RequestParam Map allRequestParams, HttpServletResponse response)
    throws IOException
{
    BoolQueryBuilder query = QueryBuilders.boolQuery();
    for (Map.Entry entry : allRequestParams.entrySet()) {
        query.should(QueryBuilders.fuzzyQuery(entry.getKey(), entry.getValue()));
    }

    SearchResponse results = esClient.prepareSearch("nyc_visionzero")
        .setTypes("logs")
        .setQuery(query)
        .execute()
        .actionGet();

    SearchHits hits = results.getHits();
    hits.writeTo(response.getOutputStream());
}

But the last line has a compile error since the two OutputStreams are not compatible. So my question is, what is the easiest way of wiring the results of Elasticsearch into Spring's response?

3

3 Answers

1
votes

Instead of trying to write to the response outputstream, you can change the signature of your search method to return a String then directly return the result as valid JSON. Something like:

@RequestMapping(value = "/search/{index:.*}", method = RequestMethod.GET)
public String search(@PathVariable String index, @RequestParam Map allRequestParams, HttpServletResponse response)
    throws IOException
{
    BoolQueryBuilder query = QueryBuilders.boolQuery();
    for (Map.Entry entry : allRequestParams.entrySet()) {
        query.should(QueryBuilders.fuzzyQuery(entry.getKey(), entry.getValue()));
    }

    SearchResponse results = esClient.prepareSearch("nyc_visionzero")
        .setTypes("logs")
        .setQuery(query)
        .execute()
        .actionGet();

    SearchHits hits = results.getHits();

    // Replacing hits.writeTo(response.getOutputStream()); below
    StringBuilder builder = new StringBuilder();
    SearchHit[] hitsDatas = hits.hits();
    int length = hitsDatas.length;
    builder.append("[");
    for (int i = 0; i < length; i++) {
       if (i == length - 1) {
          builder.append(hitsDatas[i].getSourceAsString());
       } else {
          builder.append(hitsDatas[i].getSourceAsString());
          builder.append(",");
       }
    }
    builder.append("]");
    return builder.toString();
}
1
votes

I managed to find a solution myself:

@RequestMapping(value = "/search/{index:.*}", method = RequestMethod.GET)
public void search(@PathVariable String index, @RequestParam Map<String, String> allRequestParams, HttpServletResponse response)
    throws IOException
{
    BoolQueryBuilder query = QueryBuilders.boolQuery();
    for (Map.Entry<String, String> entry : allRequestParams.entrySet()) {
        query.should(QueryBuilders.fuzzyQuery(entry.getKey(), entry.getValue()));
    }

    SearchResponse results = esClient.prepareSearch("nyc_visionzero")
        .setTypes("logs")
        .setQuery(query)
        .execute()
        .actionGet();

    SearchHits hits = results.getHits();

    ServletOutputStream os = response.getOutputStream();
    XContentBuilder builder = XContentFactory.jsonBuilder(os);
    results.toXContent(builder, ToXContent.EMPTY_PARAMS);
    builder.close();
    os.close();
}
-1
votes
@RequestMapping(value = "/search/{index:.*}", method = RequestMethod.GET)
public ResponseEntity<?> search(@PathVariable String index, @RequestParam Map allRequestParams)
{
BoolQueryBuilder query = QueryBuilders.boolQuery();
for (Map.Entry entry : allRequestParams.entrySet()) {
    query.should(QueryBuilders.fuzzyQuery(entry.getKey(), entry.getValue()));
}

SearchResponse results = esClient.prepareSearch("nyc_visionzero")
    .setTypes("logs")
    .setQuery(query)
    .execute()
    .actionGet();

SearchHits hits = results.getHits();
return new ResponseEntity<>(hits , HttpStatus.OK);
}

with ResponseEntity class you can return any response without caring about your result type.