1
0
mirror of synced 2026-07-07 18:50:00 +00:00

Compare commits

..

43 Commits

Author SHA1 Message Date
Spring Buildmaster 552a2dd834 DATAES-223 - Release version 1.3.2.RELEASE (Gosling SR2). 2015-12-18 00:55:31 -08:00
Oliver Gierke e7cd8dc346 DATAES-223 - Prepare 1.3.2.RELEASE (Gosling SR2). 2015-12-18 08:30:37 +01:00
Oliver Gierke 565c420834 DATAES-223 - Updated changelog. 2015-12-18 08:30:31 +01:00
Oliver Gierke b6c9a79df2 DATAES-212 - After release cleanups. 2015-11-19 12:58:42 +01:00
Spring Buildmaster b4c5ec6a23 DATAES-212 - Prepare next development iteration. 2015-11-15 05:41:19 -08:00
Spring Buildmaster a05507c505 DATAES-212 - Release version 1.3.1.RELEASE (Gosling SR1). 2015-11-15 05:41:17 -08:00
Oliver Gierke 0273d593a3 DATAES-212 - Prepare 1.3.1.RELEASE (Gosling SR1). 2015-11-15 14:06:54 +01:00
Oliver Gierke 33707d1228 DATAES-212 - Updated changelog. 2015-11-15 14:06:49 +01:00
Oliver Gierke 3fe4f15828 DATAES-202 - Updated changelog. 2015-10-14 13:57:54 +02:00
Artur Konczak 1c1b124d6e DATAES-193 - After release cleanups. 2015-09-28 11:51:26 +01:00
Kevin Leturc 11e2d11b5b DATAES-200 - BACKPORT from master - Set persistent entity index and type in query when no indices/types are set. 2015-09-27 20:12:01 +01:00
Artur Konczak 7db077c2c6 DATAES-171 - BACKPORT from master - added support for missing query keywords 2015-09-27 20:10:48 +01:00
Artur Konczak e6d698e250 DATAES-193 - Prepare next development iteration. 2015-09-27 20:04:50 +01:00
Spring Buildmaster 6a6c44401d DATAES-193 - Release version 1.3.0.RELEASE (Gosling GA). 2015-09-01 01:53:54 -07:00
Oliver Gierke 7f4ee37be3 DATAES-193 - Prepare 1.3.0.RELEASE (Gosling GA). 2015-09-01 10:13:36 +02:00
Oliver Gierke bc8b5b8bd8 DATAES-193 - Updated changelog. 2015-09-01 10:13:33 +02:00
Artur Konczak 6cdc765b24 DATAES-137 - set missing MappingContext in ElasticsearchRepositoryFactoryBean 2015-08-29 01:49:18 +01:00
Oliver Gierke f9e0b3a4f9 DATAES-186 - After release cleanups. 2015-08-04 14:09:22 +02:00
Spring Buildmaster 52fec26a1d DATAES-186 - Prepare next development iteration. 2015-08-04 04:29:19 -07:00
Spring Buildmaster eadf51ec27 DATAES-186 - Release version 1.3.0.RC1 (Gosling RC1). 2015-08-04 04:29:17 -07:00
Oliver Gierke af3121a165 DATAES-186 - Prepare 1.3.0.RC1 (Gosling RC1). 2015-08-04 11:48:44 +02:00
Oliver Gierke 9b28ca805b DATAES-186 - Updated changelog. 2015-08-04 11:48:34 +02:00
Oliver Gierke 9d8bc61401 DATAES-184 - Updated changelog. 2015-07-28 16:50:21 +02:00
Oliver Gierke ae1a873705 DATASOLR-250 - Switched to PersistentEntityInformation to avoid reference to BeanWrapper.
MappingElasticsearchEntityInformation now extends PersistentEntityInformation over AbstractInformation to be able to use the default implementations of getId(…) and getIdType().

Related ticket: DATACMNS-738.
2015-07-22 21:24:11 +02:00
Oliver Gierke 9524b2cc8d DATAES-173 - Updated changelog. 2015-07-01 10:22:17 +02:00
Oliver Gierke d83a6541aa DATAES-174 - Updated changelog. 2015-07-01 08:01:11 +02:00
Oliver Gierke fdc62dd7d6 DATAES-175 - Updated changelog. 2015-06-30 14:21:36 +02:00
Kevin Leturc 416daef2f9 DATAES-165 - Add Java 8 Steram support in custom repositories. 2015-06-21 01:39:50 +01:00
Kevin Leturc 576495932e DATAES-167 - Add scan method for CriteriaQuery. 2015-06-21 01:11:39 +01:00
Matija Obreza c9ffc4417a DATAES-127 - Include total, other and missing count in TermResult
Include totalCount, otherCount and missingCount from TermsFacet in TermResult.
2015-06-21 00:13:41 +01:00
Artur Konczak e80ddd249f DATAES-103 - fix for schema parsing errors with Spring 4.0.x 2015-06-20 23:03:03 +01:00
Oliver Gierke 9a8c04c16f DATAES-168 - After release cleanups. 2015-06-02 11:40:22 +02:00
Spring Buildmaster d117f6f515 DATAES-168 - Prepare next development iteration. 2015-06-02 01:39:58 -07:00
Spring Buildmaster 3e1099740b DATAES-168 - Release version 1.3.0.M1 (Gosling M1). 2015-06-02 01:39:54 -07:00
Oliver Gierke 763e61c862 DATAES-168 - Prepare 1.3.0.M1 (Gosling M1). 2015-06-02 08:25:10 +02:00
Oliver Gierke ea02e99263 DATAES-168 - Updated changelog. 2015-06-02 08:24:59 +02:00
Artur Konczak a3828c6161 Additional tests to cover synonyms 2015-05-22 13:20:06 +02:00
Mohsin Husen 4a90020dc1 DATAES-157 - support deleteBy operation 2015-05-15 13:21:38 +01:00
Mohsin Husen 01a67eef05 DATAES-164 - CriteriaQuery equals method has to use AND operator instead of OR 2015-05-15 12:23:23 +01:00
Mohsin Husen 0825f15ec3 DATAES-94 - upgrade to latest elasticsearch 1.5.2 driver 2015-05-12 15:54:49 +01:00
XAVIER VANDEMEULEBROUCKE 7aaf7e1782 DATAES-158 - DATAES-159 2015-05-11 00:32:42 +01:00
Kevin Leturc 455df72923 DATAES-155 setPersistentEntityId in mapResutls(MultiGetResponse, Class). 2015-05-11 00:19:33 +01:00
Artur Konczak cee493a6c7 DATAES-162 - Adapt to changes in Spring Data Commons.
Tweaked method signatures in ElasticsearchRepositoryFactory after some signature changes in Spring Data Commons. Use newly introduced getTragetRepositoryViaReflection(…) to obtain the repository instance via the super class.

Added repositoryBaseClass() attribute to @EnableMongoRepositories.

Related tickets: DATACMNS-542
2015-05-09 00:45:34 +01:00
35 changed files with 1390 additions and 270 deletions
+14 -7
View File
@@ -1,15 +1,15 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-elasticsearch</artifactId>
<version>1.2.3.BUILD-SNAPSHOT</version>
<version>1.3.2.RELEASE</version>
<parent>
<groupId>org.springframework.data.build</groupId>
<artifactId>spring-data-parent</artifactId>
<version>1.6.3.BUILD-SNAPSHOT</version>
<version>1.7.2.RELEASE</version>
<relativePath>../spring-data-build/parent/pom.xml</relativePath>
</parent>
@@ -23,8 +23,8 @@
<commonscollections>3.2.1</commonscollections>
<commonslang>2.6</commonslang>
<elasticsearch>1.4.4</elasticsearch>
<springdata.commons>1.10.3.BUILD-SNAPSHOT</springdata.commons>
<elasticsearch>1.5.2</elasticsearch>
<springdata.commons>1.11.2.RELEASE</springdata.commons>
</properties>
@@ -121,6 +121,13 @@
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.4</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
@@ -150,8 +157,8 @@
<repositories>
<repository>
<id>spring-libs-snapshot</id>
<url>https://repo.spring.io/libs-snapshot</url>
<id>spring-libs-release</id>
<url>https://repo.spring.io/libs-release</url>
</repository>
</repositories>
@@ -24,10 +24,11 @@ import java.util.List;
import java.util.ListIterator;
import org.apache.lucene.queryparser.flexible.core.util.StringUtils;
import org.elasticsearch.index.query.*;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostableQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryStringQueryBuilder;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.geo.Point;
import org.springframework.util.Assert;
/**
@@ -36,6 +37,7 @@ import org.springframework.util.Assert;
* @author Rizwan Idrees
* @author Mohsin Husen
* @author Franck Marchand
* @author Artur Konczak
*/
class CriteriaQueryProcessor {
@@ -49,11 +51,19 @@ class CriteriaQueryProcessor {
List<QueryBuilder> mustQueryBuilderList = new LinkedList<QueryBuilder>();
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
QueryBuilder firstQuery = null;
boolean negateFirstQuery = false;
while (chainIterator.hasNext()) {
Criteria chainedCriteria = chainIterator.next();
QueryBuilder queryFragmentForCriteria = createQueryFragmentForCriteria(chainedCriteria);
if (queryFragmentForCriteria != null) {
if (firstQuery == null) {
firstQuery = queryFragmentForCriteria;
negateFirstQuery = chainedCriteria.isNegating();
continue;
}
if (chainedCriteria.isOr()) {
shouldQueryBuilderList.add(queryFragmentForCriteria);
} else if (chainedCriteria.isNegating()) {
@@ -64,6 +74,18 @@ class CriteriaQueryProcessor {
}
}
if (firstQuery != null) {
if (!shouldQueryBuilderList.isEmpty() && mustNotQueryBuilderList.isEmpty() && mustQueryBuilderList.isEmpty()) {
shouldQueryBuilderList.add(0, firstQuery);
} else {
if (negateFirstQuery) {
mustNotQueryBuilderList.add(0, firstQuery);
} else {
mustQueryBuilderList.add(0, firstQuery);
}
}
}
BoolQueryBuilder query = null;
if (!shouldQueryBuilderList.isEmpty() || !mustNotQueryBuilderList.isEmpty() || !mustQueryBuilderList.isEmpty()) {
@@ -98,12 +120,12 @@ class CriteriaQueryProcessor {
if (singeEntryCriteria) {
Criteria.CriteriaEntry entry = it.next();
query = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName);
query = processCriteriaEntry(entry, fieldName);
} else {
query = boolQuery();
while (it.hasNext()) {
Criteria.CriteriaEntry entry = it.next();
((BoolQueryBuilder) query).must(processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName));
((BoolQueryBuilder) query).must(processCriteriaEntry(entry, fieldName));
}
}
@@ -112,14 +134,18 @@ class CriteriaQueryProcessor {
}
private QueryBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
private QueryBuilder processCriteriaEntry(Criteria.CriteriaEntry entry,/* OperationKey key, Object value,*/ String fieldName) {
Object value = entry.getValue();
if (value == null) {
return null;
}
OperationKey key = entry.getKey();
QueryBuilder query = null;
String searchText = StringUtils.toString(value);
Iterable<Object> collection = null;
switch (key) {
case EQUALS:
query = queryString(searchText).field(fieldName).defaultOperator(QueryStringQueryBuilder.Operator.AND);
@@ -134,24 +160,42 @@ class CriteriaQueryProcessor {
query = queryString("*" + searchText).field(fieldName).analyzeWildcard(true);
break;
case EXPRESSION:
query = queryString((String) value).field(fieldName);
query = queryString(searchText).field(fieldName);
break;
case LESS_EQUAL:
query = rangeQuery(fieldName).lte(value);
break;
case GREATER_EQUAL:
query = rangeQuery(fieldName).gte(value);
break;
case BETWEEN:
Object[] ranges = (Object[]) value;
query = rangeQuery(fieldName).from(ranges[0]).to(ranges[1]);
break;
case LESS:
query = rangeQuery(fieldName).lt(value);
break;
case GREATER:
query = rangeQuery(fieldName).gt(value);
break;
case FUZZY:
query = fuzzyQuery(fieldName, (String) value);
query = fuzzyQuery(fieldName, searchText);
break;
case IN:
query = boolQuery();
Iterable<Object> collection = (Iterable<Object>) value;
collection = (Iterable<Object>) value;
for (Object item : collection) {
((BoolQueryBuilder) query).should(queryString((String) item).field(fieldName));
((BoolQueryBuilder) query).should(queryString(item.toString()).field(fieldName));
}
break;
case NOT_IN:
query = boolQuery();
collection = (Iterable<Object>) value;
for (Object item : collection) {
((BoolQueryBuilder) query).mustNot(queryString(item.toString()).field(fieldName));
}
break;
}
return query;
}
@@ -15,15 +15,16 @@
*/
package org.springframework.data.elasticsearch.core;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.elasticsearch.action.update.UpdateResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.data.util.CloseableIterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* ElasticsearchOperations
@@ -209,6 +210,46 @@ public interface ElasticsearchOperations {
*/
<T> FacetedPage<T> queryForPage(StringQuery query, Class<T> clazz, SearchResultMapper mapper);
/**
* Executes the given {@link CriteriaQuery} against elasticsearch and return result as {@link CloseableIterator}.
* <p>
* Returns a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of error.
*
* @param <T> element return type
* @param query
* @param clazz
* @return
* @since 1.3
*/
<T> CloseableIterator<T> stream(CriteriaQuery query, Class<T> clazz);
/**
* Executes the given {@link SearchQuery} against elasticsearch and return result as {@link CloseableIterator}.
* <p>
* Returns a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of error.
*
* @param <T> element return type
* @param query
* @param clazz
* @return
* @since 1.3
*/
<T> CloseableIterator<T> stream(SearchQuery query, Class<T> clazz);
/**
* Executes the given {@link SearchQuery} against elasticsearch and return result as {@link CloseableIterator} using custom mapper.
* <p>
* Returns a {@link CloseableIterator} that wraps an Elasticsearch scroll context that needs to be closed in case of error.
*
* @param <T> element return type
* @param query
* @param clazz
* @param mapper
* @return
* @since 1.3
*/
<T> CloseableIterator<T> stream(SearchQuery query, Class<T> clazz, SearchResultMapper mapper);
/**
* Execute the criteria query against elasticsearch and return result as {@link List}
*
@@ -323,6 +364,13 @@ public interface ElasticsearchOperations {
*/
void bulkIndex(List<IndexQuery> queries);
/**
* Bulk update all objects. Will do update
*
* @param queries
*/
void bulkUpdate(List<UpdateQuery> queries);
/**
* Delete the one object with provided id
*
@@ -333,6 +381,14 @@ public interface ElasticsearchOperations {
*/
String delete(String indexName, String type, String id);
/**
* Delete all records matching the criteria
*
* @param clazz
* @param criteriaQuery
*/
<T> void delete(CriteriaQuery criteriaQuery, Class<T> clazz);
/**
* Delete the one object with provided id
*
@@ -424,6 +480,16 @@ public interface ElasticsearchOperations {
*/
<T> void refresh(Class<T> clazz, boolean waitForOperation);
/**
* Returns scroll id for criteria query
*
* @param query
* @param scrollTimeInMillis
* @param noFields
* @return
*/
String scan(CriteriaQuery query, long scrollTimeInMillis, boolean noFields);
/**
* Returns scroll id for scan query
*
@@ -93,6 +93,7 @@ import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersiste
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.data.mapping.PersistentProperty;
import org.springframework.data.util.CloseableIterator;
import org.springframework.util.Assert;
/**
@@ -311,6 +312,9 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
if (elasticsearchFilter != null)
searchRequestBuilder.setPostFilter(elasticsearchFilter);
if (logger.isDebugEnabled()) {
logger.debug("doSearch query:\n" + searchRequestBuilder.toString());
}
SearchResponse response = getSearchResponse(searchRequestBuilder
.execute());
@@ -328,6 +332,81 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
return mapper.mapResults(response, clazz, query.getPageable());
}
@Override
public <T> CloseableIterator<T> stream(CriteriaQuery query, Class<T> clazz) {
final long scrollTimeInMillis = TimeValue.timeValueMinutes(1).millis();
setPersistentEntityIndexAndType(query, clazz);
final String initScrollId = scan(query, scrollTimeInMillis, false);
return doStream(initScrollId, scrollTimeInMillis, clazz, resultsMapper);
}
@Override
public <T> CloseableIterator<T> stream(SearchQuery query, Class<T> clazz) {
return stream(query, clazz, resultsMapper);
}
@Override
public <T> CloseableIterator<T> stream(SearchQuery query, final Class<T> clazz, final SearchResultMapper mapper) {
final long scrollTimeInMillis = TimeValue.timeValueMinutes(1).millis();
setPersistentEntityIndexAndType(query, clazz);
final String initScrollId = scan(query, scrollTimeInMillis, false);
return doStream(initScrollId, scrollTimeInMillis, clazz, mapper);
}
private <T> CloseableIterator<T> doStream(final String initScrollId, final long scrollTimeInMillis, final Class<T> clazz, final SearchResultMapper mapper) {
return new CloseableIterator<T>() {
/** As we couldn't retrieve single result with scroll, store current hits. */
private volatile Iterator<T> currentHits;
/** The scroll id. */
private volatile String scrollId = initScrollId;
/** If stream is finished (ie: cluster returns no results. */
private volatile boolean finished;
@Override
public void close() {
try {
// Clear scroll on cluster only in case of error (cause elasticsearch auto clear scroll when it's done)
if (!finished && scrollId != null && currentHits != null && currentHits.hasNext()) {
client.prepareClearScroll().addScrollId(scrollId).execute().actionGet();
}
} finally {
currentHits = null;
scrollId = null;
}
}
@Override
public boolean hasNext() {
// Test if stream is finished
if (finished) {
return false;
}
// Test if it remains hits
if (currentHits == null || !currentHits.hasNext()) {
// Do a new request
SearchResponse response = getSearchResponse(client.prepareSearchScroll(scrollId)
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).execute());
// Save hits and scroll id
currentHits = mapper.mapResults(response, clazz, null).iterator();
finished = !currentHits.hasNext();
scrollId = response.getScrollId();
}
return currentHits.hasNext();
}
@Override
public T next() {
if (hasNext()) {
return currentHits.next();
}
throw new NoSuchElementException();
}
};
}
@Override
public <T> long count(CriteriaQuery criteriaQuery, Class<T> clazz) {
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
@@ -447,6 +526,10 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
@Override
public UpdateResponse update(UpdateQuery query) {
return this.prepareUpdate(query).execute().actionGet();
}
private UpdateRequestBuilder prepareUpdate(UpdateQuery query) {
String indexName = isNotBlank(query.getIndexName()) ? query.getIndexName() : getPersistentEntityFor(query.getClazz()).getIndexName();
String type = isNotBlank(query.getType()) ? query.getType() : getPersistentEntityFor(query.getClazz()).getIndexType();
Assert.notNull(indexName, "No index defined for Query");
@@ -454,16 +537,24 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
Assert.notNull(query.getId(), "No Id define for Query");
Assert.notNull(query.getUpdateRequest(), "No IndexRequest define for Query");
UpdateRequestBuilder updateRequestBuilder = client.prepareUpdate(indexName, type, query.getId());
if (query.DoUpsert()) {
updateRequestBuilder.setDocAsUpsert(true)
.setDoc(query.getUpdateRequest().doc())
if (query.getUpdateRequest().script() == null) {
// doc
if (query.DoUpsert()) {
updateRequestBuilder.setDocAsUpsert(true)
.setDoc(query.getUpdateRequest().doc());
} else {
updateRequestBuilder.setDoc(query.getUpdateRequest().doc());
}
} else {
// or script
updateRequestBuilder
.setScript(query.getUpdateRequest().script(), query.getUpdateRequest().scriptType())
.setScriptParams(query.getUpdateRequest().scriptParams())
.setScriptLang(query.getUpdateRequest().scriptLang());
} else {
updateRequestBuilder.setDoc(query.getUpdateRequest().doc());
}
return updateRequestBuilder.execute().actionGet();
return updateRequestBuilder;
}
@Override
@@ -486,6 +577,26 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
}
}
@Override
public void bulkUpdate(List<UpdateQuery> queries) {
BulkRequestBuilder bulkRequest = client.prepareBulk();
for (UpdateQuery query : queries) {
bulkRequest.add(prepareUpdate(query));
}
BulkResponse bulkResponse = bulkRequest.execute().actionGet();
if (bulkResponse.hasFailures()) {
Map<String, String> failedDocuments = new HashMap<String, String>();
for (BulkItemResponse item : bulkResponse.getItems()) {
if (item.isFailed())
failedDocuments.put(item.getId(), item.getFailureMessage());
}
throw new ElasticsearchException(
"Bulk indexing has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages ["
+ failedDocuments + "]", failedDocuments
);
}
}
@Override
public <T> boolean indexExists(Class<T> clazz) {
return indexExists(getPersistentEntityFor(clazz).getIndexName());
@@ -551,29 +662,67 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
.setQuery(deleteQuery.getQuery()).execute().actionGet();
}
@Override
public <T> void delete(CriteriaQuery criteriaQuery, Class<T> clazz) {
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
Assert.notNull(elasticsearchQuery, "Query can not be null.");
DeleteQuery deleteQuery = new DeleteQuery();
deleteQuery.setQuery(elasticsearchQuery);
delete(deleteQuery, clazz);
}
@Override
public String scan(CriteriaQuery criteriaQuery, long scrollTimeInMillis, boolean noFields) {
Assert.notNull(criteriaQuery.getIndices(), "No index defined for Query");
Assert.notNull(criteriaQuery.getTypes(), "No type define for Query");
Assert.notNull(criteriaQuery.getPageable(), "Query.pageable is required for scan & scroll");
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(criteriaQuery.getCriteria());
FilterBuilder elasticsearchFilter = new CriteriaFilterProcessor().createFilterFromCriteria(criteriaQuery.getCriteria());
SearchRequestBuilder requestBuilder = prepareScan(criteriaQuery, scrollTimeInMillis, noFields);
if (elasticsearchQuery != null) {
requestBuilder.setQuery(elasticsearchQuery);
} else {
requestBuilder.setQuery(QueryBuilders.matchAllQuery());
}
if (elasticsearchFilter != null) {
requestBuilder.setPostFilter(elasticsearchFilter);
}
return getSearchResponse(requestBuilder.execute()).getScrollId();
}
@Override
public String scan(SearchQuery searchQuery, long scrollTimeInMillis, boolean noFields) {
Assert.notNull(searchQuery.getIndices(), "No index defined for Query");
Assert.notNull(searchQuery.getTypes(), "No type define for Query");
Assert.notNull(searchQuery.getPageable(), "Query.pageable is required for scan & scroll");
SearchRequestBuilder requestBuilder = client.prepareSearch(toArray(searchQuery.getIndices())).setSearchType(SCAN)
.setQuery(searchQuery.getQuery()).setTypes(toArray(searchQuery.getTypes()))
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).setFrom(0)
.setSize(searchQuery.getPageable().getPageSize());
SearchRequestBuilder requestBuilder = prepareScan(searchQuery, scrollTimeInMillis, noFields);
if (searchQuery.getFilter() != null) {
requestBuilder.setPostFilter(searchQuery.getFilter());
}
if (isNotEmpty(searchQuery.getFields())) {
requestBuilder.addFields(toArray(searchQuery.getFields()));
return getSearchResponse(requestBuilder.setQuery(searchQuery.getQuery()).execute()).getScrollId();
}
private SearchRequestBuilder prepareScan(Query query, long scrollTimeInMillis, boolean noFields) {
SearchRequestBuilder requestBuilder = client.prepareSearch(toArray(query.getIndices())).setSearchType(SCAN)
.setTypes(toArray(query.getTypes()))
.setScroll(TimeValue.timeValueMillis(scrollTimeInMillis)).setFrom(0)
.setSize(query.getPageable().getPageSize());
if (isNotEmpty(query.getFields())) {
requestBuilder.addFields(toArray(query.getFields()));
}
if (noFields) {
requestBuilder.setNoFields();
}
return getSearchResponse(requestBuilder.execute()).getScrollId();
return requestBuilder;
}
@Override
@@ -749,12 +898,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
}
private <T> SearchRequestBuilder prepareSearch(Query query, Class<T> clazz) {
if (query.getIndices().isEmpty()) {
query.addIndices(retrieveIndexNameFromPersistentEntity(clazz));
}
if (query.getTypes().isEmpty()) {
query.addTypes(retrieveTypeFromPersistentEntity(clazz));
}
setPersistentEntityIndexAndType(query, clazz);
return prepareSearch(query);
}
@@ -916,6 +1060,15 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
}
}
private void setPersistentEntityIndexAndType(Query query, Class clazz) {
if (query.getIndices().isEmpty()) {
query.addIndices(retrieveIndexNameFromPersistentEntity(clazz));
}
if (query.getTypes().isEmpty()) {
query.addTypes(retrieveTypeFromPersistentEntity(clazz));
}
}
private String[] retrieveIndexNameFromPersistentEntity(Class clazz) {
if (clazz != null) {
return new String[]{getPersistentEntityFor(clazz).getIndexName()};
@@ -56,7 +56,7 @@ public class DefaultFacetMapper {
for (TermsFacet.Entry entry : facet.getEntries()) {
entries.add(new Term(entry.getTerm().toString(), entry.getCount()));
}
return new TermResult(facet.getName(), entries);
return new TermResult(facet.getName(), entries, facet.getTotalCount(), facet.getOtherCount(), facet.getMissingCount());
}
private static FacetResult parseRange(RangeFacet facet) {
@@ -27,17 +27,36 @@ import org.springframework.data.elasticsearch.core.facet.FacetType;
* @author Mohsin Husen
* @author Artur Konczak
* @author Jonathan Yan
* @author Matija Obreza
*/
public class TermResult extends AbstractFacetResult {
private List<Term> terms;
private long total;
private long other;
private long missing;
public TermResult(String name, List<Term> terms) {
public TermResult(String name, List<Term> terms, long total, long other, long missing) {
super(name, FacetType.term);
this.terms = terms;
this.total = total;
this.other = other;
this.missing = missing;
}
public List<Term> getTerms() {
return terms;
}
public long getTotal() {
return total;
}
public long getOther() {
return other;
}
public long getMissing() {
return missing;
}
}
@@ -35,6 +35,17 @@ import org.springframework.util.Assert;
*/
public class Criteria {
@Override
public String toString() {
return "Criteria{" +
"field=" + field.getName() +
", boost=" + boost +
", negating=" + negating +
", queryCriteria=" + StringUtils.join(queryCriteria, '|') +
", filterCriteria=" + StringUtils.join(filterCriteria, '|') +
'}';
}
public static final String WILDCARD = "*";
public static final String CRITERIA_VALUE_SEPERATOR = " ";
@@ -71,7 +82,6 @@ public class Criteria {
public Criteria(Field field) {
Assert.notNull(field, "Field for criteria must not be null");
Assert.hasText(field.getName(), "Field.name for criteria must not be null/empty");
this.criteriaChain.add(this);
this.field = field;
}
@@ -304,7 +314,18 @@ public class Criteria {
* @return
*/
public Criteria lessThanEqual(Object upperBound) {
between(null, upperBound);
if (upperBound == null) {
throw new InvalidDataAccessApiUsageException("UpperBound can't be null");
}
queryCriteria.add(new CriteriaEntry(OperationKey.LESS_EQUAL, upperBound));
return this;
}
public Criteria lessThan(Object upperBound) {
if (upperBound == null) {
throw new InvalidDataAccessApiUsageException("UpperBound can't be null");
}
queryCriteria.add(new CriteriaEntry(OperationKey.LESS, upperBound));
return this;
}
@@ -315,7 +336,18 @@ public class Criteria {
* @return
*/
public Criteria greaterThanEqual(Object lowerBound) {
between(lowerBound, null);
if (lowerBound == null) {
throw new InvalidDataAccessApiUsageException("LowerBound can't be null");
}
queryCriteria.add(new CriteriaEntry(OperationKey.GREATER_EQUAL, lowerBound));
return this;
}
public Criteria greaterThan(Object lowerBound) {
if (lowerBound == null) {
throw new InvalidDataAccessApiUsageException("LowerBound can't be null");
}
queryCriteria.add(new CriteriaEntry(OperationKey.GREATER, lowerBound));
return this;
}
@@ -326,12 +358,7 @@ public class Criteria {
* @return
*/
public Criteria in(Object... values) {
if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) {
throw new InvalidDataAccessApiUsageException("At least one element "
+ (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "")
+ " has to be present.");
}
return in(Arrays.asList(values));
return in(toCollection(values));
}
/**
@@ -346,6 +373,25 @@ public class Criteria {
return this;
}
private List<Object> toCollection(Object... values) {
if (values.length == 0 || (values.length > 1 && values[1] instanceof Collection)) {
throw new InvalidDataAccessApiUsageException("At least one element "
+ (values.length > 0 ? ("of argument of type " + values[1].getClass().getName()) : "")
+ " has to be present.");
}
return Arrays.asList(values);
}
public Criteria notIn(Object... values) {
return notIn(toCollection(values));
}
public Criteria notIn(Iterable<?> values) {
Assert.notNull(values, "Collection of 'NotIn' values must not be null");
queryCriteria.add(new CriteriaEntry(OperationKey.NOT_IN, values));
return this;
}
/**
* Creates new CriteriaEntry for {@code location WITHIN distance}
*
@@ -522,7 +568,7 @@ public class Criteria {
}
public enum OperationKey {
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN, WITHIN, BBOX, NEAR;
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY, IN, NOT_IN, WITHIN, BBOX, NEAR, LESS, LESS_EQUAL, GREATER, GREATER_EQUAL;
}
public static class CriteriaEntry {
@@ -542,5 +588,13 @@ public class Criteria {
public Object getValue() {
return value;
}
@Override
public String toString() {
return "CriteriaEntry{" +
"key=" + key +
", value=" + value +
'}';
}
}
}
@@ -21,6 +21,7 @@ import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.Import;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;
import org.springframework.data.repository.config.DefaultRepositoryBaseClass;
import org.springframework.data.repository.query.QueryLookupStrategy.Key;
/**
@@ -103,6 +104,13 @@ public @interface EnableElasticsearchRepositories {
*/
Class<?> repositoryFactoryBeanClass() default ElasticsearchRepositoryFactoryBean.class;
/**
* Configure the repository base class to be used to create repository proxies for this particular configuration.
*
* @return
*/
Class<?> repositoryBaseClass() default DefaultRepositoryBaseClass.class;
// Elasticsearch specific configuration
/**
@@ -23,6 +23,9 @@ import org.springframework.data.elasticsearch.repository.query.parser.Elasticsea
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.parser.PartTree;
import org.springframework.util.ClassUtils;
import org.springframework.data.util.CloseableIterator;
import org.springframework.data.util.StreamUtils;
/**
* ElasticsearchPartQuery
@@ -46,9 +49,21 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery
public Object execute(Object[] parameters) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
CriteriaQuery query = createQuery(accessor);
if (queryMethod.isPageQuery()) {
if(tree.isDelete()) {
Object result = countOrGetDocumentsForDelete(query, accessor);
elasticsearchOperations.delete(query, queryMethod.getEntityInformation().getJavaType());
return result;
} else if (queryMethod.isPageQuery()) {
query.setPageable(accessor.getPageable());
return elasticsearchOperations.queryForPage(query, queryMethod.getEntityInformation().getJavaType());
} else if (queryMethod.isStreamQuery()) {
Class<?> entityType = queryMethod.getEntityInformation().getJavaType();
if (query.getPageable() == null) {
query.setPageable(new PageRequest(0, 20));
}
return StreamUtils.createStreamFromIterator((CloseableIterator<Object>) elasticsearchOperations.stream(query, entityType));
} else if (queryMethod.isCollectionQuery()) {
if (accessor.getPageable() == null) {
int itemCount = (int) elasticsearchOperations.count(query, queryMethod.getEntityInformation().getJavaType());
@@ -63,6 +78,26 @@ public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery
return elasticsearchOperations.queryForObject(query, queryMethod.getEntityInformation().getJavaType());
}
private Object countOrGetDocumentsForDelete(CriteriaQuery query, ParametersParameterAccessor accessor) {
Object result = null;
if (queryMethod.isCollectionQuery()) {
if (accessor.getPageable() == null) {
int itemCount = (int) elasticsearchOperations.count(query, queryMethod.getEntityInformation().getJavaType());
query.setPageable(new PageRequest(0, Math.max(1, itemCount)));
} else {
query.setPageable(accessor.getPageable());
}
result = elasticsearchOperations.queryForList(query, queryMethod.getEntityInformation().getJavaType());
}
if (ClassUtils.isAssignable(Number.class, queryMethod.getReturnedObjectType())) {
result = elasticsearchOperations.count(query, queryMethod.getEntityInformation().getJavaType());
}
return result;
}
public CriteriaQuery createQuery(ParametersParameterAccessor accessor) {
return new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();
}
@@ -41,6 +41,7 @@ import org.springframework.data.repository.query.parser.PartTree;
* @author Rizwan Idrees
* @author Mohsin Husen
* @author Franck Marchand
* @author Artur Konczak
*/
public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuery, CriteriaQuery> {
@@ -112,12 +113,14 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
return criteria.endsWith(parameters.next().toString());
case CONTAINING:
return criteria.contains(parameters.next().toString());
case AFTER:
case GREATER_THAN:
return criteria.greaterThan(parameters.next());
case AFTER:
case GREATER_THAN_EQUAL:
return criteria.greaterThanEqual(parameters.next());
case BEFORE:
case LESS_THAN:
return criteria.lessThan(parameters.next());
case BEFORE:
case LESS_THAN_EQUAL:
return criteria.lessThanEqual(parameters.next());
case BETWEEN:
@@ -125,7 +128,7 @@ public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuer
case IN:
return criteria.in(asArray(parameters.next()));
case NOT_IN:
return criteria.in(asArray(parameters.next())).not();
return criteria.notIn(asArray(parameters.next()));
case SIMPLE_PROPERTY:
case WITHIN: {
Object firstParameter = parameters.next();
@@ -27,6 +27,7 @@ import org.springframework.data.elasticsearch.repository.query.ElasticsearchQuer
import org.springframework.data.elasticsearch.repository.query.ElasticsearchStringQuery;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.core.NamedQueries;
import org.springframework.data.repository.core.RepositoryInformation;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy;
@@ -59,28 +60,8 @@ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
@Override
@SuppressWarnings({"rawtypes", "unchecked"})
protected Object getTargetRepository(RepositoryMetadata metadata) {
ElasticsearchEntityInformation<?, ?> entityInformation = getEntityInformation(metadata.getDomainType());
AbstractElasticsearchRepository repository;
// Probably a better way to store and look these up.
if (Integer.class.isAssignableFrom(entityInformation.getIdType())
|| Long.class.isAssignableFrom(entityInformation.getIdType())
|| Double.class.isAssignableFrom(entityInformation.getIdType())) {
// logger.debug("Using NumberKeyedRepository for " + metadata.getRepositoryInterface());
repository = new NumberKeyedRepository(getEntityInformation(metadata.getDomainType()), elasticsearchOperations);
} else if (entityInformation.getIdType() == String.class) {
// logger.debug("Using SimpleElasticsearchRepository for " + metadata.getRepositoryInterface());
repository = new SimpleElasticsearchRepository(getEntityInformation(metadata.getDomainType()),
elasticsearchOperations);
} else {
throw new IllegalArgumentException("Unsuppored ID type " + entityInformation.getIdType());
}
repository.setEntityClass(metadata.getDomainType());
return repository;
protected Object getTargetRepository(RepositoryInformation metadata) {
return getTargetRepositoryViaReflection(metadata,getEntityInformation(metadata.getDomainType()), elasticsearchOperations);
}
@Override
@@ -88,7 +69,15 @@ public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
if (isQueryDslRepository(metadata.getRepositoryInterface())) {
throw new IllegalArgumentException("QueryDsl Support has not been implemented yet.");
}
return SimpleElasticsearchRepository.class;
if (Integer.class.isAssignableFrom(metadata.getIdType())
|| Long.class.isAssignableFrom(metadata.getIdType())
|| Double.class.isAssignableFrom(metadata.getIdType())) {
return NumberKeyedRepository.class;
} else if (metadata.getIdType() == String.class) {
return SimpleElasticsearchRepository.class;
} else {
throw new IllegalArgumentException("Unsuppored ID type " + metadata.getIdType());
}
}
private static boolean isQueryDslRepository(Class<?> repositoryInterface) {
@@ -42,6 +42,7 @@ public class ElasticsearchRepositoryFactoryBean<T extends Repository<S, ID>, S,
*/
public void setElasticsearchOperations(ElasticsearchOperations operations) {
Assert.notNull(operations);
setMappingContext(operations.getElasticsearchConverter().getMappingContext());
this.operations = operations;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2013 the original author or authors.
* Copyright 2013-2015 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -21,8 +21,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.mapping.model.BeanWrapper;
import org.springframework.data.repository.core.support.AbstractEntityInformation;
import org.springframework.data.repository.core.support.PersistentEntityInformation;
import org.springframework.util.Assert;
/**
@@ -34,44 +33,27 @@ import org.springframework.util.Assert;
* @author Rizwan Idrees
* @author Mohsin Husen
* @author Ryan Henszey
* @author Oliver Gierke
*/
public class MappingElasticsearchEntityInformation<T, ID extends Serializable> extends AbstractEntityInformation<T, ID>
public class MappingElasticsearchEntityInformation<T, ID extends Serializable> extends PersistentEntityInformation<T, ID>
implements ElasticsearchEntityInformation<T, ID> {
private static final Logger logger = LoggerFactory.getLogger(MappingElasticsearchEntityInformation.class);
private final ElasticsearchPersistentEntity<T> entityMetadata;
private final String indexName;
private final String type;
private Class<?> idClass;
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity) {
this(entity, null, null);
}
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity, String indexName, String type) {
super(entity.getType());
super(entity);
this.entityMetadata = entity;
this.indexName = indexName;
this.type = type;
this.idClass = entity.getIdProperty().getType();
}
@SuppressWarnings("unchecked")
@Override
public ID getId(T entity) {
ElasticsearchPersistentProperty id = entityMetadata.getIdProperty();
try {
return (ID) BeanWrapper.create(entity, null).getProperty(id);
} catch (Exception e) {
throw new IllegalStateException("ID could not be resolved", e);
}
}
@SuppressWarnings("unchecked")
@Override
public Class<ID> getIdType() {
return (Class<ID>) idClass;
}
@Override
public String getIdAttribute() {
@@ -96,7 +78,7 @@ public class MappingElasticsearchEntityInformation<T, ID extends Serializable> e
ElasticsearchPersistentProperty versionProperty = entityMetadata.getVersionProperty();
try {
if (versionProperty != null) {
return (Long) BeanWrapper.create(entity, null).getProperty(versionProperty);
return (Long) entityMetadata.getPropertyAccessor(entity).getProperty(versionProperty);
}
} catch (Exception e) {
throw new IllegalStateException("failed to load version field", e);
@@ -109,7 +91,7 @@ public class MappingElasticsearchEntityInformation<T, ID extends Serializable> e
ElasticsearchPersistentProperty parentProperty = entityMetadata.getParentIdProperty();
try {
if (parentProperty != null) {
return (String) BeanWrapper.create(entity, null).getProperty(parentProperty);
return (String) entityMetadata.getPropertyAccessor(entity).getProperty(parentProperty);
}
} catch (Exception e) {
throw new IllegalStateException("failed to load parent ID: " + e, e);
-38
View File
@@ -1,44 +1,6 @@
Spring Data Elasticsearch Changelog
===================================
Changes in version 2.0.0.RELEASE (2016-04-06)
---------------------------------------------
* DATAES-245 - Release 2.0 GA (Hopper).
Changes in version 2.0.0.RC1 (2016-03-18)
-----------------------------------------
* DATAES-241 - remove commons-collections dependency and use CollectionUtils from Spring Utils.
* DATAES-240 - Release 2.0 RC1 (Hopper).
* DATAES-238 - ElasticsearchTemplate.prepareUpdate() does not preserve routing parameter which is required for updating child documents.
* DATAES-237 - path-configuration fails to load configs from inside jars.
* DATAES-236 - Clear the search contexts associated with specified scroll id.
* DATAES-234 - CDI support can fail due to Set.toString() used as Map key.
* DATAES-211 - Upgrade to Elasticsearch 2.0.
* DATAES-188 - Source filtering feature Implementation.
* DATAES-124 - ElasticSearchTemplate should expose client.
Changes in version 1.3.4.RELEASE (2016-02-23)
---------------------------------------------
* DATAES-235 - Release 1.3.4 (Gosling SR4).
Changes in version 1.4.0.M1 (2016-02-12)
----------------------------------------
* DATAES-232 - Add code of conduct.
* DATAES-231 - Release 1.4 M1 (Hopper).
* DATAES-230 - Remove unnecessary type check in AbstractElasticsearchRepository.
* DATAES-224 - ElasticsearchTemplate discards newlines in mappings and settings files.
* DATAES-221 - Adapt to changes in Spring Data Commons.
* DATAES-216 - Add support to Indices Boost.
* DATAES-210 - Typo in error message.
* DATAES-209 - Handle dynamic mapping annotation at field level.
* DATAES-194 - Tests should clean up "data" directory.
* DATAES-171 - findByIdNotIn not work.
* DATAES-94 - Bump to support ES 1.2.0.
Changes in version 1.3.2.RELEASE (2015-12-18)
---------------------------------------------
* DATAES-223 - Release 1.3.2 (Gosling).
+1 -1
View File
@@ -1,4 +1,4 @@
Spring Data Elasticsearch 1.2.2
Spring Data Elasticsearch 1.3.2
Copyright (c) [2013-2015] Pivotal Software, Inc.
This product is licensed to you under the Apache License, Version 2.0 (the "License").
@@ -5,7 +5,8 @@
xmlns:tool="http://www.springframework.org/schema/tool"
xmlns:repository="http://www.springframework.org/schema/data/repository"
targetNamespace="http://www.springframework.org/schema/data/elasticsearch"
elementFormDefault="qualified" attributeFormDefault="unqualified">
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:import namespace="http://www.springframework.org/schema/tool"/>
@@ -37,7 +38,7 @@
<xsd:element name="node-client">
<xsd:annotation>
<xsd:documentation source="java: org.springframework.data.elasticsearch.client.NodeClientFactoryBean"/>
<xsd:documentation/>
<xsd:appinfo>
<tool:assignable-to type="org.elasticsearch.client.Client"/>
</xsd:appinfo>
@@ -48,28 +49,31 @@
<xsd:attribute name="local" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation>
<![CDATA[local here means local on the JVM (well, actually class loader) level, meaning that two local servers started within the same JVM will discover themselves and form a cluster]]></xsd:documentation>
<![CDATA[local here means local on the JVM (well, actually class loader) level, meaning that two local servers started within the same JVM will discover themselves and form a cluster]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cluster-name" type="xsd:string" default="elasticsearch">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Name of the cluster in which this instance of node client will connect to]]> </xsd:documentation>
<![CDATA[Name of the cluster in which this instance of node client will connect to]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="http-enabled" type="xsd:boolean" default="true">
<xsd:annotation>
<xsd:documentation><![CDATA[to enable or desable http port]]> </xsd:documentation>
<xsd:documentation>
<![CDATA[ to enable or disable http port ]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:element name="transport-client">
<xsd:annotation>
<xsd:documentation source="java: org.springframework.data.elasticsearch.client.TransportClientFactoryBean"/>
<xsd:documentation/>
<xsd:appinfo>
<tool:assignable-to type="org.elasticsearch.client.Client"/>
</xsd:appinfo>
@@ -80,42 +84,47 @@
<xsd:attribute name="cluster-nodes" type="xsd:string" default="127.0.0.1:9300">
<xsd:annotation>
<xsd:documentation>
<![CDATA[The comma delimited list of host:port entries to use for elasticsearch cluster.]]></xsd:documentation>
<![CDATA[The comma delimited list of host:port entries to use for elasticsearch cluster.]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="cluster-name" type="xsd:string" default="elasticsearch">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Name of the cluster in which this instance of node client will connect to]]> </xsd:documentation>
<![CDATA[Name of the cluster in which this instance of node client will connect to]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="client-transport-sniff" type="xsd:boolean" default="true">
<xsd:annotation>
<xsd:documentation>
<![CDATA[The client allows to sniff the rest of the cluster, and add those into its list of machines to use.]]> </xsd:documentation>
<![CDATA[The client allows to sniff the rest of the cluster, and add those into its list of machines to use.]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="client-transport-ignore-cluster-name" type="xsd:boolean" default="false">
<xsd:annotation>
<xsd:documentation>
<![CDATA[Set to true to ignore cluster name validation of connected nodes. (since 0.19.4)]]> </xsd:documentation>
<![CDATA[Set to true to ignore cluster name validation of connected nodes. (since 0.19.4)]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="client-transport-ping-timeout" type="xsd:string" default="5s">
<xsd:annotation>
<xsd:documentation>
<![CDATA[The time to wait for a ping response from a node. Defaults to 5s.]]> </xsd:documentation>
<![CDATA[The time to wait for a ping response from a node. Defaults to 5s.]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="client-transport-nodes-sampler-interval" type="xsd:string" default="5s">
<xsd:annotation>
<xsd:documentation>
<![CDATA[How often to sample / ping the nodes listed and connected. Defaults to 5s.]]> </xsd:documentation>
<![CDATA[How often to sample / ping the nodes listed and connected. Defaults to 5s.]]>
</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
</xsd:schema>
@@ -15,14 +15,6 @@
*/
package org.springframework.data.elasticsearch.core;
import static org.apache.commons.lang.RandomStringUtils.*;
import static org.elasticsearch.index.query.FilterBuilders.*;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.elasticsearch.action.get.MultiGetItemResponse;
import org.elasticsearch.action.get.MultiGetResponse;
@@ -50,9 +42,19 @@ import org.springframework.data.elasticsearch.entities.HetroEntity1;
import org.springframework.data.elasticsearch.entities.HetroEntity2;
import org.springframework.data.elasticsearch.entities.SampleEntity;
import org.springframework.data.elasticsearch.entities.SampleMappingEntity;
import org.springframework.data.util.CloseableIterator;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.*;
import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
import static org.elasticsearch.index.query.FilterBuilders.boolFilter;
import static org.elasticsearch.index.query.FilterBuilders.termFilter;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
/**
* @author Rizwan Idrees
* @author Mohsin Husen
@@ -254,6 +256,41 @@ public class ElasticsearchTemplateTests {
assertThat(sampleEntities.getTotalElements(), is(equalTo(2L)));
}
@Test
public void shouldDoBulkUpdate() {
//given
String documentId = randomNumeric(5);
String messageBeforeUpdate = "some test message";
String messageAfterUpdate = "test message";
SampleEntity sampleEntity = new SampleEntityBuilder(documentId)
.message(messageBeforeUpdate)
.version(System.currentTimeMillis()).build();
IndexQuery indexQuery = getIndexQuery(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
IndexRequest indexRequest = new IndexRequest();
indexRequest.source("message", messageAfterUpdate);
UpdateQuery updateQuery = new UpdateQueryBuilder().withId(documentId)
.withClass(SampleEntity.class).withIndexRequest(indexRequest).build();
List<UpdateQuery> queries = new ArrayList<UpdateQuery>();
queries.add(updateQuery);
// when
elasticsearchTemplate.bulkUpdate(queries);
//then
GetQuery getQuery = new GetQuery();
getQuery.setId(documentId);
SampleEntity indexedEntity = elasticsearchTemplate.queryForObject(getQuery, SampleEntity.class);
assertThat(indexedEntity.getMessage(), is(messageAfterUpdate));
}
@Test
public void shouldDeleteDocumentForGivenId() {
// given
@@ -523,6 +560,28 @@ public class ElasticsearchTemplateTests {
assertThat(sampleEntity1, is(notNullValue()));
}
@Test
public void shouldDeleteGivenCriteriaQuery() {
// given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntityBuilder(documentId).message("test message")
.version(System.currentTimeMillis()).build();
IndexQuery indexQuery = getIndexQuery(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").contains("test"));
// when
elasticsearchTemplate.delete(criteriaQuery, SampleEntity.class);
// then
StringQuery stringQuery = new StringQuery(matchAllQuery().toString());
List<SampleEntity> sampleEntities = elasticsearchTemplate.queryForList(stringQuery, SampleEntity.class);
assertThat(sampleEntities.size(), is(0));
}
@Test
public void shouldReturnSpecifiedFields() {
// given
@@ -589,8 +648,39 @@ public class ElasticsearchTemplateTests {
assertThat(sampleEntities.getContent(), hasItem(sampleEntity));
}
/*
DATAES-167
*/
@Test
public void shouldReturnResultsWithScanAndScroll() {
public void shouldReturnResultsWithScanAndScrollForGivenCriteriaQuery() {
//given
List<IndexQuery> entities = createSampleEntitiesWithMessage("Test message", 30);
// when
elasticsearchTemplate.bulkIndex(entities);
elasticsearchTemplate.refresh(SampleEntity.class, true);
// then
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria());
criteriaQuery.addIndices(INDEX_NAME);
criteriaQuery.addTypes(TYPE_NAME);
criteriaQuery.setPageable(new PageRequest(0, 10));
String scrollId = elasticsearchTemplate.scan(criteriaQuery, 1000, false);
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
boolean hasRecords = true;
while (hasRecords) {
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L, SampleEntity.class);
if (page.hasContent()) {
sampleEntities.addAll(page.getContent());
} else {
hasRecords = false;
}
}
assertThat(sampleEntities.size(), is(equalTo(30)));
}
@Test
public void shouldReturnResultsWithScanAndScrollForGivenSearchQuery() {
//given
List<IndexQuery> entities = createSampleEntitiesWithMessage("Test message", 30);
// when
@@ -615,11 +705,60 @@ public class ElasticsearchTemplateTests {
assertThat(sampleEntities.size(), is(equalTo(30)));
}
/*
DATAES-167
*/
@Test
public void shouldReturnResultsWithScanAndScrollForSpecifiedFieldsForCriteriaCriteria() {
//given
List<IndexQuery> entities = createSampleEntitiesWithMessage("Test message", 30);
// when
elasticsearchTemplate.bulkIndex(entities);
elasticsearchTemplate.refresh(SampleEntity.class, true);
// then
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria());
criteriaQuery.addIndices(INDEX_NAME);
criteriaQuery.addTypes(TYPE_NAME);
criteriaQuery.addFields("message");
criteriaQuery.setPageable(new PageRequest(0, 10));
String scrollId = elasticsearchTemplate.scan(criteriaQuery, 5000, false);
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
boolean hasRecords = true;
while (hasRecords) {
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L, new SearchResultMapper() {
@Override
public <T> FacetedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
List<SampleEntity> result = new ArrayList<SampleEntity>();
for (SearchHit searchHit : response.getHits()) {
String message = searchHit.getFields().get("message").getValue();
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(searchHit.getId());
sampleEntity.setMessage(message);
result.add(sampleEntity);
}
if (result.size() > 0) {
return new FacetedPageImpl<T>((List<T>) result);
}
return null;
}
});
if (page != null) {
sampleEntities.addAll(page.getContent());
} else {
hasRecords = false;
}
}
assertThat(sampleEntities.size(), is(equalTo(30)));
}
/*
DATAES-84
*/
@Test
public void shouldReturnResultsWithScanAndScrollForSpecifiedFields() {
public void shouldReturnResultsWithScanAndScrollForSpecifiedFieldsForSearchCriteria() {
//given
List<IndexQuery> entities = createSampleEntitiesWithMessage("Test message", 30);
// when
@@ -665,8 +804,57 @@ public class ElasticsearchTemplateTests {
assertThat(sampleEntities.size(), is(equalTo(30)));
}
/*
DATAES-167
*/
@Test
public void shouldReturnResultsForScanAndScrollWithCustomResultMapper() {
public void shouldReturnResultsForScanAndScrollWithCustomResultMapperForGivenCriteriaQuery() {
//given
List<IndexQuery> entities = createSampleEntitiesWithMessage("Test message", 30);
// when
elasticsearchTemplate.bulkIndex(entities);
elasticsearchTemplate.refresh(SampleEntity.class, true);
// then
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria());
criteriaQuery.addIndices(INDEX_NAME);
criteriaQuery.addTypes(TYPE_NAME);
criteriaQuery.setPageable(new PageRequest(0, 10));
String scrollId = elasticsearchTemplate.scan(criteriaQuery, 1000, false);
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
boolean hasRecords = true;
while (hasRecords) {
Page<SampleEntity> page = elasticsearchTemplate.scroll(scrollId, 5000L, new SearchResultMapper() {
@Override
public <T> FacetedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
List<SampleEntity> chunk = new ArrayList<SampleEntity>();
for (SearchHit searchHit : response.getHits()) {
if (response.getHits().getHits().length <= 0) {
return null;
}
SampleEntity user = new SampleEntity();
user.setId(searchHit.getId());
user.setMessage((String) searchHit.getSource().get("message"));
chunk.add(user);
}
if (chunk.size() > 0) {
return new FacetedPageImpl<T>((List<T>) chunk);
}
return null;
}
});
if (page != null) {
sampleEntities.addAll(page.getContent());
} else {
hasRecords = false;
}
}
assertThat(sampleEntities.size(), is(equalTo(30)));
}
@Test
public void shouldReturnResultsForScanAndScrollWithCustomResultMapperForGivenSearchQuery() {
//given
List<IndexQuery> entities = createSampleEntitiesWithMessage("Test message", 30);
// when
@@ -709,6 +897,31 @@ public class ElasticsearchTemplateTests {
assertThat(sampleEntities.size(), is(equalTo(30)));
}
/*
DATAES-167
*/
@Test
public void shouldReturnResultsWithStreamForGivenCriteriaQuery() {
//given
List<IndexQuery> entities = createSampleEntitiesWithMessage("Test message", 30);
// when
elasticsearchTemplate.bulkIndex(entities);
elasticsearchTemplate.refresh(SampleEntity.class, true);
// then
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria());
criteriaQuery.addIndices(INDEX_NAME);
criteriaQuery.addTypes(TYPE_NAME);
criteriaQuery.setPageable(new PageRequest(0, 10));
CloseableIterator<SampleEntity> stream = elasticsearchTemplate.stream(criteriaQuery, SampleEntity.class);
List<SampleEntity> sampleEntities = new ArrayList<SampleEntity>();
while (stream.hasNext()) {
sampleEntities.add(stream.next());
}
assertThat(sampleEntities.size(), is(equalTo(30)));
}
private static List<IndexQuery> createSampleEntitiesWithMessage(String message, int numberOfEntities) {
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
for (int i = 0; i < numberOfEntities; i++) {
@@ -102,6 +102,10 @@ public class ElasticsearchTemplateFacetTests {
term = facet.getTerms().get(3);
assertThat(term.getTerm(), is(JONATHAN_YAN));
assertThat(term.getCount(), is(1));
assertThat(facet.getTotal(), is(10l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(0l));
}
@Test
@@ -129,6 +133,10 @@ public class ElasticsearchTemplateFacetTests {
term = facet.getTerms().get(2);
assertThat(term.getTerm(), is(MOHSIN_HUSEN));
assertThat(term.getCount(), is(1));
assertThat(facet.getTotal(), is(6l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(0l));
}
@Test
@@ -150,6 +158,10 @@ public class ElasticsearchTemplateFacetTests {
Term term = facet.getTerms().get(0);
assertThat(term.getTerm(), is(MOHSIN_HUSEN));
assertThat(term.getCount(), is(1));
assertThat(facet.getTotal(), is(6l));
assertThat(facet.getOther(), is(5l));
assertThat(facet.getMissing(), is(0l));
}
@Test
@@ -180,6 +192,10 @@ public class ElasticsearchTemplateFacetTests {
term = facet.getTerms().get(3);
assertThat(term.getTerm(), is(RIZWAN_IDREES));
assertThat(term.getCount(), is(4));
assertThat(facet.getTotal(), is(10l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(0l));
}
@Test
@@ -210,6 +226,10 @@ public class ElasticsearchTemplateFacetTests {
term = facet.getTerms().get(3);
assertThat(term.getTerm(), is(RIZWAN_IDREES));
assertThat(term.getCount(), is(4));
assertThat(facet.getTotal(), is(10l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(0l));
}
@Test
@@ -238,6 +258,43 @@ public class ElasticsearchTemplateFacetTests {
term = facet.getTerms().get(2);
assertThat(term.getTerm(), is(Integer.toString(YEAR_2002)));
assertThat(term.getCount(), is(1));
assertThat(facet.getTotal(), is(6l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(1l));
}
@Test
public void shouldReturnExistingFacetedYearsForGivenQuery() {
// given
String facetName = "fyears";
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery())
.withFilter(FilterBuilders.notFilter(FilterBuilders.missingFilter("publishedYears")))
.withFacet(new TermFacetRequestBuilder(facetName).applyQueryFilter().fields("publishedYears").descCount().build()).build();
// when
FacetedPage<ArticleEntity> result = elasticsearchTemplate.queryForPage(searchQuery, ArticleEntity.class);
// then
assertThat(result.getNumberOfElements(), is(equalTo(3)));
TermResult facet = (TermResult) result.getFacet(facetName);
assertThat(facet.getTerms().size(), is(equalTo(3)));
Term term = facet.getTerms().get(0);
assertThat(term.getTerm(), is(Integer.toString(YEAR_2000)));
assertThat(term.getCount(), is(3));
term = facet.getTerms().get(1);
assertThat(term.getTerm(), is(Integer.toString(YEAR_2001)));
assertThat(term.getCount(), is(2));
term = facet.getTerms().get(2);
assertThat(term.getTerm(), is(Integer.toString(YEAR_2002)));
assertThat(term.getCount(), is(1));
assertThat(facet.getTotal(), is(6l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(0l));
}
@@ -283,6 +340,10 @@ public class ElasticsearchTemplateFacetTests {
term = facet.getTerms().get(6);
assertThat(term.getTerm(), is(RIZWAN_IDREES));
assertThat(term.getCount(), is(4));
assertThat(facet.getTotal(), is(16l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(1l));
}
@Test
@@ -331,6 +392,10 @@ public class ElasticsearchTemplateFacetTests {
stringTerm = stringFacet.getTerms().get(3);
assertThat(stringTerm.getTerm(), is(RIZWAN_IDREES));
assertThat(stringTerm.getCount(), is(4));
assertThat(stringFacet.getTotal(), is(10l));
assertThat(stringFacet.getOther(), is(0l));
assertThat(stringFacet.getMissing(), is(0l));
}
@@ -360,6 +425,10 @@ public class ElasticsearchTemplateFacetTests {
term = facet.getTerms().get(2);
assertThat(term.getTerm(), is(Integer.toString(YEAR_2002)));
assertThat(term.getCount(), is(1));
assertThat(facet.getTotal(), is(6l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(1l));
}
@Test
@@ -381,6 +450,10 @@ public class ElasticsearchTemplateFacetTests {
Term term = facet.getTerms().get(0);
assertThat(term.getTerm(), is(ARTUR_KONCZAK));
assertThat(term.getCount(), is(2));
assertThat(facet.getTotal(), is(6l));
assertThat(facet.getOther(), is(4l));
assertThat(facet.getMissing(), is(0l));
}
@Test
@@ -398,6 +471,10 @@ public class ElasticsearchTemplateFacetTests {
TermResult facet = (TermResult) result.getFacet(facetName);
assertThat(facet.getTerms().size(), is(4));
assertThat(facet.getTotal(), is(6l));
assertThat(facet.getOther(), is(0l));
assertThat(facet.getMissing(), is(0l));
}
@@ -18,12 +18,21 @@ package org.springframework.data.elasticsearch.entities;
import java.util.Date;
import java.util.List;
import lombok.*;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
/**
* @author Mohsin Husen
* @author Artur Konczak
*/
@Setter
@Getter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@Document(indexName = "test-product-index", type = "test-product-type", indexStoreType = "memory", shards = 1, replicas = 0, refreshInterval = "-1")
public class Product {
@@ -42,6 +51,7 @@ public class Product {
private Float weight;
@Field(type = FieldType.Float)
private Float price;
private Integer popularity;
@@ -52,93 +62,6 @@ public class Product {
private Date lastModified;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public List<String> getTitle() {
return title;
}
public void setTitle(List<String> title) {
this.title = title;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public List<String> getCategories() {
return categories;
}
public void setCategories(List<String> categories) {
this.categories = categories;
}
public Float getWeight() {
return weight;
}
public void setWeight(Float weight) {
this.weight = weight;
}
public Float getPrice() {
return price;
}
public void setPrice(Float price) {
this.price = price;
}
public Integer getPopularity() {
return popularity;
}
public void setPopularity(Integer popularity) {
this.popularity = popularity;
}
public boolean isAvailable() {
return available;
}
public void setAvailable(boolean available) {
this.available = available;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getLocation() {
return location;
}
public void setLocation(String location) {
this.location = location;
}
public Date getLastModified() {
return lastModified;
}
public void setLastModified(Date lastModified) {
this.lastModified = lastModified;
}
@Override
public int hashCode() {
@@ -166,12 +89,4 @@ public class Product {
}
return true;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
@@ -0,0 +1,52 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.entities;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Mapping;
import org.springframework.data.elasticsearch.annotations.Setting;
/**
* Sample DynamicSettingAndMappingEntity for test out dynamic setting using @Setting Annotation
*
* @author Mohsin Husen
*/
@Document(indexName = "synonym-index", type = "synonym-type")
@Setting(settingPath = "/synonyms/settings.json")
@Mapping(mappingPath = "/synonyms/mappings.json")
public class SynonymEntity {
@Id
private String id;
private String text;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
@@ -19,8 +19,10 @@ import static org.apache.commons.lang.RandomStringUtils.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Stream;
import org.junit.Before;
import org.junit.Test;
@@ -120,7 +122,7 @@ public class CustomMethodRepositoryTests {
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setType("test");
sampleEntity.setRate(10);
sampleEntity.setRate(9);
sampleEntity.setMessage("some message");
repository.save(sampleEntity);
@@ -641,6 +643,22 @@ public class CustomMethodRepositoryTests {
assertThat(page.getTotalElements(), is(equalTo(1L)));
}
/*
DATAES-165
*/
@Test
public void shouldAllowReturningJava8StreamInCustomQuery() {
// given
List<SampleEntity> entities = createSampleEntities("abc", 30);
repository.save(entities);
// when
Stream<SampleEntity> stream = repository.findByType("abc");
// then
assertThat(stream, is(notNullValue()));
assertThat(stream.count(), is(equalTo(30L)));
}
/*
DATAES-106
*/
@@ -735,7 +753,7 @@ public class CustomMethodRepositoryTests {
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setType("test");
sampleEntity.setRate(10);
sampleEntity.setRate(9);
sampleEntity.setMessage("some message");
repository.save(sampleEntity);
@@ -1174,5 +1192,18 @@ public class CustomMethodRepositoryTests {
// then
assertThat(count, is(equalTo(1L)));
}
private List<SampleEntity> createSampleEntities(String type, int numberOfEntities) {
List<SampleEntity> entities = new ArrayList<SampleEntity>();
for (int i = 0; i < numberOfEntities; i++) {
SampleEntity entity = new SampleEntity();
entity.setId(randomNumeric(numberOfEntities));
entity.setAvailable(true);
entity.setMessage("Message");
entity.setType(type);
entities.add(entity);
}
return entities;
}
}
@@ -16,6 +16,7 @@
package org.springframework.data.elasticsearch.repositories.custom;
import java.util.List;
import java.util.stream.Stream;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
@@ -87,6 +88,8 @@ public interface SampleCustomMethodRepository extends ElasticsearchRepository<Sa
Page<SampleEntity> findByLocationNear(GeoPoint point, String distance, Pageable pageable);
Stream<SampleEntity> findByType(String type);
long countByType(String type);
long countByTypeNot(String type);
@@ -0,0 +1,43 @@
package org.springframework.data.elasticsearch.repositories.query;
import java.util.List;
import org.springframework.data.elasticsearch.entities.Product;
import org.springframework.data.repository.PagingAndSortingRepository;
/**
* Created by akonczak on 04/09/15.
*/
public interface ProductRepository extends PagingAndSortingRepository<Product, String> {
public List<Product> findByNameAndText(String name, String text);
public List<Product> findByNameAndPrice(String name, Float price);
public List<Product> findByNameOrText(String name, String text);
public List<Product> findByNameOrPrice(String name, Float price);
public List<Product> findByAvailableTrue();
public List<Product> findByAvailableFalse();
public List<Product> findByPriceIn(List<Float> floats);
public List<Product> findByPriceNotIn(List<Float> floats);
public List<Product> findByPriceNot(float v);
public List<Product> findByPriceBetween(float v, float v1);
public List<Product> findByPriceLessThan(float v);
public List<Product> findByPriceLessThanEqual(float v);
public List<Product> findByPriceGreaterThan(float v);
public List<Product> findByPriceGreaterThanEqual(float v);
public List<Product> findByIdNotIn(List<String> strings);
}
@@ -15,6 +15,8 @@
*/
package org.springframework.data.elasticsearch.repositories.sample;
import java.util.List;
import org.springframework.data.elasticsearch.entities.SampleEntity;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
@@ -24,4 +26,9 @@ import org.springframework.data.elasticsearch.repository.ElasticsearchRepository
*/
public interface SampleElasticsearchRepository extends ElasticsearchRepository<SampleEntity, String> {
long deleteById(String id);
List<SampleEntity> deleteByAvailable(boolean available);
List<SampleEntity> deleteByMessage(String message);
void deleteByType(String type);
}
@@ -0,0 +1,28 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.repositories.synonym;
import org.springframework.data.elasticsearch.entities.SynonymEntity;
import org.springframework.data.elasticsearch.repository.ElasticsearchCrudRepository;
/**
* SynonymRepository
*
* @author Artur Konczak
*/
public interface SynonymRepository extends ElasticsearchCrudRepository<SynonymEntity, String> {
}
@@ -0,0 +1,77 @@
/*
* Copyright 2014 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.data.elasticsearch.repositories.synonym;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
import java.util.List;
import org.elasticsearch.index.query.QueryBuilders;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
import org.springframework.data.elasticsearch.entities.SynonymEntity;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* SynonymRepositoryTests
*
* @author Artur Konczak
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:synonym-test.xml")
public class SynonymRepositoryTests {
@Autowired
private SynonymRepository repository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Before
public void before() {
elasticsearchTemplate.deleteIndex(SynonymEntity.class);
elasticsearchTemplate.createIndex(SynonymEntity.class);
elasticsearchTemplate.putMapping(SynonymEntity.class);
elasticsearchTemplate.refresh(SynonymEntity.class, true);
}
@Test
public void shouldDo() {
//given
SynonymEntity entry1 = new SynonymEntity();
entry1.setText("Elizabeth is the English queen");
SynonymEntity entry2 = new SynonymEntity();
entry2.setText("Other text");
repository.save(entry1);
repository.save(entry2);
//when
//then
assertThat(repository.count(),is(2L));
List<SynonymEntity> synonymEntities = elasticsearchTemplate.queryForList(new NativeSearchQueryBuilder().withQuery(QueryBuilders.termQuery("text", "british")).build(), SynonymEntity.class);
assertThat(synonymEntities.size(), is(1));
}
}
@@ -0,0 +1,129 @@
package org.springframework.data.elasticsearch.repository.support;
import static org.hamcrest.core.Is.*;
import static org.junit.Assert.*;
import java.util.Arrays;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.entities.Product;
import org.springframework.data.elasticsearch.repositories.query.ProductRepository;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
/**
* @author Artur Konczak
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/repository-query-support.xml")
public class QueryKeywordsTest {
@Autowired
private ProductRepository repository;
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Before
public void before() {
elasticsearchTemplate.deleteIndex(Product.class);
elasticsearchTemplate.createIndex(Product.class);
elasticsearchTemplate.putMapping(Product.class);
elasticsearchTemplate.refresh(Product.class, true);
repository.save(Arrays.asList(
Product.builder().id("1").name("Sugar").text("Cane sugar").price(1.0f).available(false).build()
, Product.builder().id("2").name("Sugar").text("Cane sugar").price(1.2f).available(true).build()
, Product.builder().id("3").name("Sugar").text("Beet sugar").price(1.1f).available(true).build()
, Product.builder().id("4").name("Salt").text("Rock salt").price(1.9f).available(true).build()
, Product.builder().id("5").name("Salt").text("Sea salt").price(2.1f).available(false).build()));
elasticsearchTemplate.refresh(Product.class, true);
}
@Test
public void shouldSupportAND() {
//given
//when
//then
assertThat(repository.findByNameAndText("Sugar", "Cane sugar").size(), is(2));
assertThat(repository.findByNameAndPrice("Sugar", 1.1f).size(), is(1));
}
@Test
public void shouldSupportOR() {
//given
//when
//then
assertThat(repository.findByNameOrPrice("Sugar", 1.9f).size(), is(4));
assertThat(repository.findByNameOrText("Salt", "Beet sugar").size(), is(3));
}
@Test
public void shouldSupportTrueAndFalse() {
//given
//when
//then
assertThat(repository.findByAvailableTrue().size(), is(3));
assertThat(repository.findByAvailableFalse().size(), is(2));
}
@Test
public void shouldSupportInAndNotInAndNot() {
//given
//when
//then
assertThat(repository.findByPriceIn(Arrays.asList(1.2f, 1.1f)).size(), is(2));
assertThat(repository.findByPriceNotIn(Arrays.asList(1.2f, 1.1f)).size(), is(3));
assertThat(repository.findByPriceNot(1.2f).size(), is(4));
}
/*
DATAES-171
*/
@Test
public void shouldWorkWithNotIn() {
//given
//when
//then
assertThat(repository.findByIdNotIn(Arrays.asList("2", "3")).size(), is(3));
}
@Test
public void shouldSupportBetween() {
//given
//when
//then
assertThat(repository.findByPriceBetween(1.0f, 2.0f).size(), is(4));
}
@Test
public void shouldSupportLessThanAndGreaterThan() {
//given
//when
//then
assertThat(repository.findByPriceLessThan(1.1f).size(), is(1));
assertThat(repository.findByPriceLessThanEqual(1.1f).size(), is(2));
assertThat(repository.findByPriceGreaterThan(1.9f).size(), is(1));
assertThat(repository.findByPriceGreaterThanEqual(1.9f).size(), is(2));
}
}
@@ -299,6 +299,118 @@ public class SimpleElasticsearchRepositoryTests {
assertThat(sampleEntities.getTotalElements(), equalTo(0L));
}
@Test
public void shouldDeleteById() {
// given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
sampleEntity.setVersion(System.currentTimeMillis());
repository.save(sampleEntity);
// when
long result = repository.deleteById(documentId);
// then
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(termQuery("id", documentId)).build();
Page<SampleEntity> sampleEntities = repository.search(searchQuery);
assertThat(sampleEntities.getTotalElements(), equalTo(0L));
assertThat(result, equalTo(1L));
}
@Test
public void shouldDeleteByMessageAndReturnList() {
// given
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("hello world 1");
sampleEntity1.setAvailable(true);
sampleEntity1.setVersion(System.currentTimeMillis());
documentId = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId);
sampleEntity2.setMessage("hello world 2");
sampleEntity2.setAvailable(true);
sampleEntity2.setVersion(System.currentTimeMillis());
documentId = randomNumeric(5);
SampleEntity sampleEntity3 = new SampleEntity();
sampleEntity3.setId(documentId);
sampleEntity3.setMessage("hello world 3");
sampleEntity3.setAvailable(false);
sampleEntity3.setVersion(System.currentTimeMillis());
repository.save(Arrays.asList(sampleEntity1, sampleEntity2, sampleEntity3));
// when
List<SampleEntity> result = repository.deleteByAvailable(true);
// then
assertThat(result.size(), equalTo(2));
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
Page<SampleEntity> sampleEntities = repository.search(searchQuery);
assertThat(sampleEntities.getTotalElements(), equalTo(1L));
}
@Test
public void shouldDeleteByListForMessage() {
// given
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("hello world 1");
sampleEntity1.setVersion(System.currentTimeMillis());
documentId = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId);
sampleEntity2.setMessage("hello world 2");
sampleEntity2.setVersion(System.currentTimeMillis());
documentId = randomNumeric(5);
SampleEntity sampleEntity3 = new SampleEntity();
sampleEntity3.setId(documentId);
sampleEntity3.setMessage("hello world 3");
sampleEntity3.setVersion(System.currentTimeMillis());
repository.save(Arrays.asList(sampleEntity1, sampleEntity2, sampleEntity3));
// when
List<SampleEntity> result = repository.deleteByMessage("hello world 3");
// then
assertThat(result.size(), equalTo(1));
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
Page<SampleEntity> sampleEntities = repository.search(searchQuery);
assertThat(sampleEntities.getTotalElements(), equalTo(2L));
}
@Test
public void shouldDeleteByType() {
// given
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setType("book");
sampleEntity1.setVersion(System.currentTimeMillis());
documentId = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId);
sampleEntity2.setType("article");
sampleEntity2.setVersion(System.currentTimeMillis());
documentId = randomNumeric(5);
SampleEntity sampleEntity3 = new SampleEntity();
sampleEntity3.setId(documentId);
sampleEntity3.setType("image");
sampleEntity3.setVersion(System.currentTimeMillis());
repository.save(Arrays.asList(sampleEntity1, sampleEntity2, sampleEntity3));
// when
repository.deleteByType("article");
// then
SearchQuery searchQuery = new NativeSearchQueryBuilder().withQuery(matchAllQuery()).build();
Page<SampleEntity> sampleEntities = repository.search(searchQuery);
assertThat(sampleEntities.getTotalElements(), equalTo(2L));
}
@Test
public void shouldDeleteEntity() {
// given
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<import resource="infrastructure.xml"/>
<bean name="elasticsearchTemplate"
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client"/>
</bean>
<elasticsearch:repositories base-package="org.springframework.data.elasticsearch.repositories.query"/>
</beans>
+18
View File
@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:elasticsearch="http://www.springframework.org/schema/data/elasticsearch"
xsi:schemaLocation="http://www.springframework.org/schema/data/elasticsearch http://www.springframework.org/schema/data/elasticsearch/spring-elasticsearch-1.0.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd">
<import resource="infrastructure.xml"/>
<bean name="elasticsearchTemplate"
class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client"/>
</bean>
<elasticsearch:repositories
base-package="org.springframework.data.elasticsearch.repositories.synonym"/>
</beans>
+13
View File
@@ -0,0 +1,13 @@
{
"synonym-type": {
"_all": {
"enabled": true
},
"properties": {
"text": {
"type": "string",
"analyzer": "synonym_analyzer"
}
}
}
}
@@ -0,0 +1,23 @@
{
"index": {
"number_of_shards": "1",
"number_of_replicas": "0",
"analysis": {
"analyzer": {
"synonym_analyzer": {
"tokenizer": "whitespace",
"filter": [
"synonym_filter"
]
}
},
"filter": {
"synonym_filter": {
"type": "synonym",
"synonyms_path": "synonyms.txt",
"ignore_case": "true"
}
}
}
}
}
+26
View File
@@ -0,0 +1,26 @@
{
"index": {
"number_of_shards": "1",
"number_of_replicas": "0",
"analysis": {
"analyzer": {
"synonym_analyzer": {
"tokenizer": "whitespace",
"filter": [
"synonym_filter"
]
}
},
"filter": {
"synonym_filter": {
"type": "synonym",
"synonyms": [
"british,english",
"queen,monarch"
],
"ignore_case": "true"
}
}
}
}
}
+3
View File
@@ -0,0 +1,3 @@
british,english
queen,monarch
+1 -1
View File
@@ -12,7 +12,7 @@ Import-Template:
org.apache.commons.lang.*;version="${commonslang:[=.=.=,+1.0.0)}",
com.fasterxml.jackson.*;version="${jackson:[=.=.=,+1.0.0)}";resolution:=optional,
org.elasticsearch.*;version="${elasticsearch:[=.=.=,+1.4.4)}",
org.apache.lucene.*;version="4.10.3",
org.apache.lucene.*;version="4.10.4",
org.joda.time.*;version="${jodatime:[=.=.=,+1.0.0)}",
org.slf4j.*;version="${slf4j:[=.=.=,+1.0.0)}",
org.springframework.*;version="${spring:[=.=.=.=,+1.0.0)}",