Reputation: 16831
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?
Upvotes: 0
Views: 591
Reputation: 16831
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();
}
Upvotes: 1
Reputation: 86
@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.
Upvotes: -1
Reputation: 4434
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();
}
Upvotes: 1