mirror of
https://github.com/spring-projects/spring-data-elasticsearch.git
synced 2025-05-31 09:12:11 +00:00
Adding missing files
This commit is contained in:
parent
05de948d20
commit
54a1f186d7
5
.gitignore
vendored
5
.gitignore
vendored
@ -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
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 "";
|
||||
}
|
@ -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 "";
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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"));
|
||||
}
|
||||
}
|
@ -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";
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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 };
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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>
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
@ -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()));
|
||||
}
|
||||
|
||||
}
|
@ -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()));
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
@ -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()));
|
||||
}
|
||||
}
|
@ -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()));
|
||||
}
|
||||
|
||||
}
|
@ -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)));
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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)));
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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> {
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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>
|
Loading…
x
Reference in New Issue
Block a user