Adding missing files

This commit is contained in:
Rizwan Idrees 2013-01-24 17:37:03 +00:00
parent 05de948d20
commit 54a1f186d7
66 changed files with 5243 additions and 3 deletions

5
.gitignore vendored
View File

@ -1,7 +1,6 @@
atlassian-ide-plugin.xml
.svn/
data/
.svn
spring-data-elasticsearch.iml
spring-data-elasticsearch.ipr
spring-data-elasticsearch.iws
target/
target

View File

@ -0,0 +1,31 @@
package org.springframework.data.elasticsearch;
import java.util.Map;
public class ElasticsearchException extends RuntimeException{
private Map<String, String> failedDocuments;
public ElasticsearchException(String message) {
super(message);
}
public ElasticsearchException(String message, Throwable cause) {
super(message, cause);
}
public ElasticsearchException(String message, Throwable cause, Map<String, String> failedDocuments) {
super(message, cause);
this.failedDocuments = failedDocuments;
}
public ElasticsearchException(String message, Map<String, String> failedDocuments) {
super(message);
this.failedDocuments = failedDocuments;
}
public Map<String, String> getFailedDocuments() {
return failedDocuments;
}
}

View File

@ -0,0 +1,16 @@
package org.springframework.data.elasticsearch.annotations;
import org.springframework.data.annotation.Persistent;
import java.lang.annotation.*;
@Persistent
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE })
public @interface Document {
String indexName() default "";
String type() default "";
}

View File

@ -0,0 +1,25 @@
package org.springframework.data.elasticsearch.annotations;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface Query {
/**
* Elasticsearch query to be used when executing query. May contain placeholders eg. ?0
*
* @return
*/
String value() default "";
/**
* Named Query Named looked up by repository.
*
* @return
*/
String name() default "";
}

View File

@ -0,0 +1,45 @@
package org.springframework.data.elasticsearch.client;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.node.NodeClient;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
public class NodeClientFactoryBean implements FactoryBean<NodeClient>, InitializingBean{
private boolean local;
private NodeClient nodeClient;
NodeClientFactoryBean() {
}
public NodeClientFactoryBean(boolean local) {
this.local = local;
}
@Override
public NodeClient getObject() throws Exception {
return nodeClient;
}
@Override
public Class<? extends Client> getObjectType() {
return NodeClient.class;
}
@Override
public boolean isSingleton() {
return true;
}
@Override
public void afterPropertiesSet() throws Exception {
nodeClient = (NodeClient) nodeBuilder().local(this.local).node().client();
}
public void setLocal(boolean local) {
this.local = local;
}
}

View File

@ -0,0 +1,89 @@
package org.springframework.data.elasticsearch.client;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
import java.util.Properties;
import static org.apache.commons.lang.StringUtils.substringAfter;
import static org.apache.commons.lang.StringUtils.substringBefore;
import static org.elasticsearch.common.settings.ImmutableSettings.settingsBuilder;
public class TransportClientFactoryBean implements FactoryBean<TransportClient>, InitializingBean, DisposableBean {
private static final Logger logger = LoggerFactory.getLogger(TransportClientFactoryBean.class);
private String[] clusterNodes;
private TransportClient client;
private Properties properties;
static final String COLON = ":";
@Override
public void destroy() throws Exception {
try {
logger.info("Closing elasticSearch client");
if (client != null) {
client.close();
}
} catch (final Exception e) {
logger.error("Error closing ElasticSearch client: ", e);
}
}
@Override
public TransportClient getObject() throws Exception {
return client;
}
@Override
public Class<TransportClient> getObjectType() {
return TransportClient.class;
}
@Override
public boolean isSingleton() {
return false;
}
@Override
public void afterPropertiesSet() throws Exception {
buildClient();
}
protected void buildClient() throws Exception {
client = new TransportClient(settings());
Assert.notEmpty(clusterNodes,"[Assertion failed] clusterNodes settings missing.");
for (String clusterNode : clusterNodes) {
String hostName = substringBefore(clusterNode, COLON);
String port = substringAfter(clusterNode, COLON);
Assert.hasText(hostName,"[Assertion failed] missing host name in 'clusterNodes'");
Assert.hasText(port,"[Assertion failed] missing port in 'clusterNodes'");
logger.info("adding transport node : " + clusterNode);
client.addTransportAddress(new InetSocketTransportAddress(hostName, Integer.valueOf(port)));
}
client.connectedNodes();
}
private Settings settings(){
if(properties != null){
return settingsBuilder().put(properties).build();
}
return settingsBuilder()
.put("client.transport.sniff",true).build();
}
public void setClusterNodes(String[] clusterNodes) {
this.clusterNodes = clusterNodes;
}
public void setProperties(Properties properties) {
this.properties = properties;
}
}

View File

@ -0,0 +1,20 @@
package org.springframework.data.elasticsearch.config;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
import org.springframework.data.elasticsearch.repository.config.ElasticsearchRepositoryConfigExtension;
import org.springframework.data.repository.config.RepositoryBeanDefinitionParser;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
public class ElasticsearchNamespaceHandler extends NamespaceHandlerSupport{
@Override
public void init() {
RepositoryConfigurationExtension extension = new ElasticsearchRepositoryConfigExtension();
RepositoryBeanDefinitionParser parser = new RepositoryBeanDefinitionParser(extension);
registerBeanDefinitionParser("repositories", parser);
registerBeanDefinitionParser("node-client", new NodeClientBeanDefinitionParser());
registerBeanDefinitionParser("transport-client", new TransportClientBeanDefinitionParser());
}
}

View File

@ -0,0 +1,31 @@
package org.springframework.data.elasticsearch.config;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.elasticsearch.client.NodeClientFactoryBean;
import org.w3c.dom.Element;
public class NodeClientBeanDefinitionParser extends AbstractBeanDefinitionParser {
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(NodeClientFactoryBean.class);
setLocalSettings(element,builder);
return getSourcedBeanDefinition(builder, element, parserContext);
}
private void setLocalSettings(Element element, BeanDefinitionBuilder builder) {
builder.addPropertyValue("local", Boolean.valueOf(element.getAttribute("local")));
}
private AbstractBeanDefinition getSourcedBeanDefinition(BeanDefinitionBuilder builder, Element source,
ParserContext context) {
AbstractBeanDefinition definition = builder.getBeanDefinition();
definition.setSource(context.extractSource(source));
return definition;
}
}

View File

@ -0,0 +1,34 @@
package org.springframework.data.elasticsearch.config;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.springframework.data.elasticsearch.client.TransportClientFactoryBean;
import org.w3c.dom.Element;
import static org.apache.commons.lang.StringUtils.split;
public class TransportClientBeanDefinitionParser extends AbstractBeanDefinitionParser {
private static final String SEPARATOR_CHARS = ",";
@Override
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(TransportClientFactoryBean.class);
setClusterNodes(element, builder);
return getSourcedBeanDefinition(builder,element, parserContext);
}
private void setClusterNodes(Element element, BeanDefinitionBuilder builder){
builder.addPropertyValue("clusterNodes", split(element.getAttribute("cluster-nodes"), SEPARATOR_CHARS));
}
private AbstractBeanDefinition getSourcedBeanDefinition(BeanDefinitionBuilder builder, Element source,
ParserContext context) {
AbstractBeanDefinition definition = builder.getBeanDefinition();
definition.setSource(context.extractSource(source));
return definition;
}
}

View File

@ -0,0 +1,123 @@
/*
* Copyright 2012 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.core;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.BoostableQueryBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.util.Assert;
import java.util.Iterator;
import java.util.ListIterator;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.springframework.data.elasticsearch.core.query.Criteria.OperationKey;
class CriteriaQueryProcessor {
QueryBuilder createQueryFromCriteria(Criteria criteria) {
BoolQueryBuilder query = boolQuery();
ListIterator<Criteria> chainIterator = criteria.getCriteriaChain().listIterator();
while (chainIterator.hasNext()) {
Criteria chainedCriteria = chainIterator.next();
if(chainedCriteria.isOr()){
query.should(createQueryFragmentForCriteria(chainedCriteria));
}else if(chainedCriteria.isNegating()){
query.mustNot(createQueryFragmentForCriteria(chainedCriteria));
}else{
query.must(createQueryFragmentForCriteria(chainedCriteria));
}
}
return query;
}
private QueryBuilder createQueryFragmentForCriteria(Criteria chainedCriteria) {
Iterator<Criteria.CriteriaEntry> it = chainedCriteria.getCriteriaEntries().iterator();
boolean singeEntryCriteria = (chainedCriteria.getCriteriaEntries().size() == 1);
String fieldName = chainedCriteria.getField().getName();
Assert.notNull(fieldName,"Unknown field");
QueryBuilder query = null;
if(singeEntryCriteria){
Criteria.CriteriaEntry entry = it.next();
query = processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName);
}else{
query = boolQuery();
while (it.hasNext()){
Criteria.CriteriaEntry entry = it.next();
((BoolQueryBuilder)query).must(processCriteriaEntry(entry.getKey(), entry.getValue(), fieldName));
}
}
addBoost(query, chainedCriteria.getBoost());
return query;
}
private QueryBuilder processCriteriaEntry(OperationKey key, Object value, String fieldName) {
if (value == null) {
return null;
}
QueryBuilder query = null;
switch (key){
case EQUALS:
query = fieldQuery(fieldName, value); break;
case CONTAINS:
query = fieldQuery(fieldName,"*" + value + "*").analyzeWildcard(true); break;
case STARTS_WITH:
query = fieldQuery(fieldName,value +"*").analyzeWildcard(true); break;
case ENDS_WITH:
query = fieldQuery(fieldName, "*"+value).analyzeWildcard(true); break;
case EXPRESSION:
query = queryString((String)value).field(fieldName); break;
case BETWEEN:
Object[] ranges = (Object[]) value;
query = rangeQuery(fieldName).from(ranges[0]).to(ranges[1]); break;
case FUZZY:
query = fuzzyQuery(fieldName, (String) value); break;
}
return query;
}
private QueryBuilder buildNegationQuery(String fieldName, Iterator<Criteria.CriteriaEntry> it){
BoolQueryBuilder notQuery = boolQuery();
while (it.hasNext()){
notQuery.mustNot(fieldQuery(fieldName, it.next().getValue()));
}
return notQuery;
}
private void addBoost(QueryBuilder query, float boost){
if(Float.isNaN(boost)){
return;
}
if(query instanceof BoostableQueryBuilder){
((BoostableQueryBuilder)query).boost(boost);
}
}
}

View File

@ -0,0 +1,148 @@
package org.springframework.data.elasticsearch.core;
import org.elasticsearch.action.bulk.BulkResponse;
import org.springframework.data.domain.Page;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.query.*;
import java.util.List;
public interface ElasticsearchOperations {
/**
* @return Converter in use
*/
ElasticsearchConverter getElasticsearchConverter();
/**
* Create an index
* @param clazz
* @param <T>
*/
<T> boolean createIndex(Class<T> clazz);
/**
* Execute the query against elasticsearch and return the first returned object
*
* @param query
* @param clazz
* @return the first matching object
*/
<T> T queryForObject(GetQuery query, Class<T> clazz);
/**
* Execute the query against elasticsearch and return the first returned object
*
* @param query
* @param clazz
* @return the first matching object
*/
<T> T queryForObject(CriteriaQuery query, Class<T> clazz);
/**
* Execute the query against elasticsearch and return the first returned object
*
* @param query
* @param clazz
* @return the first matching object
*/
<T> T queryForObject(StringQuery query, Class<T> clazz);
/**
* Execute the query against elasticsearch and return result as {@link Page}
*
* @param query
* @param clazz
* @return
*/
<T> Page<T> queryForPage(SearchQuery query, Class<T> clazz);
/**
* Execute the query against elasticsearch and return result as {@link Page}
*
* @param query
* @param clazz
* @return
*/
<T> Page<T> queryForPage(CriteriaQuery query, Class<T> clazz);
/**
* Execute the query against elasticsearch and return result as {@link Page}
*
* @param query
* @param clazz
* @return
*/
<T> Page<T> queryForPage(StringQuery query, Class<T> clazz);
/**
* return number of elements found by for given query
*
* @param query
* @param clazz
* @return
*/
<T> long count(SearchQuery query, Class<T> clazz);
/**
* Index an object. Will do save or update
*
* @param query
* @return returns the document id
*/
String index(IndexQuery query);
/**
* Bulk index all objects. Will do save or update
*
* @param queries
*/
void bulkIndex(List<IndexQuery> queries);
/**
* Delete the one object with provided id
*
* @param indexName
* @param type
* @param id
* @return documentId of the document deleted
*/
String delete(String indexName, String type, String id);
/**
* Delete the one object with provided id
*
* @param clazz
* @param id
* @return documentId of the document deleted
*/
<T> String delete(Class<T> clazz, String id);
/**
* Delete all records matching the query
* @param clazz
* @param query
*/
<T> void delete(DeleteQuery query, Class<T> clazz);
/**
* refresh the index
* @param indexName
* @param waitForOperation
*/
void refresh(String indexName,boolean waitForOperation);
/**
* refresh the index
* @param clazz
* @param waitForOperation
*/
<T> void refresh(Class<T> clazz,boolean waitForOperation);
}

View File

@ -0,0 +1,267 @@
package org.springframework.data.elasticsearch.core;
import org.codehaus.jackson.map.DeserializationConfig;
import org.codehaus.jackson.map.ObjectMapper;
import org.elasticsearch.action.bulk.BulkItemResponse;
import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.count.CountRequestBuilder;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequestBuilder;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.Client;
import org.elasticsearch.client.Requests;
import org.elasticsearch.common.collect.MapBuilder;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.ElasticsearchException;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.util.Assert;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import static org.apache.commons.lang.StringUtils.isBlank;
import static org.elasticsearch.action.search.SearchType.DFS_QUERY_THEN_FETCH;
import static org.elasticsearch.client.Requests.indicesExistsRequest;
import static org.elasticsearch.client.Requests.refreshRequest;
public class ElasticsearchTemplate implements ElasticsearchOperations {
private Client client;
private ElasticsearchConverter elasticsearchConverter;
private ObjectMapper objectMapper = new ObjectMapper();
{
objectMapper.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
public ElasticsearchTemplate(Client client) {
this(client, null);
}
public ElasticsearchTemplate(Client client, ElasticsearchConverter elasticsearchConverter) {
this.client = client;
this.elasticsearchConverter = (elasticsearchConverter == null)? new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext()) : elasticsearchConverter ;
}
@Override
public <T> boolean createIndex(Class<T> clazz) {
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
return createIndexIfNotCreated(persistentEntity.getIndexName());
}
@Override
public ElasticsearchConverter getElasticsearchConverter() {
return elasticsearchConverter;
}
@Override
public <T> T queryForObject(GetQuery query, Class<T> clazz) {
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
GetResponse response = client.prepareGet(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId())
.execute().actionGet();
return mapResult(response.getSourceAsString(), clazz);
}
@Override
public <T> T queryForObject(CriteriaQuery query, Class<T> clazz) {
Page<T> page = queryForPage(query,clazz);
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found "+ page.getTotalElements() +" results");
return page.getTotalElements() > 0? page.getContent().get(0) : null;
}
@Override
public <T> T queryForObject(StringQuery query, Class<T> clazz) {
Page<T> page = queryForPage(query,clazz);
Assert.isTrue(page.getTotalElements() < 2, "Expected 1 but found "+ page.getTotalElements() +" results");
return page.getTotalElements() > 0? page.getContent().get(0) : null;
}
@Override
public <T> Page<T> queryForPage(SearchQuery query, Class<T> clazz) {
SearchRequestBuilder searchRequestBuilder = prepareSearch(query,clazz);
if(query.getElasticsearchFilter() != null){
searchRequestBuilder.setFilter(query.getElasticsearchFilter());
}
SearchResponse response = searchRequestBuilder.setQuery(query.getElasticsearchQuery()).execute().actionGet();
return mapResults(response, clazz, query.getPageable());
}
@Override
public <T> Page<T> queryForPage(CriteriaQuery query, Class<T> clazz) {
QueryBuilder elasticsearchQuery = new CriteriaQueryProcessor().createQueryFromCriteria(query.getCriteria());
SearchResponse response = prepareSearch(query,clazz)
.setQuery(elasticsearchQuery)
.execute().actionGet();
return mapResults(response, clazz, query.getPageable());
}
@Override
public <T> Page<T> queryForPage(StringQuery query, Class<T> clazz) {
SearchResponse response = prepareSearch(query,clazz)
.setQuery(query.getSource())
.execute().actionGet();
return mapResults(response, clazz, query.getPageable());
}
@Override
public <T> long count(SearchQuery query, Class<T> clazz) {
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
CountRequestBuilder countRequestBuilder = client.prepareCount(persistentEntity.getIndexName())
.setTypes(persistentEntity.getIndexType());
if(query.getElasticsearchQuery() != null){
countRequestBuilder.setQuery(query.getElasticsearchQuery());
}
return countRequestBuilder.execute().actionGet().count();
}
@Override
public String index(IndexQuery query) {
return prepareIndex(query)
.execute()
.actionGet().getId();
}
@Override
public void bulkIndex(List<IndexQuery> queries) {
BulkRequestBuilder bulkRequest = client.prepareBulk();
for(IndexQuery query : queries){
bulkRequest.add(prepareIndex(query));
}
BulkResponse bulkResponse = bulkRequest.execute().actionGet();
if (bulkResponse.hasFailures()) {
Map<String, String> failedDocuments = new HashMap<String, String>();
for (BulkItemResponse item : bulkResponse.items()) {
if (item.failed())
failedDocuments.put(item.getId(), item.failureMessage());
}
throw new ElasticsearchException("Bulk indexing has failures. Use ElasticsearchException.getFailedDocuments() for detailed messages [" + failedDocuments+"]", failedDocuments);
}
}
@Override
public String delete(String indexName, String type, String id) {
return client.prepareDelete(indexName, type, id)
.execute().actionGet().getId();
}
@Override
public <T> String delete(Class<T> clazz, String id) {
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
return delete(persistentEntity.getIndexName(), persistentEntity.getIndexType(), id);
}
@Override
public <T> void delete(DeleteQuery query, Class<T> clazz) {
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
client.prepareDeleteByQuery(persistentEntity.getIndexName())
.setTypes(persistentEntity.getIndexType())
.setQuery(query.getElasticsearchQuery())
.execute().actionGet();
}
private boolean createIndexIfNotCreated(String indexName) {
return indexExists(indexName) || createIndex(indexName);
}
private boolean indexExists(String indexName) {
return client.admin()
.indices()
.exists(indicesExistsRequest(indexName)).actionGet().exists();
}
private boolean createIndex(String indexName) {
return client.admin().indices().create(Requests.createIndexRequest(indexName).
settings(new MapBuilder<String, String>().put("index.refresh_interval", "-1").map())).actionGet().acknowledged();
}
private <T> SearchRequestBuilder prepareSearch(Query query, Class<T> clazz){
int startRecord=0;
if(query.getPageable() != null){
startRecord = ((query.getPageable().getPageNumber() - 1) * query.getPageable().getPageSize());
}
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(persistentEntity.getIndexName())
.setSearchType(DFS_QUERY_THEN_FETCH)
.setTypes(persistentEntity.getIndexType())
.setFrom(startRecord < 0 ? 0 : startRecord)
.setSize(query.getPageable() != null ? query.getPageable().getPageSize() : 10);
if(query.getSort() != null){
for(Sort.Order order : query.getSort()){
searchRequestBuilder.addSort(order.getProperty(), order.getDirection() == Sort.Direction.DESC? SortOrder.DESC : SortOrder.ASC);
}
}
return searchRequestBuilder;
}
private IndexRequestBuilder prepareIndex(IndexQuery query){
try {
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(query.getObject().getClass());
return client.prepareIndex(persistentEntity.getIndexName(), persistentEntity.getIndexType(), query.getId())
.setSource(objectMapper.writeValueAsString(query.getObject()));
} catch (IOException e) {
throw new ElasticsearchException("failed to index the document [id: " + query.getId() +"]",e);
}
}
public void refresh(String indexName, boolean waitForOperation) {
client.admin().indices()
.refresh(refreshRequest(indexName).waitForOperations(waitForOperation)).actionGet();
}
public <T> void refresh(Class<T> clazz, boolean waitForOperation) {
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
client.admin().indices()
.refresh(refreshRequest(persistentEntity.getIndexName()).waitForOperations(waitForOperation)).actionGet();
}
private ElasticsearchPersistentEntity getPersistentEntityFor(Class clazz){
return elasticsearchConverter.getMappingContext().getPersistentEntity(clazz);
}
private <T> Page<T> mapResults(SearchResponse response, final Class<T> elementType,final Pageable pageable){
ResultsMapper<T> resultsMapper = new ResultsMapper<T>(){
@Override
public Page<T> mapResults(SearchResponse response) {
long totalHits = response.getHits().totalHits();
List<T> results = new ArrayList<T>();
for (SearchHit hit : response.getHits()) {
if (hit != null) {
results.add(mapResult(hit.sourceAsString(), elementType));
}
}
return new PageImpl<T>(results, pageable, totalHits);
}
};
return resultsMapper.mapResults(response);
}
private <T> T mapResult(String source, Class<T> clazz){
if(isBlank(source)){
return null;
}
try {
return objectMapper.readValue(source, clazz);
} catch (IOException e) {
throw new ElasticsearchException("failed to map source [ " + source + "] to class " + clazz.getSimpleName() , e);
}
}
}

View File

@ -0,0 +1,11 @@
package org.springframework.data.elasticsearch.core;
import org.elasticsearch.action.search.SearchResponse;
import org.springframework.data.domain.Page;
public interface ResultsMapper<T> {
Page<T> mapResults(SearchResponse response);
}

View File

@ -0,0 +1,71 @@
/*
* Copyright 2012 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.core.convert;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import org.joda.time.ReadableInstant;
import org.joda.time.format.DateTimeFormatter;
import org.joda.time.format.ISODateTimeFormat;
import org.springframework.core.convert.converter.Converter;
import java.util.Date;
public final class DateTimeConverters {
private static DateTimeFormatter formatter = ISODateTimeFormat.dateTime().withZone(DateTimeZone.UTC);
public enum JodaDateTimeConverter implements Converter<ReadableInstant, String> {
INSTANCE;
@Override
public String convert(ReadableInstant source) {
if (source == null) {
return null;
}
return formatter.print(source);
}
}
public enum JodaLocalDateTimeConverter implements Converter<LocalDateTime, String> {
INSTANCE;
@Override
public String convert(LocalDateTime source) {
if (source == null) {
return null;
}
return formatter.print(source.toDateTime(DateTimeZone.UTC));
}
}
public enum JavaDateConverter implements Converter<Date, String> {
INSTANCE;
@Override
public String convert(Date source) {
if (source == null) {
return null;
}
return formatter.print(source.getTime());
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012 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.core.convert;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
public interface ElasticsearchConverter{
/**
* Returns the underlying {@link org.springframework.data.mapping.context.MappingContext} used by the converter.
*
* @return never {@literal null}
*/
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> getMappingContext();
/**
* Returns the underlying {@link org.springframework.core.convert.ConversionService} used by the converter.
*
* @return never {@literal null}.
*/
ConversionService getConversionService();
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2012 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.core.convert;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.core.convert.ConversionService;
import org.springframework.core.convert.support.DefaultConversionService;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.Assert;
public class MappingElasticsearchConverter implements ElasticsearchConverter, ApplicationContextAware{
private final MappingContext<? extends ElasticsearchPersistentEntity<?>,ElasticsearchPersistentProperty> mappingContext;
private final GenericConversionService conversionService;
@SuppressWarnings("unused")
private ApplicationContext applicationContext;
public MappingElasticsearchConverter(MappingContext<? extends ElasticsearchPersistentEntity<?>,ElasticsearchPersistentProperty> mappingContext) {
Assert.notNull(mappingContext);
this.mappingContext = mappingContext;
this.conversionService = new DefaultConversionService();
}
@Override
public MappingContext<? extends ElasticsearchPersistentEntity<?>,ElasticsearchPersistentProperty> getMappingContext() {
return mappingContext;
}
@Override
public ConversionService getConversionService() {
return this.conversionService;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}

View File

@ -0,0 +1,25 @@
/*
* Copyright 2012 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.core.mapping;
import org.springframework.data.mapping.PersistentEntity;
public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, ElasticsearchPersistentProperty> {
String getIndexName();
String getIndexType();
}

View File

@ -0,0 +1,34 @@
/*
* Copyright 2012 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.core.mapping;
import org.springframework.core.convert.converter.Converter;
import org.springframework.data.mapping.PersistentProperty;
public interface ElasticsearchPersistentProperty extends PersistentProperty<ElasticsearchPersistentProperty>{
String getFieldName();
public enum PropertyToFieldNameConverter implements Converter<ElasticsearchPersistentProperty, String> {
INSTANCE;
public String convert(ElasticsearchPersistentProperty source) {
return source.getFieldName();
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012 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.core.mapping;
import org.springframework.data.mapping.context.AbstractMappingContext;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import org.springframework.data.util.TypeInformation;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
public class SimpleElasticsearchMappingContext extends
AbstractMappingContext<SimpleElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> {
@Override
protected <T> SimpleElasticsearchPersistentEntity<?> createPersistentEntity(TypeInformation<T> typeInformation) {
return new SimpleElasticsearchPersistentEntity<T>(typeInformation);
}
@Override
protected ElasticsearchPersistentProperty createPersistentProperty(Field field, PropertyDescriptor descriptor,
SimpleElasticsearchPersistentEntity<?> owner, SimpleTypeHolder simpleTypeHolder) {
return new SimpleElasticsearchPersistentProperty(field, descriptor, owner, simpleTypeHolder);
}
}

View File

@ -0,0 +1,73 @@
/*
* Copyright 2012 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.core.mapping;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.expression.BeanFactoryAccessor;
import org.springframework.context.expression.BeanFactoryResolver;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.mapping.model.BasicPersistentEntity;
import org.springframework.data.util.TypeInformation;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.util.Assert;
import java.util.Locale;
import static org.springframework.util.StringUtils.hasText;
/**
* Elasticsearch specific {@link org.springframework.data.mapping.PersistentEntity} implementation holding
*
* @param <T>
*/
public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntity<T, ElasticsearchPersistentProperty> implements
ElasticsearchPersistentEntity<T>, ApplicationContextAware {
private final StandardEvaluationContext context;
private String indexName;
private String indexType;
public SimpleElasticsearchPersistentEntity(TypeInformation<T> typeInformation) {
super(typeInformation);
this.context = new StandardEvaluationContext();
Class<T> clazz = typeInformation.getType();
Assert.isTrue(clazz.isAnnotationPresent(Document.class),
clazz.getSimpleName() + " is not a Document. Make sure the document class is annotated with @Document(indexName=\"foo\")");
Document document = clazz.getAnnotation(Document.class);
Assert.hasText(document.indexName(), " Unknown indexName. Make sure the indexName is defined. e.g @Document(indexName=\"foo\")");
this.indexName = typeInformation.getType().getAnnotation(Document.class).indexName();
this.indexType = hasText(document.type())? document.type() : clazz.getSimpleName().toLowerCase(Locale.ENGLISH);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
context.addPropertyAccessor(new BeanFactoryAccessor());
context.setBeanResolver(new BeanFactoryResolver(applicationContext));
context.setRootObject(applicationContext);
}
@Override
public String getIndexName() {
return indexName;
}
@Override
public String getIndexType() {
return indexType;
}
}

View File

@ -0,0 +1,63 @@
/*
* Copyright 2012 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.core.mapping;
import org.springframework.data.mapping.Association;
import org.springframework.data.mapping.PersistentEntity;
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
import org.springframework.data.mapping.model.SimpleTypeHolder;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.util.HashSet;
import java.util.Set;
/**
* Elasticsearch specific {@link org.springframework.data.mapping.PersistentProperty} implementation processing
*/
public class SimpleElasticsearchPersistentProperty extends AnnotationBasedPersistentProperty<ElasticsearchPersistentProperty> implements
ElasticsearchPersistentProperty {
private static final Set<Class<?>> SUPPORTED_ID_TYPES = new HashSet<Class<?>>();
private static final Set<String> SUPPORTED_ID_PROPERTY_NAMES = new HashSet<String>();
static {
SUPPORTED_ID_TYPES.add(String.class);
SUPPORTED_ID_PROPERTY_NAMES.add("id");
SUPPORTED_ID_PROPERTY_NAMES.add("documentId");
}
public SimpleElasticsearchPersistentProperty(Field field, PropertyDescriptor propertyDescriptor,
PersistentEntity<?, ElasticsearchPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
super(field, propertyDescriptor, owner, simpleTypeHolder);
}
@Override
public String getFieldName() {
return field.getName();
}
@Override
public boolean isIdProperty() {
return super.isIdProperty() || SUPPORTED_ID_PROPERTY_NAMES.contains(getFieldName());
}
@Override
protected Association<ElasticsearchPersistentProperty> createAssociation() {
return null;
}
}

View File

@ -0,0 +1,67 @@
/*
* Copyright 2012 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.core.query;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.util.Assert;
/**
* AbstractQuery
*
*/
abstract class AbstractQuery implements Query{
private static final Pageable DEFAULT_PAGE = new PageRequest(0, DEFAULT_PAGE_SIZE);
protected Pageable pageable = DEFAULT_PAGE;
protected Sort sort;
@Override
public Sort getSort() {
return this.sort;
}
@Override
public Pageable getPageable() {
return this.pageable;
}
@Override
public final <T extends Query> T setPageable(Pageable pageable) {
Assert.notNull(pageable);
this.pageable = pageable;
return (T) this.addSort(pageable.getSort());
}
@SuppressWarnings("unchecked")
public final <T extends Query> T addSort(Sort sort) {
if (sort == null) {
return (T) this;
}
if (this.sort == null) {
this.sort = sort;
} else {
this.sort = this.sort.and(sort);
}
return (T) this;
}
}

View File

@ -0,0 +1,456 @@
/*
* Copyright 2012 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.core.query;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;
import org.apache.commons.lang.StringUtils;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.util.Assert;
/**
* Criteria is the central class when constructing queries. It follows more or less a fluent API style, which allows to
* easily chain together multiple criteria.
*
*/
public class Criteria {
public static final String WILDCARD = "*";
public static final String CRITERIA_VALUE_SEPERATOR = " ";
private static final String OR_OPERATOR = " OR ";
private static final String AND_OPERATOR = " AND ";
private Field field;
private float boost = Float.NaN;
private boolean negating = false;
private List<Criteria> criteriaChain = new ArrayList<Criteria>(1);
private Set<CriteriaEntry> criteria = new LinkedHashSet<CriteriaEntry>();
public Criteria() {
}
/**
* Creates a new CriterSimpleFieldia for the Filed with provided name
*
* @param fieldname
*/
public Criteria(String fieldname) {
this(new SimpleField(fieldname));
}
/**
* Creates a new Criteria for the given field
*
* @param field
*/
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;
}
protected Criteria(List<Criteria> criteriaChain, String fieldname) {
this(criteriaChain, new SimpleField(fieldname));
}
protected Criteria(List<Criteria> criteriaChain, Field field) {
Assert.notNull(criteriaChain, "CriteriaChain must not be null");
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.addAll(criteriaChain);
this.criteriaChain.add(this);
this.field = field;
}
/**
* Static factory method to create a new Criteria for field with given name
*
* @param field
* @return
*/
public static Criteria where(String field) {
return where(new SimpleField(field));
}
/**
* Static factory method to create a new Criteria for provided field
*
* @param field
* @return
*/
public static Criteria where(Field field) {
return new Criteria(field);
}
/**
* Chain using {@code AND}
*
* @param field
* @return
*/
public Criteria and(Field field) {
return new Criteria(this.criteriaChain, field);
}
/**
* Chain using {@code AND}
*
* @param fieldName
* @return
*/
public Criteria and(String fieldName) {
return new Criteria(this.criteriaChain, fieldName);
}
/**
* Chain using {@code AND}
*
* @param criteria
* @return
*/
public Criteria and(Criteria criteria) {
this.criteriaChain.add(criteria);
return this;
}
/**
* Chain using {@code AND}
*
* @param criterias
* @return
*/
public Criteria and(Criteria... criterias) {
this.criteriaChain.addAll(Arrays.asList(criterias));
return this;
}
/**
* Chain using {@code OR}
*
* @param field
* @return
*/
public Criteria or(Field field) {
return new OrCriteria(this.criteriaChain, field);
}
/**
* Chain using {@code OR}
*
* @param criteria
* @return
*/
public Criteria or(Criteria criteria) {
Assert.notNull(criteria, "Cannot chain 'null' criteria.");
Criteria orConnectedCritiera = new OrCriteria(this.criteriaChain, criteria.getField());
orConnectedCritiera.criteria.addAll(criteria.criteria);
return orConnectedCritiera;
}
/**
* Chain using {@code OR}
*
* @param fieldName
* @return
*/
public Criteria or(String fieldName) {
return or(new SimpleField(fieldName));
}
/**
* Crates new CriteriaEntry without any wildcards
*
* @param o
* @return
*/
public Criteria is(Object o) {
criteria.add(new CriteriaEntry(OperationKey.EQUALS, o));
return this;
}
/**
* Crates new CriteriaEntry with leading and trailing wildcards <br/>
* <strong>NOTE: </strong> mind your schema as leading wildcards may not be supported and/or execution might be slow.
*
* @param s
* @return
*/
public Criteria contains(String s) {
assertNoBlankInWildcardedQuery(s, true, true);
criteria.add(new CriteriaEntry(OperationKey.CONTAINS, s));
return this;
}
/**
* Crates new CriteriaEntry with trailing wildcard
*
* @param s
* @return
*/
public Criteria startsWith(String s) {
assertNoBlankInWildcardedQuery(s, true, false);
criteria.add(new CriteriaEntry(OperationKey.STARTS_WITH, s));
return this;
}
/**
* Crates new CriteriaEntry with leading wildcard <br />
* <strong>NOTE: </strong> mind your schema and execution times as leading wildcards may not be supported.
*
* @param s
* @return
*/
public Criteria endsWith(String s) {
assertNoBlankInWildcardedQuery(s, false, true);
criteria.add(new CriteriaEntry(OperationKey.ENDS_WITH, s));
return this;
}
/**
* Crates new CriteriaEntry with trailing -
*
* @return
*/
public Criteria not() {
this.negating = true;
return this;
}
/**
* Crates new CriteriaEntry with trailing ~
*
* @param s
* @return
*/
public Criteria fuzzy(String s) {
criteria.add(new CriteriaEntry(OperationKey.FUZZY, s));
return this;
}
/**
* Crates new CriteriaEntry allowing native solr expressions
*
* @param s
* @return
*/
public Criteria expression(String s) {
criteria.add(new CriteriaEntry(OperationKey.EXPRESSION, s));
return this;
}
/**
* Boost positive hit with given factor. eg. ^2.3
*
* @param boost
* @return
*/
public Criteria boost(float boost) {
if (boost < 0) {
throw new InvalidDataAccessApiUsageException("Boost must not be negative.");
}
this.boost = boost;
return this;
}
/**
* Crates new CriteriaEntry for {@code RANGE [lowerBound TO upperBound]}
*
* @param lowerBound
* @param upperBound
* @return
*/
public Criteria between(Object lowerBound, Object upperBound) {
if (lowerBound == null && upperBound == null) {
throw new InvalidDataAccessApiUsageException("Range [* TO *] is not allowed");
}
criteria.add(new CriteriaEntry(OperationKey.BETWEEN, new Object[] { lowerBound, upperBound }));
return this;
}
/**
* Crates new CriteriaEntry for {@code RANGE [* TO upperBound]}
*
* @param upperBound
* @return
*/
public Criteria lessThanEqual(Object upperBound) {
between(null, upperBound);
return this;
}
/**
* Crates new CriteriaEntry for {@code RANGE [lowerBound TO *]}
*
* @param lowerBound
* @return
*/
public Criteria greaterThanEqual(Object lowerBound) {
between(lowerBound, null);
return this;
}
/**
* Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)}
*
* @param values
* @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));
}
/**
* Crates new CriteriaEntry for multiple values {@code (arg0 arg1 arg2 ...)}
*
* @param values the collection containing the values to match against
* @return
*/
public Criteria in(Iterable<?> values) {
Assert.notNull(values, "Collection of 'in' values must not be null");
for (Object value : values) {
if (value instanceof Collection) {
in((Collection<?>) value);
} else {
is(value);
}
}
return this;
}
private void assertNoBlankInWildcardedQuery(String searchString, boolean leadingWildcard, boolean trailingWildcard) {
if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) {
throw new InvalidDataAccessApiUsageException("Cannot constructQuery '" + (leadingWildcard ? "*" : "") + "\""
+ searchString + "\"" + (trailingWildcard ? "*" : "") + "'. Use epxression or mulitple clauses instead.");
}
}
/**
* Field targeted by this Criteria
*
* @return
*/
public Field getField() {
return this.field;
}
public Set<CriteriaEntry> getCriteriaEntries() {
return Collections.unmodifiableSet(this.criteria);
}
/**
* Conjunction to be used with this criteria (AND | OR)
*
* @return
*/
public String getConjunctionOperator() {
return AND_OPERATOR;
}
public List<Criteria> getCriteriaChain() {
return Collections.unmodifiableList(this.criteriaChain);
}
public boolean isNegating() {
return this.negating;
}
public boolean isAnd(){
return AND_OPERATOR == getConjunctionOperator();
}
public boolean isOr(){
return OR_OPERATOR == getConjunctionOperator();
}
public float getBoost() {
return this.boost;
}
static class OrCriteria extends Criteria {
public OrCriteria() {
super();
}
public OrCriteria(Field field) {
super(field);
}
public OrCriteria(List<Criteria> criteriaChain, Field field) {
super(criteriaChain, field);
}
public OrCriteria(List<Criteria> criteriaChain, String fieldname) {
super(criteriaChain, fieldname);
}
public OrCriteria(String fieldname) {
super(fieldname);
}
@Override
public String getConjunctionOperator() {
return OR_OPERATOR;
}
}
public enum OperationKey {
EQUALS, CONTAINS, STARTS_WITH, ENDS_WITH, EXPRESSION, BETWEEN, FUZZY;
}
public static class CriteriaEntry {
private OperationKey key;
private Object value;
CriteriaEntry(OperationKey key, Object value) {
this.key = key;
this.value = value;
}
public OperationKey getKey() {
return key;
}
public Object getValue() {
return value;
}
}
}

View File

@ -0,0 +1,75 @@
/*
* Copyright 2012 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.core.query;
import org.springframework.data.domain.Pageable;
import org.springframework.util.Assert;
public class CriteriaQuery extends AbstractQuery implements Query {
private Criteria criteria;
private CriteriaQuery() {
}
public CriteriaQuery(Criteria criteria) {
this(criteria, null);
}
public CriteriaQuery(Criteria criteria, Pageable pageable) {
this.criteria = criteria;
this.pageable = pageable;
if (pageable != null) {
this.addSort(pageable.getSort());
}
}
public static final Query fromQuery(CriteriaQuery source) {
return fromQuery(source, new CriteriaQuery());
}
public static <T extends CriteriaQuery> T fromQuery(CriteriaQuery source, T destination) {
if (source == null || destination == null) {
return null;
}
if (source.getCriteria() != null) {
destination.addCriteria(source.getCriteria());
}
if (source.getSort() != null) {
destination.addSort(source.getSort());
}
return destination;
}
@SuppressWarnings("unchecked")
public final <T extends CriteriaQuery> T addCriteria(Criteria criteria) {
Assert.notNull(criteria, "Cannot add null criteria.");
if (this.criteria == null) {
this.criteria = criteria;
} else {
this.criteria.and(criteria);
}
return (T) this;
}
public Criteria getCriteria() {
return this.criteria;
}
}

View File

@ -0,0 +1,17 @@
package org.springframework.data.elasticsearch.core.query;
import org.elasticsearch.index.query.QueryBuilder;
public class DeleteQuery{
private QueryBuilder elasticsearchQuery;
public QueryBuilder getElasticsearchQuery() {
return elasticsearchQuery;
}
public void setElasticsearchQuery(QueryBuilder elasticsearchQuery) {
this.elasticsearchQuery = elasticsearchQuery;
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012 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.core.query;
/**
* Defines a Field that can be used within a Criteria.
*
*/
public interface Field {
/**
* Get the name of the field used in schema.xml of solr server
*
* @return
*/
String getName();
}

View File

@ -0,0 +1,15 @@
package org.springframework.data.elasticsearch.core.query;
public class GetQuery{
private String id;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
}

View File

@ -0,0 +1,24 @@
package org.springframework.data.elasticsearch.core.query;
public class IndexQuery{
private String id;
private Object object;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
}

View File

@ -0,0 +1,51 @@
package org.springframework.data.elasticsearch.core.query;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
public interface Query {
int DEFAULT_PAGE_SIZE = 10;
/**
* restrict result to entries on given page. Corresponds to the 'start' and 'rows' parameter in solr
*
* @param pageable
* @return
*/
<T extends Query> T setPageable(Pageable pageable);
/**
* Get filter queries if defined
*
* @return
*/
//List<FilterQuery> getFilterQueries();
/**
* Get page settings if defined
*
* @return
*/
Pageable getPageable();
/**
* Add {@link org.springframework.data.domain.Sort} to query
*
* @param sort
* @return
*/
<T extends Query> T addSort(Sort sort);
/**
* @return null if not set
*/
Sort getSort();
}

View File

@ -0,0 +1,28 @@
package org.springframework.data.elasticsearch.core.query;
import org.elasticsearch.index.query.FilterBuilder;
import org.elasticsearch.index.query.QueryBuilder;
public class SearchQuery extends AbstractQuery{
private QueryBuilder elasticsearchQuery;
private FilterBuilder elasticsearchFilter;
public QueryBuilder getElasticsearchQuery() {
return elasticsearchQuery;
}
public void setElasticsearchQuery(QueryBuilder elasticsearchQuery) {
this.elasticsearchQuery = elasticsearchQuery;
}
public FilterBuilder getElasticsearchFilter() {
return elasticsearchFilter;
}
public void setElasticsearchFilter(FilterBuilder elasticsearchFilter) {
this.elasticsearchFilter = elasticsearchFilter;
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2012 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.core.query;
/**
* The most trivial implementation of a Field
*
*/
public class SimpleField implements Field {
private final String name;
public SimpleField(String name) {
this.name = name;
}
@Override
public String getName() {
return this.name;
}
@Override
public String toString() {
return this.name;
}
}

View File

@ -0,0 +1,31 @@
package org.springframework.data.elasticsearch.core.query;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
public class StringQuery extends AbstractQuery{
private String source;
public StringQuery(String source) {
this.source = source;
}
public StringQuery(String source, Pageable pageable) {
this.source = source;
this.pageable = pageable;
}
public StringQuery(String source, Pageable pageable, Sort sort) {
this.pageable = pageable;
this.sort = sort;
this.source = source;
}
public String getSource() {
return source;
}
}

View File

@ -0,0 +1,31 @@
/*
* Copyright 2012 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.repository;
import org.springframework.data.repository.PagingAndSortingRepository;
import java.io.Serializable;
import java.util.List;
/**
* @param <T>
* @param <ID>
*/
public interface ElasticsearchCrudRepository<T, ID extends Serializable> extends PagingAndSortingRepository<T, ID> {
<S extends T> List<S> save(List<S> entities);
}

View File

@ -0,0 +1,41 @@
/*
* Copyright 2012 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.repository;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.repository.NoRepositoryBean;
import java.io.Serializable;
import java.util.List;
/**
* @param <T>
* @param <ID>
*/
@NoRepositoryBean
public interface ElasticsearchRepository<T, ID extends Serializable> extends ElasticsearchCrudRepository<T,ID> {
<S extends T> S index(S entity);
Iterable<T> search(QueryBuilder elasticsearchQuery);
Page<T> search(QueryBuilder elasticsearchQuery, Pageable pageable);
Page<T> search(SearchQuery searchQuery);
}

View File

@ -0,0 +1,56 @@
/*
* Copyright 2012 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.repository.cdi;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactory;
import org.springframework.data.repository.cdi.CdiRepositoryBean;
import org.springframework.util.Assert;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import java.lang.annotation.Annotation;
import java.util.Set;
/**
* Uses CdiRepositoryBean to create ElasticsearchRepository instances.
*
*/
public class ElasticsearchRepositoryBean<T> extends CdiRepositoryBean<T> {
private final Bean<ElasticsearchOperations> elasticsearchOperationsBean;
public ElasticsearchRepositoryBean(Bean<ElasticsearchOperations> operations, Set<Annotation> qualifiers, Class<T> repositoryType,
BeanManager beanManager) {
super(qualifiers, repositoryType, beanManager);
Assert.notNull(operations, "Cannot create repository with 'null' for ElasticsearchOperations.");
this.elasticsearchOperationsBean = operations;
}
@Override
protected T create(CreationalContext<T> creationalContext, Class<T> repositoryType) {
ElasticsearchOperations elasticsearchOperations = getDependencyInstance(elasticsearchOperationsBean, ElasticsearchOperations.class);
return new ElasticsearchRepositoryFactory(elasticsearchOperations).getRepository(repositoryType);
}
@Override
public Class<? extends Annotation> getScope() {
return elasticsearchOperationsBean.getScope();
}
}

View File

@ -0,0 +1,70 @@
/*
* Copyright 2012 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.repository.cdi;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.repository.cdi.CdiRepositoryExtensionSupport;
import javax.enterprise.event.Observes;
import javax.enterprise.inject.UnsatisfiedResolutionException;
import javax.enterprise.inject.spi.AfterBeanDiscovery;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanManager;
import javax.enterprise.inject.spi.ProcessBean;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
public class ElasticsearchRepositoryExtension extends CdiRepositoryExtensionSupport {
private final Map<String, Bean<ElasticsearchOperations>> elasticsearchOperationsMap = new HashMap<String, Bean<ElasticsearchOperations>>();
@SuppressWarnings("unchecked")
<T> void processBean(@Observes ProcessBean<T> processBean) {
Bean<T> bean = processBean.getBean();
for (Type type : bean.getTypes()) {
if (type instanceof Class<?> && ElasticsearchOperations.class.isAssignableFrom((Class<?>) type)) {
elasticsearchOperationsMap.put(bean.getQualifiers().toString(), ((Bean<ElasticsearchOperations>) bean));
}
}
}
void afterBeanDiscovery(@Observes AfterBeanDiscovery afterBeanDiscovery, BeanManager beanManager) {
for (Entry<Class<?>, Set<Annotation>> entry : getRepositoryTypes()) {
Class<?> repositoryType = entry.getKey();
Set<Annotation> qualifiers = entry.getValue();
Bean<?> repositoryBean = createRepositoryBean(repositoryType, qualifiers, beanManager);
afterBeanDiscovery.addBean(repositoryBean);
}
}
private <T> Bean<T> createRepositoryBean(Class<T> repositoryType, Set<Annotation> qualifiers, BeanManager beanManager) {
Bean<ElasticsearchOperations> elasticsearchOperationsBean = this.elasticsearchOperationsMap.get(qualifiers.toString());
if (elasticsearchOperationsBean == null) {
throw new UnsatisfiedResolutionException(String.format("Unable to resolve a bean for '%s' with qualifiers %s.",
ElasticsearchOperations.class.getName(), qualifiers));
}
return new ElasticsearchRepositoryBean<T>(elasticsearchOperationsBean, qualifiers, repositoryType, beanManager);
}
}

View File

@ -0,0 +1,47 @@
/*
* Copyright 2012 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.repository.config;
import org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport;
import org.springframework.data.repository.config.RepositoryConfigurationExtension;
import java.lang.annotation.Annotation;
/**
* {@link org.springframework.context.annotation.ImportBeanDefinitionRegistrar} implementation to trigger configuration of the {@link EnableElasticsearchRepositories}
* annotation.
*
*/
class ElasticsearchRepositoriesRegistrar extends RepositoryBeanDefinitionRegistrarSupport {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getAnnotation()
*/
@Override
protected Class<? extends Annotation> getAnnotation() {
return EnableElasticsearchRepositories.class;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryBeanDefinitionRegistrarSupport#getExtension()
*/
@Override
protected RepositoryConfigurationExtension getExtension() {
return new ElasticsearchRepositoryConfigExtension();
}
}

View File

@ -0,0 +1,74 @@
/*
* Copyright 2012 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.repository.config;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.core.annotation.AnnotationAttributes;
import org.springframework.data.elasticsearch.repository.support.ElasticsearchRepositoryFactoryBean;
import org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource;
import org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport;
import org.springframework.data.repository.config.XmlRepositoryConfigurationSource;
import org.w3c.dom.Element;
/**
* {@link org.springframework.data.repository.config.RepositoryConfigurationExtension} implementation to configure Solr repository configuration support,
* evaluating the {@link EnableElasticsearchRepositories} annotation or the equivalent XML element.
*
*/
public class ElasticsearchRepositoryConfigExtension extends RepositoryConfigurationExtensionSupport {
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtension#getRepositoryFactoryClassName()
*/
@Override
public String getRepositoryFactoryClassName() {
return ElasticsearchRepositoryFactoryBean.class.getName();
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#getModulePrefix()
*/
@Override
protected String getModulePrefix() {
return "elasticsearch";
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.AnnotationRepositoryConfigurationSource)
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, AnnotationRepositoryConfigurationSource config) {
AnnotationAttributes attributes = config.getAttributes();
builder.addPropertyReference("elasticsearchOperations", attributes.getString("elasticsearchTemplateRef"));
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.config.RepositoryConfigurationExtensionSupport#postProcess(org.springframework.beans.factory.support.BeanDefinitionBuilder, org.springframework.data.repository.config.XmlRepositoryConfigurationSource)
*/
@Override
public void postProcess(BeanDefinitionBuilder builder, XmlRepositoryConfigurationSource config) {
Element element = config.getElement();
builder.addPropertyReference("elasticsearchOperations", element.getAttribute("elasticsearch-template-ref"));
}
}

View File

@ -0,0 +1,110 @@
/*
* Copyright 2012 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.repository.config;
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.query.QueryLookupStrategy.Key;
import java.lang.annotation.*;
/**
* Annotation to enable Elasticsearch repositories. Will scan the package of the annotated configuration class for Spring Data
* repositories by default.
*
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import(ElasticsearchRepositoriesRegistrar.class)
public @interface EnableElasticsearchRepositories {
/**
* Alias for the {@link #basePackages()} attribute. Allows for more concise annotation declarations e.g.:
* {@code @EnableElasticsearchRepositories("org.my.pkg")} instead of {@code @EnableElasticsearchRepositories(basePackages="org.my.pkg")}.
*/
String[] value() default {};
/**
* Base packages to scan for annotated components. {@link #value()} is an alias for (and mutually exclusive with) this
* attribute. Use {@link #basePackageClasses()} for a type-safe alternative to String-based package names.
*/
String[] basePackages() default {};
/**
* Type-safe alternative to {@link #basePackages()} for specifying the packages to scan for annotated components. The
* package of each class specified will be scanned. Consider creating a special no-op marker class or interface in
* each package that serves no purpose other than being referenced by this attribute.
*/
Class<?>[] basePackageClasses() default {};
/**
* Specifies which types are eligible for component scanning. Further narrows the set of candidate components from
* everything in {@link #basePackages()} to everything in the base packages that matches the given filter or filters.
*/
Filter[] includeFilters() default {};
/**
* Specifies which types are not eligible for component scanning.
*/
Filter[] excludeFilters() default {};
/**
* Returns the postfix to be used when looking up custom repository implementations. Defaults to {@literal Impl}. So
* for a repository named {@code PersonRepository} the corresponding implementation class will be looked up scanning
* for {@code PersonRepositoryImpl}.
*
* @return
*/
String repositoryImplementationPostfix() default "Impl";
/**
* Configures the location of where to find the Spring Data named queries properties file. Will default to
* {@code META-INFO/elasticsearch-named-queries.properties}.
*
* @return
*/
String namedQueriesLocation() default "";
/**
* Returns the key of the {@link org.springframework.data.repository.query.QueryLookupStrategy} to be used for lookup queries for query methods. Defaults to
* {@link org.springframework.data.repository.query.QueryLookupStrategy.Key#CREATE_IF_NOT_FOUND}.
*
* @return
*/
Key queryLookupStrategy() default Key.CREATE_IF_NOT_FOUND;
/**
* Returns the {@link org.springframework.beans.factory.FactoryBean} class to be used for each repository instance. Defaults to
* {@link ElasticsearchRepositoryFactoryBean}.
*
* @return
*/
Class<?> repositoryFactoryBeanClass() default ElasticsearchRepositoryFactoryBean.class;
// Solr specific configuration
/**
* Configures the name of the {@link ElasticsearchTemplate} bean definition to be used to create repositories discovered
* through this annotation. Defaults to {@code elasticsearchTemplate}.
*
* @return
*/
String elasticsearchTemplateRef() default "elasticsearchTemplate";
}

View File

@ -0,0 +1,38 @@
/*
* Copyright 2012 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.repository.query;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.data.repository.query.RepositoryQuery;
public abstract class AbstractElasticsearchRepositoryQuery implements RepositoryQuery {
protected ElasticsearchQueryMethod queryMethod;
protected ElasticsearchOperations elasticsearchOperations;
public AbstractElasticsearchRepositoryQuery(ElasticsearchQueryMethod queryMethod, ElasticsearchOperations elasticsearchOperations) {
this.queryMethod = queryMethod;
this.elasticsearchOperations = elasticsearchOperations;
}
@Override
public QueryMethod getQueryMethod() {
return queryMethod;
}
}

View File

@ -0,0 +1,37 @@
package org.springframework.data.elasticsearch.repository.query;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.elasticsearch.repository.query.parser.ElasticsearchQueryCreator;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.data.repository.query.parser.PartTree;
public class ElasticsearchPartQuery extends AbstractElasticsearchRepositoryQuery{
private final PartTree tree;
private final MappingContext<?, ElasticsearchPersistentProperty> mappingContext;
public ElasticsearchPartQuery(ElasticsearchQueryMethod method, ElasticsearchOperations elasticsearchOperations) {
super(method, elasticsearchOperations);
this.tree = new PartTree(method.getName(), method.getEntityInformation().getJavaType());
this.mappingContext = elasticsearchOperations.getElasticsearchConverter().getMappingContext();
}
@Override
public Object execute(Object[] parameters) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
CriteriaQuery query = createQuery(accessor);
if(queryMethod.isPageQuery()){
return elasticsearchOperations.queryForPage(query, queryMethod.getEntityInformation().getJavaType());
}
return elasticsearchOperations.queryForObject(query, queryMethod.getEntityInformation().getJavaType());
}
public CriteriaQuery createQuery(ParametersParameterAccessor accessor) {
return new ElasticsearchQueryCreator(tree, accessor, mappingContext).createQuery();
}
}

View File

@ -0,0 +1,38 @@
package org.springframework.data.elasticsearch.repository.query;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.support.ElasticsearchEntityInformation;
import org.springframework.data.elasticsearch.repository.support.ElasticsearchEntityInformationCreator;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.query.QueryMethod;
import org.springframework.util.StringUtils;
import java.lang.reflect.Method;
public class ElasticsearchQueryMethod extends QueryMethod {
private final ElasticsearchEntityInformation<?, ?> entityInformation;
private Method method;
public ElasticsearchQueryMethod(Method method, RepositoryMetadata metadata, ElasticsearchEntityInformationCreator elasticsearchEntityInformationCreator) {
super(method, metadata);
this.entityInformation = elasticsearchEntityInformationCreator.getEntityInformation(metadata.getReturnedDomainClass(method));
this.method = method;
}
public boolean hasAnnotatedQuery() {
return getQueryAnnotation() != null;
}
public String getAnnotatedQuery() {
String query = (String) AnnotationUtils.getValue(getQueryAnnotation(), "value");
return StringUtils.hasText(query) ? query : null;
}
private Query getQueryAnnotation() {
return this.method.getAnnotation(Query.class);
}
}

View File

@ -0,0 +1,77 @@
package org.springframework.data.elasticsearch.repository.query;
import org.springframework.core.convert.support.GenericConversionService;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.convert.DateTimeConverters;
import org.springframework.data.elasticsearch.core.query.StringQuery;
import org.springframework.data.repository.query.ParametersParameterAccessor;
import org.springframework.util.Assert;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class ElasticsearchStringQuery extends AbstractElasticsearchRepositoryQuery{
private static final Pattern PARAMETER_PLACEHOLDER = Pattern.compile("\\?(\\d+)");
private String query;
private final GenericConversionService conversionService = new GenericConversionService();
{
if (!conversionService.canConvert(java.util.Date.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JavaDateConverter.INSTANCE);
}
if (!conversionService.canConvert(org.joda.time.ReadableInstant.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JodaDateTimeConverter.INSTANCE);
}
if (!conversionService.canConvert(org.joda.time.LocalDateTime.class, String.class)) {
conversionService.addConverter(DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE);
}
}
public ElasticsearchStringQuery(ElasticsearchQueryMethod queryMethod, ElasticsearchOperations elasticsearchOperations, String query) {
super(queryMethod, elasticsearchOperations);
Assert.notNull(query, "Query cannot be empty");
this.query = query;
}
@Override
public Object execute(Object[] parameters) {
ParametersParameterAccessor accessor = new ParametersParameterAccessor(queryMethod.getParameters(), parameters);
StringQuery stringQuery = createQuery(accessor);
if(queryMethod.isPageQuery()){
return elasticsearchOperations.queryForPage(stringQuery, queryMethod.getEntityInformation().getJavaType());
}
return elasticsearchOperations.queryForObject(stringQuery, queryMethod.getEntityInformation().getJavaType());
}
protected StringQuery createQuery(ParametersParameterAccessor parameterAccessor) {
String queryString = replacePlaceholders(this.query, parameterAccessor);
return new StringQuery(queryString);
}
private String replacePlaceholders(String input, ParametersParameterAccessor accessor) {
Matcher matcher = PARAMETER_PLACEHOLDER.matcher(input);
String result = input;
while (matcher.find()) {
String group = matcher.group();
int index = Integer.parseInt(matcher.group(1));
result = result.replace(group, getParameterWithIndex(accessor, index));
}
return result;
}
private String getParameterWithIndex(ParametersParameterAccessor accessor, int index) {
Object parameter = accessor.getBindableValue(index);
if (parameter == null) {
return "null";
}
if (conversionService.canConvert(parameter.getClass(), String.class)) {
return conversionService.convert(parameter, String.class);
}
return parameter.toString();
}
}

View File

@ -0,0 +1,115 @@
package org.springframework.data.elasticsearch.repository.query.parser;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.query.Criteria;
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.mapping.context.PersistentPropertyPath;
import org.springframework.data.repository.query.ParameterAccessor;
import org.springframework.data.repository.query.parser.AbstractQueryCreator;
import org.springframework.data.repository.query.parser.Part;
import org.springframework.data.repository.query.parser.PartTree;
import java.util.Collection;
import java.util.Iterator;
public class ElasticsearchQueryCreator extends AbstractQueryCreator<CriteriaQuery,CriteriaQuery>{
private final MappingContext<?, ElasticsearchPersistentProperty> context;
public ElasticsearchQueryCreator(PartTree tree, ParameterAccessor parameters, MappingContext<?, ElasticsearchPersistentProperty> context) {
super(tree, parameters);
this.context = context;
}
public ElasticsearchQueryCreator(PartTree tree, MappingContext<?, ElasticsearchPersistentProperty> context) {
super(tree);
this.context = context;
}
@Override
protected CriteriaQuery create(Part part, Iterator<Object> iterator) {
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
return new CriteriaQuery(from(part.getType(),
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), iterator));
}
@Override
protected CriteriaQuery and(Part part, CriteriaQuery base, Iterator<Object> iterator) {
if (base == null) {
return create(part, iterator);
}
PersistentPropertyPath<ElasticsearchPersistentProperty> path = context.getPersistentPropertyPath(part.getProperty());
return base.addCriteria(from(part.getType(),
new Criteria(path.toDotPath(ElasticsearchPersistentProperty.PropertyToFieldNameConverter.INSTANCE)), iterator));
}
@Override
protected CriteriaQuery or(CriteriaQuery base, CriteriaQuery query) {
return new CriteriaQuery(base.getCriteria().or(query.getCriteria()));
}
@Override
protected CriteriaQuery complete(CriteriaQuery query, Sort sort) {
if (query == null) {
return null;
}
return query.addSort(sort);
}
private Criteria from(Part.Type type, Criteria instance, Iterator<?> parameters) {
Criteria criteria = instance;
if (criteria == null) {
criteria = new Criteria();
}
switch (type) {
case TRUE:
return criteria.is(true);
case FALSE:
return criteria.is(false);
case SIMPLE_PROPERTY:
return criteria.is(parameters.next());
case NEGATING_SIMPLE_PROPERTY:
return criteria.is(parameters.next()).not();
case REGEX:
return criteria.expression(parameters.next().toString());
case LIKE:
case STARTING_WITH:
return criteria.startsWith(parameters.next().toString());
case ENDING_WITH:
return criteria.endsWith(parameters.next().toString());
case CONTAINING:
return criteria.contains(parameters.next().toString());
case AFTER:
case GREATER_THAN:
case GREATER_THAN_EQUAL:
return criteria.greaterThanEqual(parameters.next());
case BEFORE:
case LESS_THAN:
case LESS_THAN_EQUAL:
return criteria.lessThanEqual(parameters.next());
case BETWEEN:
return criteria.between(parameters.next(), parameters.next());
case IN:
return criteria.in(asArray(parameters.next()));
case NOT_IN:
return criteria.in(asArray(parameters.next())).not();
default:
throw new InvalidDataAccessApiUsageException("Illegal criteria found '" + type + "'.");
}
}
private Object[] asArray(Object o) {
if (o instanceof Collection) {
return ((Collection<?>) o).toArray();
} else if (o.getClass().isArray()) {
return (Object[]) o;
}
return new Object[] { o };
}
}

View File

@ -0,0 +1,32 @@
/*
* Copyright 2012 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.repository.support;
import org.springframework.data.repository.core.EntityInformation;
import java.io.Serializable;
/**
* @param <T>
* @param <ID>
*/
public interface ElasticsearchEntityInformation<T, ID extends Serializable> extends EntityInformation<T, ID> {
String getIdAttribute();
String getIndexName();
String getType();
}

View File

@ -0,0 +1,24 @@
/*
* Copyright 2012 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.repository.support;
import java.io.Serializable;
public interface ElasticsearchEntityInformationCreator {
<T, ID extends Serializable> ElasticsearchEntityInformation<T, ID> getEntityInformation(Class<T> domainClass);
}

View File

@ -0,0 +1,43 @@
/*
* Copyright 2012 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.repository.support;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.util.Assert;
import java.io.Serializable;
public class ElasticsearchEntityInformationCreatorImpl implements ElasticsearchEntityInformationCreator {
private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;
public ElasticsearchEntityInformationCreatorImpl(
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
Assert.notNull(mappingContext);
this.mappingContext = mappingContext;
}
@Override
@SuppressWarnings("unchecked")
public <T, ID extends Serializable> ElasticsearchEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
ElasticsearchPersistentEntity<T> persistentEntity = (ElasticsearchPersistentEntity<T>) mappingContext
.getPersistentEntity(domainClass);
return new MappingElasticsearchEntityInformation<T, ID>(persistentEntity);
}
}

View File

@ -0,0 +1,101 @@
/*
* Copyright 2012 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.repository.support;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.data.elasticsearch.repository.query.ElasticsearchPartQuery;
import org.springframework.data.elasticsearch.repository.query.ElasticsearchQueryMethod;
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.RepositoryMetadata;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.data.repository.query.QueryLookupStrategy;
import org.springframework.data.repository.query.RepositoryQuery;
import org.springframework.util.Assert;
import java.io.Serializable;
import java.lang.reflect.Method;
import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT;
/**
* Factory to create {@link ElasticsearchRepository}
*
*/
public class ElasticsearchRepositoryFactory extends RepositoryFactorySupport {
private final ElasticsearchOperations elasticsearchOperations;
private final ElasticsearchEntityInformationCreator entityInformationCreator;
public ElasticsearchRepositoryFactory(ElasticsearchOperations elasticsearchOperations) {
Assert.notNull(elasticsearchOperations);
this.elasticsearchOperations = elasticsearchOperations;
this.entityInformationCreator = new ElasticsearchEntityInformationCreatorImpl(elasticsearchOperations.getElasticsearchConverter()
.getMappingContext());
}
@Override
public <T, ID extends Serializable> ElasticsearchEntityInformation<T, ID> getEntityInformation(Class<T> domainClass) {
return entityInformationCreator.getEntityInformation(domainClass);
}
@Override
@SuppressWarnings({ "rawtypes", "unchecked" })
protected Object getTargetRepository(RepositoryMetadata metadata) {
SimpleElasticsearchRepository repository = new SimpleElasticsearchRepository(getEntityInformation(metadata.getDomainType()), elasticsearchOperations);
repository.setEntityClass(metadata.getDomainType());
return repository;
}
@Override
protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
if (isQueryDslRepository(metadata.getRepositoryInterface())) {
throw new IllegalArgumentException("QueryDsl Support has not been implemented yet.");
}
return SimpleElasticsearchRepository.class;
}
private static boolean isQueryDslRepository(Class<?> repositoryInterface) {
return QUERY_DSL_PRESENT && QueryDslPredicateExecutor.class.isAssignableFrom(repositoryInterface);
}
@Override
protected QueryLookupStrategy getQueryLookupStrategy(QueryLookupStrategy.Key key) {
return new ElasticsearchQueryLookupStrategy();
}
private class ElasticsearchQueryLookupStrategy implements QueryLookupStrategy {
@Override
public RepositoryQuery resolveQuery(Method method, RepositoryMetadata metadata, NamedQueries namedQueries) {
ElasticsearchQueryMethod queryMethod = new ElasticsearchQueryMethod(method, metadata, entityInformationCreator);
String namedQueryName = queryMethod.getNamedQueryName();
if (namedQueries.hasQuery(namedQueryName)) {
String namedQuery = namedQueries.getQuery(namedQueryName);
return new ElasticsearchStringQuery(queryMethod, elasticsearchOperations, namedQuery);
}
else if (queryMethod.hasAnnotatedQuery()) {
return new ElasticsearchStringQuery(queryMethod, elasticsearchOperations, queryMethod.getAnnotatedQuery());
}
return new ElasticsearchPartQuery(queryMethod, elasticsearchOperations);
}
}
}

View File

@ -0,0 +1,61 @@
/*
* Copyright 2012 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.repository.support;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.repository.Repository;
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
import org.springframework.data.repository.core.support.RepositoryFactorySupport;
import org.springframework.util.Assert;
import java.io.Serializable;
/**
* Spring {@link org.springframework.beans.factory.FactoryBean} implementation to ease container based configuration for XML namespace and JavaConfig.
*
*/
public class ElasticsearchRepositoryFactoryBean<T extends Repository<S, ID>, S, ID extends Serializable> extends
RepositoryFactoryBeanSupport<T, S, ID> {
private ElasticsearchOperations operations;
/**
* Configures the {@link ElasticsearchOperations} to be used to create Solr repositories.
*
* @param operations the operations to set
*/
public void setElasticsearchOperations(ElasticsearchOperations operations) {
Assert.notNull(operations);
this.operations = operations;
}
/*
* (non-Javadoc)
* @see org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport#afterPropertiesSet()
*/
@Override
public void afterPropertiesSet() {
super.afterPropertiesSet();
Assert.notNull(operations, "ElasticsearchOperations must be configured!");
}
@Override
protected RepositoryFactorySupport createRepositoryFactory() {
return new ElasticsearchRepositoryFactory(operations);
}
}

View File

@ -0,0 +1,82 @@
/*
* Copyright 2012 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.repository.support;
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.util.Assert;
import java.io.Serializable;
/**
* Elasticsearch specific implementation of {@link org.springframework.data.repository.core.support.AbstractEntityInformation}
*
* @param <T>
* @param <ID>
*/
public class MappingElasticsearchEntityInformation<T, ID extends Serializable> extends AbstractEntityInformation<T, ID>
implements ElasticsearchEntityInformation<T, ID> {
private final ElasticsearchPersistentEntity<T> entityMetadata;
private final String indexName;
private final String type;
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity) {
this(entity, null, null);
}
public MappingElasticsearchEntityInformation(ElasticsearchPersistentEntity<T> entity, String indexName, String type) {
super(entity.getType());
this.entityMetadata = entity;
this.indexName = indexName;
this.type = type;
}
@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>) String.class;
}
@Override
public String getIdAttribute() {
Assert.notNull(entityMetadata.getIdProperty(),"Unable to identify 'id' property in class " + entityMetadata.getType().getSimpleName() +". Make sure the 'id' property is annotated with @Id or named as 'id' or 'documentId' ");
return entityMetadata.getIdProperty().getFieldName();
}
@Override
public String getIndexName() {
return indexName != null? indexName : entityMetadata.getIndexName();
}
@Override
public String getType() {
return type != null? type : entityMetadata.getIndexType();
}
}

View File

@ -0,0 +1,269 @@
/*
* Copyright 2012 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.repository.support;
import org.elasticsearch.index.query.QueryBuilder;
import org.springframework.dao.InvalidDataAccessApiUsageException;
import org.springframework.data.domain.*;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
import org.springframework.data.elasticsearch.core.query.GetQuery;
import org.springframework.data.elasticsearch.core.query.IndexQuery;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
import org.springframework.util.Assert;
import javax.annotation.PostConstruct;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import static org.elasticsearch.index.query.QueryBuilders.inQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
/**
* Elasticsearch specific repository implementation. Likely to be used as target within {@link ElasticsearchRepositoryFactory}
*
* @param <T>
*/
public class SimpleElasticsearchRepository<T> implements ElasticsearchRepository<T, String> {
private ElasticsearchOperations elasticsearchOperations;
private Class<T> entityClass;
private ElasticsearchEntityInformation<T, String> entityInformation;
public SimpleElasticsearchRepository() {
}
public SimpleElasticsearchRepository(ElasticsearchOperations elasticsearchOperations) {
Assert.notNull(elasticsearchOperations);
this.setElasticsearchOperations(elasticsearchOperations);
}
public SimpleElasticsearchRepository(ElasticsearchEntityInformation<T, String> metadata, ElasticsearchOperations elasticsearchOperations) {
this(elasticsearchOperations);
Assert.notNull(metadata);
this.entityInformation = metadata;
setEntityClass(this.entityInformation.getJavaType());
}
@PostConstruct
public void createIndex(){
elasticsearchOperations.createIndex(getEntityClass());
}
@Override
public T findOne(String id) {
GetQuery query = new GetQuery();
query.setId(id);
return elasticsearchOperations.queryForObject(query, getEntityClass());
}
@Override
public Iterable<T> findAll() {
int itemCount = (int) this.count();
if (itemCount == 0) {
return new PageImpl<T>(Collections.<T> emptyList());
}
return this.findAll(new PageRequest(0, Math.max(1, itemCount)));
}
@Override
public Page<T> findAll(Pageable pageable) {
SearchQuery query = new SearchQuery();
query.setElasticsearchQuery(matchAllQuery());
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public Iterable<T> findAll(Sort sort) {
SearchQuery query = new SearchQuery();
query.setElasticsearchQuery(matchAllQuery());
query.setPageable(new PageRequest(0,Integer.MAX_VALUE, sort));
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public Iterable<T> findAll(Iterable<String> ids) {
SearchQuery query = new SearchQuery();
query.setElasticsearchQuery(inQuery(entityInformation.getIdAttribute(), ids));
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public long count() {
SearchQuery query = new SearchQuery();
return elasticsearchOperations.count(query,getEntityClass());
}
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Cannot save 'null' entity.");
elasticsearchOperations.index(createIndexQuery(entity));
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
return entity;
}
public <S extends T> List<S> save(List<S> entities) {
Assert.notNull(entities, "Cannot insert 'null' as a List.");
Assert.notEmpty(entities,"Cannot insert empty List.");
List<IndexQuery> queries = new ArrayList<IndexQuery>();
for(S s:entities){
queries.add(createIndexQuery(s));
}
elasticsearchOperations.bulkIndex(queries);
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
return entities;
}
@Override
public <S extends T> S index(S entity) {
return save(entity);
}
@Override
public <S extends T> Iterable<S> save(Iterable<S> entities) {
Assert.notNull(entities, "Cannot insert 'null' as a List.");
if (!(entities instanceof Collection<?>)) {
throw new InvalidDataAccessApiUsageException("Entities have to be inside a collection");
}
List<IndexQuery> queries = new ArrayList<IndexQuery>();
for(S s: entities){
queries.add(createIndexQuery(s));
}
elasticsearchOperations.bulkIndex(queries);
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
return entities;
}
@Override
public boolean exists(String id) {
return findOne(id) != null;
}
@Override
public Iterable<T> search(QueryBuilder elasticsearchQuery) {
SearchQuery query = new SearchQuery();
query.setElasticsearchQuery(elasticsearchQuery);
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public Page<T> search(QueryBuilder elasticsearchQuery, Pageable pageable) {
SearchQuery query = new SearchQuery();
query.setElasticsearchQuery(elasticsearchQuery);
query.setPageable(pageable);
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public Page<T> search(SearchQuery query){
return elasticsearchOperations.queryForPage(query, getEntityClass());
}
@Override
public void delete(String id) {
Assert.notNull(id, "Cannot delete entity with id 'null'.");
elasticsearchOperations.delete(entityInformation.getIndexName(), entityInformation.getType(),id);
elasticsearchOperations.refresh(entityInformation.getIndexName(),true);
}
@Override
public void delete(T entity) {
Assert.notNull(entity, "Cannot delete 'null' entity.");
delete(extractIdFromBean(entity));
elasticsearchOperations.refresh(entityInformation.getIndexName(), true);
}
@Override
public void delete(Iterable<? extends T> entities) {
Assert.notNull(entities, "Cannot delete 'null' list.");
for (T entity : entities) {
delete(entity);
}
}
@Override
public void deleteAll() {
DeleteQuery query = new DeleteQuery();
query.setElasticsearchQuery(matchAllQuery());
elasticsearchOperations.delete(query, getEntityClass());
elasticsearchOperations.refresh(entityInformation.getIndexName(),true);
}
private IndexQuery createIndexQuery(T entity){
IndexQuery query = new IndexQuery();
query.setObject(entity);
query.setId(extractIdFromBean(entity));
return query;
}
@SuppressWarnings("unchecked")
private Class<T> resolveReturnedClassFromGenericType() {
ParameterizedType parameterizedType = resolveReturnedClassFromGenericType(getClass());
return (Class<T>) parameterizedType.getActualTypeArguments()[0];
}
private ParameterizedType resolveReturnedClassFromGenericType(Class<?> clazz) {
Object genericSuperclass = clazz.getGenericSuperclass();
if (genericSuperclass instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) genericSuperclass;
Type rawtype = parameterizedType.getRawType();
if (SimpleElasticsearchRepository.class.equals(rawtype)) {
return parameterizedType;
}
}
return resolveReturnedClassFromGenericType(clazz.getSuperclass());
}
public Class<T> getEntityClass() {
if (!isEntityClassSet()) {
try {
this.entityClass = resolveReturnedClassFromGenericType();
} catch (Exception e) {
throw new InvalidDataAccessApiUsageException("Unable to resolve EntityClass. Please use according setter!", e);
}
}
return entityClass;
}
private boolean isEntityClassSet() {
return entityClass != null;
}
public final void setEntityClass(Class<T> entityClass) {
Assert.notNull(entityClass, "EntityClass must not be null.");
this.entityClass = entityClass;
}
public final void setElasticsearchOperations(ElasticsearchOperations elasticsearchOperations) {
Assert.notNull(elasticsearchOperations, "ElasticsearchOperations must not be null.");
this.elasticsearchOperations = elasticsearchOperations;
}
private String extractIdFromBean(T entity) {
if (entityInformation != null) {
return entityInformation.getId(entity);
}
return null;
}
}

View File

@ -0,0 +1,73 @@
<?xml version="1.0" encoding="UTF-8" ?>
<xsd:schema xmlns="http://www.springframework.org/schema/data/elasticsearch"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
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">
<xsd:import namespace="http://www.springframework.org/schema/beans" />
<xsd:import namespace="http://www.springframework.org/schema/tool" />
<xsd:import namespace="http://www.springframework.org/schema/data/repository"
schemaLocation="http://www.springframework.org/schema/data/repository/spring-repository.xsd" />
<xsd:element name="repositories">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="repository:repositories">
<xsd:attributeGroup ref="repository:repository-attributes" />
<xsd:attribute name="elasticsearch-template-ref" type="elasticsearchTemplateRef" default="elasticsearchTemplate" />
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
<xsd:simpleType name="elasticsearchTemplateRef">
<xsd:annotation>
<xsd:appinfo>
<tool:annotation kind="ref">
<tool:assignable-to type="org.springframework.data.elasticsearch.core.ElasticsearchTemplate" />
</tool:annotation>
</xsd:appinfo>
</xsd:annotation>
<xsd:union memberTypes="xsd:string" />
</xsd:simpleType>
<xsd:element name="node-client">
<xsd:annotation>
<xsd:documentation source="java: org.springframework.data.elasticsearch.client.NodeClientFactoryBean" />
<xsd:appinfo>
<tool:assignable-to type="org.elasticsearch.client.Client"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="local" type="xsd:boolean" default="false"/>
</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:appinfo>
<tool:assignable-to type="org.elasticsearch.client.Client"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<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>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>

View File

@ -0,0 +1,27 @@
package org.springframework.data.elasticsearch;
import org.springframework.data.elasticsearch.annotations.Document;
@Document(indexName = "Foo")
public class NonDocumentEntity {
private String someField1;
private String someField2;
public String getSomeField1() {
return someField1;
}
public void setSomeField1(String someField1) {
this.someField1 = someField1;
}
public String getSomeField2() {
return someField2;
}
public void setSomeField2(String someField2) {
this.someField2 = someField2;
}
}

View File

@ -0,0 +1,72 @@
package org.springframework.data.elasticsearch;
import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
@Document(indexName = "test-index", type = "test-type")
public class SampleEntity {
@Id
private String id;
private String type;
private String message;
private int rate;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
public int getRate() {
return rate;
}
public void setRate(int rate) {
this.rate = rate;
}
@Override
public boolean equals(Object obj) {
if (!(obj instanceof SampleEntity)) {
return false;
}
if (this == obj) {
return true;
}
SampleEntity rhs = (SampleEntity) obj;
return new EqualsBuilder().append(this.id, rhs.id)
.append(this.type, rhs.type)
.append(this.message, rhs.message)
.isEquals();
}
@Override
public int hashCode() {
return new HashCodeBuilder()
.append(id)
.append(type)
.append(message)
.toHashCode();
}
}

View File

@ -0,0 +1,44 @@
package org.springframework.data.elasticsearch.config;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.elasticsearch.repositories.SampleElasticsearchRepository;
import org.springframework.data.elasticsearch.client.NodeClientFactoryBean;
import org.springframework.data.elasticsearch.client.TransportClientFactoryBean;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.hamcrest.CoreMatchers.instanceOf;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("namespace.xml")
public class ElasticsearchNamespaceHandlerTest {
@Autowired
private ApplicationContext context;
@Test
public void shouldCreatesNodeClient() {
assertThat(context.getBean(NodeClientFactoryBean.class), is(notNullValue()));
assertThat(context.getBean(NodeClientFactoryBean.class), is(instanceOf(NodeClientFactoryBean.class)));
}
@Test
public void shouldCreateTransportClient() {
assertThat(context.getBean(TransportClientFactoryBean.class), is(notNullValue()));
assertThat(context.getBean(TransportClientFactoryBean.class), is(instanceOf(TransportClientFactoryBean.class)));
}
@Test
public void shouldCreateRepository(){
assertThat(context.getBean(TransportClientFactoryBean.class), is(notNullValue()));
assertThat(context.getBean(SampleElasticsearchRepository.class), is(instanceOf(SampleElasticsearchRepository.class)));
}
}

View File

@ -0,0 +1,44 @@
package org.springframework.data.elasticsearch.config;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.data.elasticsearch.repositories.SampleElasticsearchRepository;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class EnableElasticsearchRepositoriesTest {
@Configuration
@EnableElasticsearchRepositories(basePackages = "org.springframework.data.elasticsearch.repositories")
static class Config {
@Bean
public ElasticsearchOperations elasticsearchTemplate() {
return new ElasticsearchTemplate(nodeBuilder().local(true).node().client());
}
}
@Autowired
private SampleElasticsearchRepository repository;
@Test
public void bootstrapsRepository() {
assertThat(repository, is(notNullValue()));
}
}

View File

@ -0,0 +1,338 @@
package org.springframework.data.elasticsearch.core;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.SampleEntity;
import org.springframework.data.elasticsearch.core.query.*;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.ArrayList;
import java.util.List;
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.fieldQuery;
import static org.elasticsearch.index.query.QueryBuilders.matchAllQuery;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
public class ElasticsearchTemplateTest {
@Autowired
private ElasticsearchTemplate elasticsearchTemplate;
@Before
public void before(){
elasticsearchTemplate.createIndex(SampleEntity.class);
DeleteQuery deleteQuery = new DeleteQuery();
deleteQuery.setElasticsearchQuery(matchAllQuery());
elasticsearchTemplate.delete(deleteQuery,SampleEntity.class);
elasticsearchTemplate.refresh(SampleEntity.class, true);
}
@Test
public void shouldReturnCountForGivenSearchQuery(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(matchAllQuery());
//when
long count = elasticsearchTemplate.count(searchQuery, SampleEntity.class);
//then
assertThat(count, is(equalTo(1L)));
}
@Test
public void shouldReturnObjectForGivenId(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
//when
GetQuery getQuery = new GetQuery();
getQuery.setId(documentId);
SampleEntity sampleEntity1 = elasticsearchTemplate.queryForObject(getQuery, SampleEntity.class);
//then
assertNotNull("not null....", sampleEntity1);
assertEquals(sampleEntity, sampleEntity1);
}
@Test
public void shouldReturnPageForGivenSearchQuery(){
//given
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(matchAllQuery());
//when
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class);
//then
assertThat(sampleEntities, is(notNullValue()));
assertThat(sampleEntities.getTotalElements(), greaterThanOrEqualTo(1L));
}
@Test
public void shouldDoBulkIndex(){
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("some message");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
//when
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
//then
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(matchAllQuery());
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
assertThat(sampleEntities.getTotalElements(), is(equalTo(2L)));
}
@Test
public void shouldDeleteDocumentForGivenId(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
//when
elasticsearchTemplate.delete("test-index","test-type",documentId);
elasticsearchTemplate.refresh(SampleEntity.class, true);
//then
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(fieldQuery("id", documentId));
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
assertThat(sampleEntities.getTotalElements(), equalTo(0L));
}
@Test
public void shouldDeleteEntityForGivenId(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
//when
elasticsearchTemplate.delete(SampleEntity.class,documentId);
elasticsearchTemplate.refresh(SampleEntity.class, true);
//then
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(fieldQuery("id", documentId));
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
assertThat(sampleEntities.getTotalElements(), equalTo(0L));
}
@Test
public void shouldDeleteDocumentForGivenQuery(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
//when
DeleteQuery deleteQuery = new DeleteQuery();
deleteQuery.setElasticsearchQuery(fieldQuery("id", documentId));
elasticsearchTemplate.delete(deleteQuery,SampleEntity.class);
//then
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(fieldQuery("id",documentId));
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
assertThat(sampleEntities.getTotalElements(), equalTo(0L));
}
@Test
public void shouldTestFilterBuilder(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(matchAllQuery());
searchQuery.setElasticsearchFilter(boolFilter().must(termFilter("id", documentId)));
//when
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery,SampleEntity.class);
//then
assertThat(sampleEntities.getTotalElements(), equalTo(1L));
}
@Test
public void testStringQuery(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
StringQuery stringQuery = new StringQuery(matchAllQuery().toString());
//when
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(stringQuery,SampleEntity.class);
//then
assertThat(sampleEntities.getTotalElements(), equalTo(1L));
}
@Test
public void testStringQueryWithPageable(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
StringQuery stringQuery = new StringQuery(matchAllQuery().toString(),new PageRequest(0,10));
//when
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(stringQuery,SampleEntity.class);
//then
assertThat(sampleEntities.getTotalElements(), is(greaterThanOrEqualTo(1L)));
}
@Test
@Ignore("By default, the search request will fail if there is no mapping associated with a field. The ignore_unmapped option allows to ignore fields that have no mapping and not sort by them")
public void testStringQueryWithPageableAndSort(){
//todo
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
StringQuery stringQuery = new StringQuery(matchAllQuery().toString(),new PageRequest(0,10), new Sort(new Sort.Order(Sort.Direction.ASC,"messsage")));
//when
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(stringQuery,SampleEntity.class);
//then
assertThat(sampleEntities.getTotalElements(), is(greaterThanOrEqualTo(1L)));
}
@Test
public void testStringQueryGetObject(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
StringQuery stringQuery = new StringQuery(fieldQuery("id",documentId).toString());
//when
SampleEntity sampleEntity1 = elasticsearchTemplate.queryForObject(stringQuery, SampleEntity.class);
//then
assertThat(sampleEntity1, is(notNullValue()));
assertThat(sampleEntity1.getId(), is(equalTo(documentId)));
}
@Test
public void testCreateIndex(){
//when
boolean created = elasticsearchTemplate.createIndex(SampleEntity.class);
//then
assertThat(created, is(true));
}
@Test
public void testCriteria(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some test message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").contains("test"));
//when
SampleEntity sampleEntity1 = elasticsearchTemplate.queryForObject(criteriaQuery,SampleEntity.class);
//then
assertThat(sampleEntity1, is(notNullValue()));
}
}

View File

@ -0,0 +1,56 @@
package org.springframework.data.elasticsearch.core.convert;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.LocalDateTime;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import java.util.Calendar;
import java.util.TimeZone;
public class DateTimeConvertersTest {
@Test
public void testJodaDateTimeConverterWithNullValue() {
Assert.assertNull(DateTimeConverters.JodaDateTimeConverter.INSTANCE.convert(null));
}
@Test
public void testJodaDateTimeConverter() {
DateTime dateTime = new DateTime(2013, 1,24 , 6, 35, 0, DateTimeZone.UTC);
Assert.assertEquals("2013-01-24T06:35:00.000Z",
DateTimeConverters.JodaDateTimeConverter.INSTANCE.convert(dateTime));
}
@Test
public void testJodaLocalDateTimeConverterWithNullValue() {
Assert.assertNull(DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE.convert(null));
}
@Test
public void testJodaLocalDateTimeConverter() {
LocalDateTime dateTime = new LocalDateTime(new DateTime(2013, 1,24, 6, 35, 0, DateTimeZone.UTC).getMillis(),
DateTimeZone.UTC);
Assert.assertEquals("2013-01-24T06:35:00.000Z",
DateTimeConverters.JodaLocalDateTimeConverter.INSTANCE.convert(dateTime));
}
@Test
public void testJavaDateConverterWithNullValue() {
Assert.assertNull(DateTimeConverters.JavaDateConverter.INSTANCE.convert(null));
}
@Test
public void testJavaDateConverter() {
DateTime dateTime = new DateTime(2013, 1,24, 6, 35, 0, DateTimeZone.UTC);
Calendar calendar = Calendar.getInstance();
calendar.setTimeZone(TimeZone.getTimeZone("UTC"));
calendar.setTimeInMillis(dateTime.getMillis());
Assert.assertEquals("2013-01-24T06:35:00.000Z",
DateTimeConverters.JavaDateConverter.INSTANCE.convert(calendar.getTime()));
}
}

View File

@ -0,0 +1,40 @@
package org.springframework.data.elasticsearch.core.convert;
import org.junit.Test;
import org.springframework.core.convert.ConversionService;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.mapping.context.MappingContext;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;
public class MappingElasticsearchConverterTest {
@Test(expected = IllegalArgumentException.class)
public void shouldFailToInitializeGivenMappingContextIsNull(){
//given
new MappingElasticsearchConverter(null);
}
@Test
public void shouldReturnMappingContextWithWhichItWasInitialized(){
//given
MappingContext mappingContext = new SimpleElasticsearchMappingContext();
MappingElasticsearchConverter converter = new MappingElasticsearchConverter(mappingContext);
//then
assertThat(converter.getMappingContext(), is(notNullValue()));
assertThat(converter.getMappingContext(), is(sameInstance(mappingContext)));
}
@Test
public void shouldReturnDefaultConversionService(){
//given
MappingElasticsearchConverter converter = new MappingElasticsearchConverter(new SimpleElasticsearchMappingContext());
//when
ConversionService conversionService = converter.getConversionService();
//then
assertThat(conversionService, is(notNullValue()));
}
}

View File

@ -0,0 +1,627 @@
package org.springframework.data.elasticsearch.core.query;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.domain.Page;
import org.springframework.data.elasticsearch.SampleEntity;
import org.springframework.data.elasticsearch.core.ElasticsearchTemplate;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
public class CriteriaQueryTest {
@Resource
private ElasticsearchTemplate elasticsearchTemplate;
@Test
public void shouldTestAndOperation(){
//given
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some test message");
IndexQuery indexQuery = new IndexQuery();
indexQuery.setId(documentId);
indexQuery.setObject(sampleEntity);
elasticsearchTemplate.index(indexQuery);
elasticsearchTemplate.refresh(SampleEntity.class, true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").contains("test").and("message").contains("some"));
//when
SampleEntity sampleEntity1 = elasticsearchTemplate.queryForObject(criteriaQuery,SampleEntity.class);
//then
assertThat(sampleEntity1, is(notNullValue()));
}
@Test
public void shouldTestOrOperation(){
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test message");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").contains("some").or("message").contains("test"));
//when
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
assertThat(page, is(notNullValue()));
assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
public void shouldTestInnerAndCriteria(){
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria().and(new Criteria("message").contains("some")));
//when
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
assertThat(page, is(notNullValue()));
assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
public void shouldTestInnerOrCriteria(){
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria().or(new Criteria("message").contains("some")));
//when
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
assertThat(page, is(notNullValue()));
assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
public void testIs() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").is("some message"));
//when
Page<SampleEntity> page= elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
assertThat("message", is(criteriaQuery.getCriteria().getField().getName()));
assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
@Test
public void testMultipleIs() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test message");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").is("some message").is("test message"));
//when
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(criteriaQuery,SampleEntity.class);
//then
assertThat("message", is(criteriaQuery.getCriteria().getField().getName()));
assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(2L)));
}
@Test
public void testEndsWith() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test message end");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
Criteria criteria = new Criteria("message").endsWith("end");
CriteriaQuery criteriaQuery = new CriteriaQuery(criteria);
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
//then
assertThat("message", is(criteriaQuery.getCriteria().getField().getName()));
assertThat(sampleEntity, is(notNullValue()));
}
@Test
public void testStartsWith() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("start some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test message");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
Criteria criteria = new Criteria("message").startsWith("start");
CriteriaQuery criteriaQuery = new CriteriaQuery(criteria);
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery,SampleEntity.class);
//then
assertThat("message", is(criteriaQuery.getCriteria().getField().getName()));
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testContains() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("contains some message");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test message");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery= new CriteriaQuery(new Criteria("message").contains("contains"));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery,SampleEntity.class);
//then
assertThat("message", is(criteriaQuery.getCriteria().getField().getName()));
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testExpression() {
//given
//todo
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("elasticsearch search");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test message");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery= new CriteriaQuery(new Criteria("message").expression("+elasticsearch || test"));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery,SampleEntity.class);
//then
assertThat("message", is(criteriaQuery.getCriteria().getField().getName()));
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testCriteriaChain() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message search");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("test test message");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").startsWith("some").endsWith("search").contains("message").is("some message search"));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery,SampleEntity.class);
//then
assertThat("message", is(criteriaQuery.getCriteria().getField().getName()));
assertThat(sampleEntity, is(notNullValue()));
}
@Test
public void testIsNot() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("bar");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("foo");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").is("foo").not());
//when
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
assertTrue(criteriaQuery.getCriteria().isNegating());
assertThat(page,is(notNullValue()));
assertFalse(page.iterator().next().getMessage().contains("foo"));
}
@Test
public void testBetween() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setRate(100);
sampleEntity1.setMessage("bar");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setRate(200);
sampleEntity2.setMessage("foo");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").between(100,150));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
//then
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testBetweenWithoutUpperBound() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setRate(300);
sampleEntity1.setMessage("bar");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setRate(400);
sampleEntity2.setMessage("foo");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").between(350,null));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
//then
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testBetweenWithoutLowerBound() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setRate(500);
sampleEntity1.setMessage("bar");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setRate(600);
sampleEntity2.setMessage("foo");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").between(null,550));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
//then
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testLessThanEqauls() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setRate(700);
sampleEntity1.setMessage("bar");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setRate(800);
sampleEntity2.setMessage("foo");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").lessThanEqual(750));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
//then
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testGreaterThanEqauls() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setRate(900);
sampleEntity1.setMessage("bar");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setRate(1000);
sampleEntity2.setMessage("foo");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("rate").greaterThanEqual(950));
//when
SampleEntity sampleEntity = elasticsearchTemplate.queryForObject(criteriaQuery, SampleEntity.class);
//then
assertThat(sampleEntity,is(notNullValue()));
}
@Test
public void testBoost() {
//given
List<IndexQuery> indexQueries = new ArrayList<IndexQuery>();
//first document
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setRate(700);
sampleEntity1.setMessage("bar foo");
IndexQuery indexQuery1 = new IndexQuery();
indexQuery1.setId(documentId);
indexQuery1.setObject(sampleEntity1);
indexQueries.add(indexQuery1);
//second document
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setRate(800);
sampleEntity2.setMessage("foo");
IndexQuery indexQuery2 = new IndexQuery();
indexQuery2.setId(documentId2);
indexQuery2.setObject(sampleEntity2);
indexQueries.add(indexQuery2);
elasticsearchTemplate.bulkIndex(indexQueries);
elasticsearchTemplate.refresh(SampleEntity.class,true);
CriteriaQuery criteriaQuery = new CriteriaQuery(new Criteria("message").contains("foo").boost(1));
//when
Page<SampleEntity> page = elasticsearchTemplate.queryForPage(criteriaQuery, SampleEntity.class);
//then
assertThat(page.getTotalElements(),is(greaterThanOrEqualTo(1L)));
}
}

View File

@ -0,0 +1,59 @@
package org.springframework.data.elasticsearch.repositories;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.elasticsearch.SampleEntity;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.notNullValue;
import static org.junit.Assert.assertThat;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:custom-method-repository-test.xml")
public class CustomMethodRepositoryTest {
@Resource
private SampleCustomMethodRepository repository;
@Test
public void shouldExecuteCustomMethod(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setType("test");
sampleEntity.setMessage("some message");
repository.save(sampleEntity);
//when
Page<SampleEntity> page = repository.findByType("test", new PageRequest(1, 10));
//then
assertThat(page, is(notNullValue()));
assertThat(page.getTotalElements(), is(greaterThanOrEqualTo(1L)));
}
@Test
public void shouldExecuteCustomMethodWithQuery(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setType("test");
sampleEntity.setMessage("customQuery");
repository.save(sampleEntity);
//when
Page<SampleEntity> page = repository.findByMessage("customQuery", new PageRequest(1, 10));
//then
assertThat(page, is(notNullValue()));
assertThat(page.getTotalElements(), is(greaterThanOrEqualTo(1L)));
}
}

View File

@ -0,0 +1,343 @@
package org.springframework.data.elasticsearch.repositories;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.elasticsearch.SampleEntity;
import org.springframework.data.elasticsearch.core.query.SearchQuery;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import javax.annotation.Resource;
import java.util.Arrays;
import static org.apache.commons.lang.RandomStringUtils.randomNumeric;
import static org.elasticsearch.index.query.QueryBuilders.*;
import static org.hamcrest.Matchers.*;
import static org.junit.Assert.*;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:/repository-test.xml")
public class RepositoryTest {
@Resource
private SampleElasticsearchRepository repository;
@Test
public void shouldDoBulkIndexDocument(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity1 = new SampleEntity();
sampleEntity1.setId(documentId);
sampleEntity1.setMessage("some message");
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId);
sampleEntity2.setMessage("some message");
//when
repository.save(Arrays.asList(sampleEntity1, sampleEntity2));
//then
SampleEntity entityFromElasticSearch = repository.findOne(documentId);
assertThat(entityFromElasticSearch, is(notNullValue()));
}
@Test
public void shouldSaveDocument(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
//when
repository.save(sampleEntity);
//then
SampleEntity entityFromElasticSearch = repository.findOne(documentId);
assertThat(entityFromElasticSearch, is(notNullValue()));
}
@Test
public void shouldFindDocumentById(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
repository.save(sampleEntity);
//when
SampleEntity entityFromElasticSearch = repository.findOne(documentId);
//then
assertThat(entityFromElasticSearch, is(notNullValue()));
assertThat(sampleEntity, is((equalTo(sampleEntity))));
}
@Test
public void shouldReturnCountOfDocuments(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
repository.save(sampleEntity);
//when
Long count = repository.count();
//then
assertThat(count, is(greaterThanOrEqualTo(1L)));
}
@Test
public void shouldFindAllDocuments(){
//when
Iterable<SampleEntity> results = repository.findAll();
//then
assertThat(results, is(notNullValue()));
}
@Test
public void shouldDeleteDocument(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
repository.save(sampleEntity);
//when
repository.delete(documentId);
//then
SampleEntity entityFromElasticSearch = repository.findOne(documentId);
assertThat(entityFromElasticSearch, is(nullValue()));
}
@Test
public void shouldSearchDocumentsGivenSearchQuery(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some test message");
repository.save(sampleEntity);
SearchQuery query = new SearchQuery();
query.setElasticsearchQuery(termQuery("message", "test"));
//when
Page<SampleEntity> page = repository.search(query);
//then
assertThat(page, is(notNullValue()));
assertThat(page.getNumberOfElements(), is(greaterThanOrEqualTo(1)));
}
@Test
public void shouldSearchDocumentsGivenElasticsearchQuery(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
repository.save(sampleEntity);
//when
Page<SampleEntity> page = repository.search(termQuery("message", "world"), new PageRequest(0,50));
//then
assertThat(page, is(notNullValue()));
assertThat(page.getNumberOfElements(), is(greaterThanOrEqualTo(1)));
}
@Test
@Ignore
public void testFindAllByIdQuery(){
//todo : find solution for findAll(Iterable<Ids> ids)
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
repository.save(sampleEntity);
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("hello world.");
repository.save(sampleEntity2);
//when
Iterable<SampleEntity> sampleEntities=repository.findAll(Arrays.asList(documentId,documentId2));
//then
assertNotNull("sample entities cant be null..", sampleEntities);
}
@Test
public void testSaveIterableEntities(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("hello world.");
Iterable<SampleEntity> sampleEntities = Arrays.asList(sampleEntity,sampleEntity2);
//when
repository.save(sampleEntities);
//then
Page<SampleEntity> entities = repository.search(fieldQuery("id", documentId), new PageRequest(0, 50));
assertNotNull(entities);
}
@Test
public void testDocumentExistById(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
repository.save(sampleEntity);
//when
boolean exist = repository.exists(documentId);
//then
assertEquals(exist, true);
}
@Test
public void testSearchForGivenSearchQuery(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
repository.save(sampleEntity);
//when
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(fieldQuery("id",documentId));
Page<SampleEntity> sampleEntities= repository.search(searchQuery);
//then
assertThat(sampleEntities.getTotalElements(), equalTo(1L));
}
@Test
public void testDeleteAll(){
//when
repository.deleteAll();
//then
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(matchAllQuery());
Page<SampleEntity> sampleEntities= repository.search(searchQuery);
assertThat(sampleEntities.getTotalElements(), equalTo(0L));
}
@Test
public void testDeleteByEntity(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
repository.save(sampleEntity);
//when
repository.delete(sampleEntity);
//then
SearchQuery searchQuery = new SearchQuery();
searchQuery.setElasticsearchQuery(fieldQuery("id", documentId));
Page<SampleEntity> sampleEntities= repository.search(searchQuery);
assertThat(sampleEntities.getTotalElements(),equalTo(0L));
}
@Test
public void testSearchForReturnIterableEntities(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
repository.save(sampleEntity);
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("hello world.");
repository.save(sampleEntity2);
//when
Iterable<SampleEntity> sampleEntities=repository.search(fieldQuery("id",documentId));
//then
assertNotNull("sample entities cant be null..", sampleEntities);
}
@Test
public void testDeleteIterableEntities(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("hello world.");
repository.save(sampleEntity);
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("hello world.");
repository.save(sampleEntity);
Iterable<SampleEntity> sampleEntities = Arrays.asList(sampleEntity,sampleEntity2);
//when
repository.delete(sampleEntities);
//then
Page<SampleEntity> entities = repository.search(fieldQuery("id", documentId), new PageRequest(0,50));
assertThat(entities.getTotalElements(),equalTo(0L));
entities = repository.search(fieldQuery("id", documentId2), new PageRequest(0,50));
assertThat(entities.getTotalElements(), equalTo(0L));
}
@Test
public void testIndexEntity(){
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("some message");
//when
repository.index(sampleEntity);
//then
Page<SampleEntity> entities = repository.search(fieldQuery("id", documentId), new PageRequest(0,50));
assertThat(entities.getTotalElements(),equalTo(1L));
}
@Test
@Ignore("By default, the search request will fail if there is no mapping associated with a field. The ignore_unmapped option allows to ignore fields that have no mapping and not sort by them")
public void testFindBySort(){
//todo
//given
String documentId = randomNumeric(5);
SampleEntity sampleEntity = new SampleEntity();
sampleEntity.setId(documentId);
sampleEntity.setMessage("A. hello world.");
repository.save(sampleEntity);
String documentId2 = randomNumeric(5);
SampleEntity sampleEntity2 = new SampleEntity();
sampleEntity2.setId(documentId2);
sampleEntity2.setMessage("B.hello world.");
repository.save(sampleEntity2);
//when
Iterable<SampleEntity> sampleEntities=repository.findAll(new Sort(new Sort.Order(Sort.Direction.ASC,"message")));
//then
assertNotNull("sample entities cant be null..", sampleEntities);
}
}

View File

@ -0,0 +1,17 @@
package org.springframework.data.elasticsearch.repositories;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.elasticsearch.SampleEntity;
import org.springframework.data.elasticsearch.annotations.Query;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface SampleCustomMethodRepository extends ElasticsearchRepository<SampleEntity,String> {
Page<SampleEntity> findByType(String type, Pageable pageable);
@Query("{\"bool\" : {\"must\" : {\"field\" : {\"message\" : \"?0\"}}}}")
Page<SampleEntity> findByMessage(String message, Pageable pageable);
}

View File

@ -0,0 +1,8 @@
package org.springframework.data.elasticsearch.repositories;
import org.springframework.data.elasticsearch.SampleEntity;
import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
public interface SampleElasticsearchRepository extends ElasticsearchRepository<SampleEntity,String> {
}

View File

@ -0,0 +1,48 @@
package org.springframework.data.elasticsearch.repository.support;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.convert.ElasticsearchConverter;
import org.springframework.data.elasticsearch.core.convert.MappingElasticsearchConverter;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentEntity;
import org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty;
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
import org.springframework.data.mapping.context.MappingContext;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.core.RepositoryMetadata;
import org.springframework.data.repository.core.support.DefaultRepositoryMetadata;
import static org.mockito.Mockito.when;
@RunWith(MockitoJUnitRunner.class)
public class ElasticsearchRepositoryFactoryTest {
@Mock
private ElasticsearchOperations operations;
private ElasticsearchConverter converter;
private ElasticsearchRepositoryFactory factory;
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext= new SimpleElasticsearchMappingContext();
@Before
public void before(){
converter = new MappingElasticsearchConverter(mappingContext);
when(operations.getElasticsearchConverter()).thenReturn(converter);
factory = new ElasticsearchRepositoryFactory(operations);
}
@Test(expected = IllegalArgumentException.class)
public void shouldThrowExceptionGivenQueryDslRepository(){
//given
RepositoryMetadata metadata = new DefaultRepositoryMetadata(QueryDslPredicateExecutor.class);
//when
factory.getRepositoryBaseClass(metadata);
}
}

View File

@ -0,0 +1,19 @@
<?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.xsd">
<elasticsearch:node-client id="client" local="true"/>
<bean name="elasticsearchTemplate" class="org.springframework.data.elasticsearch.core.ElasticsearchTemplate">
<constructor-arg name="client" ref="client"/>
</bean>
<elasticsearch:transport-client id="transportClient" />
<elasticsearch:repositories base-package="org.springframework.data.elasticsearch.repositories"/>
</beans>