我正在使用Spring Data Elasticsearch,并且对使用Elasticsearch 6.2的Multi Search API感兴趣,以便在单个API请求中执行多个搜索。
https://www.elastic.co/guide/en/elasticsearch/reference/6.2/search-multi-search.html
目前使用Spring Data Elasticsearch的{{1}}来构建搜索查询,使用NativeSearchQueryBuilder
来执行搜索请求。在查看Spring Data代码和浏览文档之后,我还没有设法找到任何公开或提交Multi Search请求的方法。
Spring Data Elasticsearch是否支持Multi Search API,通过他们的ElasticsearchTemplate
或我可能不知道的其他客户端/机制?
Elasticsearch在他们的Java API中提供了这个功能,所以我所追求的是类似于以下内容的东西,但不幸的是我必然会使用Spring Data Elasticsearch。
https://www.elastic.co/guide/en/elasticsearch/client/java-api/6.2/java-search-msearch.html
答案 0 :(得分:2)
否,Spring Data Elasticsearch暂时不支持多重搜索。我也遇到了同样的问题,因此我working a PR添加了此功能。现在,我提出以下解决方法:
@Override
public YYY findBy(XXX xxx) {
Client client = template.getClient();
MultiSearchRequest request = new MultiSearchRequest();
// build searchQuery like normal
for (NativeSearchQuery searchQuery : queries) {
request.add(prepareSearch(client, searchQuery));
}
ActionFuture<MultiSearchResponse> future = client
.multiSearch(request);
MultiSearchResponse response = future.actionGet();
Item[] items = response.getResponses();
for (int i = 0; i < items.length; i++) {
AggregatedPage<XXX> ts = resultMapper.mapResults(items[i].getResponse(), XXX.class, page);
// do with page
}
}
private SearchRequestBuilder prepareSearch(Client client, SearchQuery searchQuery) {
Assert.notNull(searchQuery.getIndices(), "No index defined for Query");
Assert.notNull(searchQuery.getTypes(), "No type defined for Query");
int startRecord = 0;
SearchRequestBuilder searchRequest = client.prepareSearch(toArray(searchQuery.getIndices()))
.setSearchType(searchQuery.getSearchType()).setTypes(toArray(searchQuery.getTypes()));
if (searchQuery.getSourceFilter() != null) {
SourceFilter sourceFilter = searchQuery.getSourceFilter();
searchRequest.setFetchSource(sourceFilter.getIncludes(), sourceFilter.getExcludes());
}
if (searchQuery.getPageable().isPaged()) {
startRecord = searchQuery.getPageable().getPageNumber() * searchQuery.getPageable().getPageSize();
searchRequest.setSize(searchQuery.getPageable().getPageSize());
}
searchRequest.setFrom(startRecord);
if (!searchQuery.getFields().isEmpty()) {
searchRequest.setFetchSource(toArray(searchQuery.getFields()), null);
}
if (searchQuery.getSort() != null) {
for (Sort.Order order : searchQuery.getSort()) {
searchRequest.addSort(order.getProperty(),
order.getDirection() == Sort.Direction.DESC ? SortOrder.DESC : SortOrder.ASC);
}
}
if (searchQuery.getMinScore() > 0) {
searchRequest.setMinScore(searchQuery.getMinScore());
}
if (searchQuery.getFilter() != null) {
searchRequest.setPostFilter(searchQuery.getFilter());
}
if (!isEmpty(searchQuery.getElasticsearchSorts())) {
for (SortBuilder sort : searchQuery.getElasticsearchSorts()) {
searchRequest.addSort(sort);
}
}
if (!searchQuery.getScriptFields().isEmpty()) {
//_source should be return all the time
//searchRequest.addStoredField("_source");
for (ScriptField scriptedField : searchQuery.getScriptFields()) {
searchRequest.addScriptField(scriptedField.fieldName(), scriptedField.script());
}
}
if (searchQuery.getHighlightFields() != null) {
for (HighlightBuilder.Field highlightField : searchQuery.getHighlightFields()) {
searchRequest.highlighter(new HighlightBuilder().field(highlightField));
}
}
if (!isEmpty(searchQuery.getIndicesBoost())) {
for (IndexBoost indexBoost : searchQuery.getIndicesBoost()) {
searchRequest.addIndexBoost(indexBoost.getIndexName(), indexBoost.getBoost());
}
}
if (!isEmpty(searchQuery.getAggregations())) {
for (AbstractAggregationBuilder aggregationBuilder : searchQuery.getAggregations()) {
searchRequest.addAggregation(aggregationBuilder);
}
}
if (!isEmpty(searchQuery.getFacets())) {
for (FacetRequest aggregatedFacet : searchQuery.getFacets()) {
searchRequest.addAggregation(aggregatedFacet.getFacet());
}
}
return searchRequest.setQuery(searchQuery.getQuery());
}
答案 1 :(得分:0)
可能为时已晚,但是当我遇到相同的问题时,我没有任何答案就提出了问题。希望我的解决方案对其他搜索者有所帮助。 Spring数据Elasticsearch有很多限制,但是您可以使用ElasticSearch的Java客户端执行任何操作。
以下是Maven依赖项:
<!--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>
这是我的解决方法:
@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());
}
}
和实体获取结果:
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");
}
}