May be it's too late, but when I faced the same problem I reached the question without any answer. I hope my solution helps to other searchers.
Spring data elasticsearch has many limitations, however you can do anything using ElasticSearch's java client.
Here are maven dependencies:
<!--ELASTICSEARCH-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-elasticsearch</artifactId>
</dependency>
<dependency>
<groupId>org.elasticsearch.client</groupId>
<artifactId>transport</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
<dependency>
<groupId>org.elasticsearch.plugin</groupId>
<artifactId>transport-netty4-client</artifactId>
<version>${elasticsearch.version}</version>
</dependency>
Here is my solution:
@Service
public class UniversalSearchHelper {
@Autowired
protected Client client;
public List<SearchResult> matchQuery(String term) {
MultiSearchRequest request = new MultiSearchRequest();
request.add(searchRequest(QueryBuilders.boolQuery()
.should(QueryBuilders.matchQuery("name", term))
.should(QueryBuilders.matchQuery("full_name", term)), "movie_index"));
request.add(searchRequest(QueryBuilders.matchQuery("name", term), "taxonomy_index"));
ActionFuture<MultiSearchResponse> r = client.multiSearch(request);
return getTopTen(r.actionGet(2000));
}
public List<SearchResult> fuzzyQuery(String term) {
MultiSearchRequest request = new MultiSearchRequest();
request.add(searchRequest(QueryBuilders.boolQuery()
.should(QueryBuilders.fuzzyQuery("name", term))
.should(QueryBuilders.fuzzyQuery("full_name", term)), "movie_index"));
request.add(searchRequest((QueryBuilders.fuzzyQuery("name", term), "taxonomy_index"));
ActionFuture<MultiSearchResponse> r = client.multiSearch(request);
return getTopTen(r.actionGet(2000));
}
private SearchRequest searchRequest(QueryBuilder queryBuilder, String... indices) {
SearchSourceBuilder search = new SearchSourceBuilder();
search.query(queryBuilder);
SearchRequest request = new SearchRequest();
request.indices(indices);
request.source(search);
return request;
}
private List<SearchResult> getTopTen(MultiSearchResponse response) {
List<SearchResult> results = new ArrayList<>();
response.iterator().forEachRemaining(item -> {
if (!item.isFailure()) {
item.getResponse().getHits().iterator().forEachRemaining(hit -> results.add(new SearchResult(hit)));
}
});
results.sort((searchResult1, searchResult2) -> (int) (searchResult2.getScore() - searchResult1.getScore()));
return results.stream().filter(sr -> sr.getTaxonomy() != null).limit(10).collect(Collectors.toList());
}
}
and entity to get the results:
import org.elasticsearch.search.SearchHit;
public class SearchResult {
private Object id;
private float score;
private String term;
private String type;
private String taxonomy;
public Object getId() {
return id;
}
public SearchResult setId(Object id) {
this.id = id;
return this;
}
public float getScore() {
return score;
}
public SearchResult setScore(float score) {
this.score = score;
return this;
}
public String getTerm() {
return term;
}
public SearchResult setTerm(String term) {
this.term = term;
return this;
}
public String getType() {
return type;
}
public SearchResult setType(String type) {
this.type = type;
return this;
}
public String getTaxonomy() {
return taxonomy;
}
public void setTaxonomy(String taxonomy) {
this.taxonomy = taxonomy;
}
public SearchResult() {
}
public SearchResult(SearchHit hit) {
this.id = hit.getSource().get("id");
this.term = (String)hit.getSource().get("name");
this.score = hit.getScore();
this.type = hit.getType();
this.taxonomy = (String) hit.getSource().get("taxonomy");
}
}