Skip to content

Commit f5814df

Browse files
committed
DATAES-631 - Consolidate query objects.
1 parent 79d75f8 commit f5814df

File tree

67 files changed

+2131
-5320
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+2131
-5320
lines changed

src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java

+249-1
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,43 @@
11
package org.springframework.data.elasticsearch.core;
22

3+
import static org.springframework.util.StringUtils.*;
4+
5+
import java.util.ArrayList;
6+
import java.util.HashMap;
7+
import java.util.Iterator;
8+
import java.util.List;
9+
import java.util.Map;
10+
11+
import org.elasticsearch.action.bulk.BulkItemResponse;
12+
import org.elasticsearch.action.bulk.BulkResponse;
13+
import org.elasticsearch.action.search.MultiSearchRequest;
14+
import org.elasticsearch.action.search.MultiSearchResponse;
15+
import org.elasticsearch.action.search.SearchRequest;
16+
import org.elasticsearch.common.collect.MapBuilder;
17+
import org.elasticsearch.index.query.MoreLikeThisQueryBuilder;
318
import org.slf4j.Logger;
419
import org.slf4j.LoggerFactory;
20+
import org.springframework.beans.BeansException;
21+
import org.springframework.context.ApplicationContext;
22+
import org.springframework.context.ApplicationContextAware;
23+
import org.springframework.data.domain.Page;
524
import org.springframework.data.elasticsearch.ElasticsearchException;
25+
import org.springframework.data.elasticsearch.annotations.Document;
626
import org.springframework.data.elasticsearch.annotations.Mapping;
27+
import org.springframework.data.elasticsearch.annotations.Setting;
728
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
829
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
30+
import org.springframework.data.elasticsearch.core.document.SearchDocumentResponse;
931
import org.springframework.data.elasticsearch.core.index.MappingBuilder;
32+
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
33+
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
1034
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
35+
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
36+
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
37+
import org.springframework.data.elasticsearch.core.query.NativeSearchQuery;
38+
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
39+
import org.springframework.data.elasticsearch.core.query.Query;
40+
import org.springframework.util.Assert;
1141
import org.springframework.util.StringUtils;
1242

1343
/**
@@ -16,11 +46,22 @@
1646
* @author Sascha Woo
1747
* @author Peter-Josef Meisch
1848
*/
19-
public abstract class AbstractElasticsearchTemplate implements ElasticsearchOperations {
49+
public abstract class AbstractElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {
2050

2151
private static final Logger LOGGER = LoggerFactory.getLogger(AbstractElasticsearchTemplate.class);
2252

2353
protected ElasticsearchConverter elasticsearchConverter;
54+
protected RequestFactory requestFactory;
55+
56+
public RequestFactory getRequestFactory() {
57+
return requestFactory;
58+
}
59+
60+
protected void initialize(ElasticsearchConverter elasticsearchConverter) {
61+
Assert.notNull(elasticsearchConverter, "elasticsearchConverter must not be null.");
62+
this.elasticsearchConverter = elasticsearchConverter;
63+
this.requestFactory = new RequestFactory(elasticsearchConverter);
64+
}
2465

2566
protected ElasticsearchConverter createElasticsearchConverter() {
2667
MappingElasticsearchConverter mappingElasticsearchConverter = new MappingElasticsearchConverter(
@@ -29,6 +70,13 @@ protected ElasticsearchConverter createElasticsearchConverter() {
2970
return mappingElasticsearchConverter;
3071
}
3172

73+
@Override
74+
public void setApplicationContext(ApplicationContext context) throws BeansException {
75+
if (elasticsearchConverter instanceof ApplicationContextAware) {
76+
((ApplicationContextAware) elasticsearchConverter).setApplicationContext(context);
77+
}
78+
}
79+
3280
protected String buildMapping(Class<?> clazz) {
3381

3482
// load mapping specified in Mapping annotation if present
@@ -53,8 +101,208 @@ protected String buildMapping(Class<?> clazz) {
53101
}
54102
}
55103

104+
@Override
105+
public boolean createIndex(String indexName) {
106+
return createIndexIfNotCreated(indexName);
107+
}
108+
109+
private <T> boolean createIndexIfNotCreated(String indexName) {
110+
return indexExists(indexName) || createIndex(indexName, null);
111+
}
112+
113+
@Override
114+
public <T> boolean createIndex(Class<T> clazz) {
115+
return createIndexIfNotCreated(clazz);
116+
}
117+
118+
private <T> boolean createIndexIfNotCreated(Class<T> clazz) {
119+
return indexExists(getPersistentEntityFor(clazz).getIndexName()) || createIndexWithSettings(clazz);
120+
}
121+
122+
private <T> boolean createIndexWithSettings(Class<T> clazz) {
123+
if (clazz.isAnnotationPresent(Setting.class)) {
124+
String settingPath = clazz.getAnnotation(Setting.class).settingPath();
125+
if (hasText(settingPath)) {
126+
String settings = ResourceUtil.readFileFromClasspath(settingPath);
127+
if (hasText(settings)) {
128+
return createIndex(getPersistentEntityFor(clazz).getIndexName(), settings);
129+
}
130+
} else {
131+
LOGGER.info("settingPath in @Setting has to be defined. Using default instead.");
132+
}
133+
}
134+
return createIndex(getPersistentEntityFor(clazz).getIndexName(), getDefaultSettings(getPersistentEntityFor(clazz)));
135+
}
136+
137+
@Override
138+
public <T> boolean createIndex(Class<T> clazz, Object settings) {
139+
return createIndex(getPersistentEntityFor(clazz).getIndexName(), settings);
140+
}
141+
142+
@Override
143+
public void delete(Query query, Class<?> clazz, IndexCoordinates index) {
144+
Assert.notNull(query, "Query must not be null.");
145+
SearchRequest searchRequest = requestFactory.searchRequest(query, clazz, index);
146+
DeleteQuery deleteQuery = new DeleteQuery();
147+
deleteQuery.setQuery(searchRequest.source().query());
148+
delete(deleteQuery, index);
149+
}
150+
151+
@Override
152+
public <T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz, IndexCoordinates index) {
153+
Assert.notNull(query.getId(), "No document id defined for MoreLikeThisQuery");
154+
MoreLikeThisQueryBuilder moreLikeThisQueryBuilder = requestFactory.moreLikeThisQueryBuilder(query, index);
155+
return queryForPage(new NativeSearchQueryBuilder().withQuery(moreLikeThisQueryBuilder).build(), clazz, index);
156+
}
157+
158+
protected static String[] toArray(List<String> values) {
159+
String[] valuesAsArray = new String[values.size()];
160+
return values.toArray(valuesAsArray);
161+
}
162+
56163
@Override
57164
public ElasticsearchConverter getElasticsearchConverter() {
58165
return elasticsearchConverter;
59166
}
167+
168+
@Override
169+
public ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz) {
170+
Assert.isTrue(clazz.isAnnotationPresent(Document.class), "Unable to identify index name. " + clazz.getSimpleName()
171+
+ " is not a Document. Make sure the document class is annotated with @Document(indexName=\"foo\")");
172+
return elasticsearchConverter.getMappingContext().getRequiredPersistentEntity(clazz);
173+
}
174+
175+
private <T> Map getDefaultSettings(ElasticsearchPersistentEntity<T> persistentEntity) {
176+
177+
if (persistentEntity.isUseServerConfiguration())
178+
return new HashMap();
179+
180+
return new MapBuilder<String, String>().put("index.number_of_shards", String.valueOf(persistentEntity.getShards()))
181+
.put("index.number_of_replicas", String.valueOf(persistentEntity.getReplicas()))
182+
.put("index.refresh_interval", persistentEntity.getRefreshInterval())
183+
.put("index.store.type", persistentEntity.getIndexStoreType()).map();
184+
}
185+
186+
protected void checkForBulkOperationFailure(BulkResponse bulkResponse) {
187+
if (bulkResponse.hasFailures()) {
188+
Map<String, String> failedDocuments = new HashMap<>();
189+
for (BulkItemResponse item : bulkResponse.getItems()) {
190+
if (item.isFailed())
191+
failedDocuments.put(item.getId(), item.getFailureMessage());
192+
}
193+
throw new ElasticsearchException(
194+
"Bulk operation has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages ["
195+
+ failedDocuments + "]",
196+
failedDocuments);
197+
}
198+
}
199+
200+
/**
201+
* @param query
202+
* @param clazz
203+
* @deprecated index names and types should not be set in query
204+
*/
205+
@Deprecated
206+
protected void setPersistentEntityIndexAndType(Query query, Class clazz) {
207+
if (query.getIndices().isEmpty()) {
208+
String[] indices = retrieveIndexNameFromPersistentEntity(clazz);
209+
210+
if (indices != null) {
211+
query.addIndices(indices);
212+
}
213+
}
214+
if (query.getTypes().isEmpty()) {
215+
String[] types = retrieveTypeFromPersistentEntity(clazz);
216+
217+
if (types != null) {
218+
query.addTypes(types);
219+
}
220+
}
221+
}
222+
223+
private String[] retrieveIndexNameFromPersistentEntity(Class clazz) {
224+
if (clazz != null) {
225+
return new String[] { getPersistentEntityFor(clazz).getIndexName() };
226+
}
227+
return null;
228+
}
229+
230+
private String[] retrieveTypeFromPersistentEntity(Class clazz) {
231+
if (clazz != null) {
232+
return new String[] { getPersistentEntityFor(clazz).getIndexType() };
233+
}
234+
return null;
235+
}
236+
237+
@Override
238+
public <T> List<Page<T>> queryForPage(List<? extends Query> queries, Class<T> clazz, IndexCoordinates index) {
239+
MultiSearchRequest request = new MultiSearchRequest();
240+
for (Query query : queries) {
241+
request.add(requestFactory.searchRequest(query, clazz, index));
242+
}
243+
return doMultiSearch(queries, clazz, request);
244+
}
245+
246+
@Override
247+
public List<Page<?>> queryForPage(List<? extends Query> queries, List<Class<?>> classes, IndexCoordinates index) {
248+
MultiSearchRequest request = new MultiSearchRequest();
249+
Iterator<Class<?>> it = classes.iterator();
250+
for (Query query : queries) {
251+
request.add(requestFactory.searchRequest(query, it.next(), index));
252+
}
253+
return doMultiSearch(queries, classes, request);
254+
}
255+
256+
private <T> List<Page<T>> doMultiSearch(List<? extends Query> queries, Class<T> clazz, MultiSearchRequest request) {
257+
MultiSearchResponse.Item[] items = getMultiSearchResult(request);
258+
List<Page<T>> res = new ArrayList<>(queries.size());
259+
int c = 0;
260+
for (Query query : queries) {
261+
res.add(elasticsearchConverter.mapResults(SearchDocumentResponse.from(items[c++].getResponse()), clazz,
262+
query.getPageable()));
263+
}
264+
return res;
265+
}
266+
267+
private List<Page<?>> doMultiSearch(List<? extends Query> queries, List<Class<?>> classes,
268+
MultiSearchRequest request) {
269+
MultiSearchResponse.Item[] items = getMultiSearchResult(request);
270+
List<Page<?>> res = new ArrayList<>(queries.size());
271+
int c = 0;
272+
Iterator<Class<?>> it = classes.iterator();
273+
for (Query query : queries) {
274+
res.add(elasticsearchConverter.mapResults(SearchDocumentResponse.from(items[c++].getResponse()), it.next(),
275+
query.getPageable()));
276+
}
277+
return res;
278+
}
279+
280+
@Override
281+
public <T> boolean putMapping(Class<T> clazz) {
282+
return putMapping(clazz, buildMapping(clazz));
283+
}
284+
285+
@Override
286+
public <T> boolean putMapping(Class<T> clazz, Object mapping) {
287+
return putMapping(getIndexCoordinatesFor(clazz), mapping);
288+
}
289+
290+
@Override
291+
public <T> boolean putMapping(IndexCoordinates index, Class<T> clazz) {
292+
return putMapping(index, buildMapping(clazz));
293+
}
294+
295+
abstract protected MultiSearchResponse.Item[] getMultiSearchResult(MultiSearchRequest request);
296+
297+
protected void setPersistentEntityId(Object entity, String id) {
298+
299+
ElasticsearchPersistentEntity<?> persistentEntity = getPersistentEntityFor(entity.getClass());
300+
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
301+
302+
// Only deal with text because ES generated Ids are strings !
303+
304+
if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {
305+
persistentEntity.getPropertyAccessor(entity).setProperty(idProperty, id);
306+
}
307+
}
60308
}

0 commit comments

Comments
 (0)