Compare commits
43 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 552a2dd834 | |||
| e7cd8dc346 | |||
| 565c420834 | |||
| b6c9a79df2 | |||
| b4c5ec6a23 | |||
| a05507c505 | |||
| 0273d593a3 | |||
| 33707d1228 | |||
| 3fe4f15828 | |||
| 1c1b124d6e | |||
| 11e2d11b5b | |||
| 7db077c2c6 | |||
| e6d698e250 | |||
| 6a6c44401d | |||
| 7f4ee37be3 | |||
| bc8b5b8bd8 | |||
| 6cdc765b24 | |||
| f9e0b3a4f9 | |||
| 52fec26a1d | |||
| eadf51ec27 | |||
| af3121a165 | |||
| 9b28ca805b | |||
| 9d8bc61401 | |||
| ae1a873705 | |||
| 9524b2cc8d | |||
| d83a6541aa | |||
| fdc62dd7d6 | |||
| 416daef2f9 | |||
| 576495932e | |||
| c9ffc4417a | |||
| e80ddd249f | |||
| 9a8c04c16f | |||
| d117f6f515 | |||
| 3e1099740b | |||
| 763e61c862 | |||
| ea02e99263 | |||
| a3828c6161 | |||
| 4a90020dc1 | |||
| 01a67eef05 | |||
| 0825f15ec3 | |||
| 7aaf7e1782 | |||
| 455df72923 | |||
| cee493a6c7 |
@@ -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>
|
||||
|
||||
|
||||
+56
-12
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+71
-5
@@ -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
|
||||
*
|
||||
|
||||
+172
-19
@@ -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()};
|
||||
|
||||
+1
-1
@@ -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) {
|
||||
|
||||
+20
-1
@@ -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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+8
@@ -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
|
||||
|
||||
/**
|
||||
|
||||
+36
-1
@@ -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();
|
||||
}
|
||||
|
||||
+6
-3
@@ -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();
|
||||
|
||||
+12
-23
@@ -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) {
|
||||
|
||||
+1
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+7
-25
@@ -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);
|
||||
|
||||
@@ -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,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").
|
||||
|
||||
+24
-15
@@ -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>
|
||||
|
||||
+224
-11
@@ -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++) {
|
||||
|
||||
+77
@@ -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;
|
||||
}
|
||||
}
|
||||
+33
-2
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
@@ -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);
|
||||
|
||||
+43
@@ -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);
|
||||
}
|
||||
+7
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
+28
@@ -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> {
|
||||
|
||||
}
|
||||
+77
@@ -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));
|
||||
}
|
||||
|
||||
}
|
||||
+129
@@ -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));
|
||||
}
|
||||
}
|
||||
+112
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
british,english
|
||||
queen,monarch
|
||||
|
||||
+1
-1
@@ -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)}",
|
||||
|
||||
Reference in New Issue
Block a user