Compare commits
44 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cef1fc7d77 | |||
| 9ddf4868ef | |||
| dde561a805 | |||
| 950c48a069 | |||
| df9954b3ef | |||
| 32d5f5dcb9 | |||
| 0191d69d94 | |||
| e7e0983ea5 | |||
| a299260a03 | |||
| 627d96cbfc | |||
| efa3b4d17e | |||
| f5d44ad755 | |||
| 5a50114b73 | |||
| 45a9384d4f | |||
| 789acdc3dc | |||
| 946a60d24d | |||
| 838776dd63 | |||
| b8324f9205 | |||
| 94d18e8111 | |||
| a1aa755253 | |||
| dfd9d962d3 | |||
| e1d3f6f160 | |||
| 7bb108c998 | |||
| d1b71f2e73 | |||
| 88fe60c7d4 | |||
| 9a0a931ce2 | |||
| 02f2171cb6 | |||
| 5d4cabae10 | |||
| 2632b69d12 | |||
| d30328f2e1 | |||
| 469455383f | |||
| cdbc832068 | |||
| 143a359eca | |||
| e58c43f391 | |||
| d66b2a6f63 | |||
| ba3eba5734 | |||
| 4a26af38c3 | |||
| 5ddb46c435 | |||
| d996406113 | |||
| 112600261d | |||
| 62a03a8fb7 | |||
| ac62aaf856 | |||
| 28629a6ede | |||
| 12cc5ced16 |
@@ -4,12 +4,12 @@
|
||||
|
||||
<groupId>org.springframework.data</groupId>
|
||||
<artifactId>spring-data-elasticsearch</artifactId>
|
||||
<version>3.1.0.M3</version>
|
||||
<version>3.1.2.RELEASE</version>
|
||||
|
||||
<parent>
|
||||
<groupId>org.springframework.data.build</groupId>
|
||||
<artifactId>spring-data-parent</artifactId>
|
||||
<version>2.1.0.M3</version>
|
||||
<version>2.1.2.RELEASE</version>
|
||||
</parent>
|
||||
|
||||
<name>Spring Data Elasticsearch</name>
|
||||
@@ -21,7 +21,7 @@
|
||||
<commonslang>2.6</commonslang>
|
||||
<elasticsearch>6.2.2</elasticsearch>
|
||||
<log4j>2.9.1</log4j>
|
||||
<springdata.commons>2.1.0.M3</springdata.commons>
|
||||
<springdata.commons>2.1.2.RELEASE</springdata.commons>
|
||||
<java-module-name>spring.data.elasticsearch</java-module-name>
|
||||
</properties>
|
||||
|
||||
@@ -56,6 +56,7 @@
|
||||
<groupId>commons-lang</groupId>
|
||||
<artifactId>commons-lang</artifactId>
|
||||
<version>${commonslang}</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- JODA Time -->
|
||||
@@ -66,12 +67,6 @@
|
||||
</dependency>
|
||||
|
||||
<!-- Elasticsearch -->
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch</groupId>
|
||||
<artifactId>elasticsearch</artifactId>
|
||||
<version>${elasticsearch}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.elasticsearch.client</groupId>
|
||||
<artifactId>transport</artifactId>
|
||||
@@ -221,8 +216,8 @@
|
||||
|
||||
<repositories>
|
||||
<repository>
|
||||
<id>spring-libs-milestone</id>
|
||||
<url>https://repo.spring.io/libs-milestone</url>
|
||||
<id>spring-libs-release</id>
|
||||
<url>https://repo.spring.io/libs-release</url>
|
||||
</repository>
|
||||
</repositories>
|
||||
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package org.springframework.data.elasticsearch.annotations;
|
||||
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Inherited;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
|
||||
/**
|
||||
* Specifies that this field is used for storing the document score.
|
||||
*
|
||||
* @author Sascha Woo
|
||||
* @since 3.1
|
||||
*/
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.FIELD)
|
||||
@Documented
|
||||
@Inherited
|
||||
@ReadOnlyProperty
|
||||
public @interface Score {}
|
||||
@@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Copyright 2018 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.client;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.Arrays;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.springframework.data.util.Streamable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Value object to represent a list of cluster nodes.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 3.1
|
||||
*/
|
||||
class ClusterNodes implements Streamable<TransportAddress> {
|
||||
|
||||
public static ClusterNodes DEFAULT = ClusterNodes.of("127.0.0.1:9300");
|
||||
|
||||
private static final String COLON = ":";
|
||||
private static final String COMMA = ",";
|
||||
|
||||
private final List<TransportAddress> clusterNodes;
|
||||
|
||||
/**
|
||||
* Creates a new {@link ClusterNodes} by parsing the given source.
|
||||
*
|
||||
* @param source must not be {@literal null} or empty.
|
||||
*/
|
||||
private ClusterNodes(String source) {
|
||||
|
||||
Assert.hasText(source, "Cluster nodes source must not be null or empty!");
|
||||
|
||||
String[] nodes = StringUtils.delimitedListToStringArray(source, COMMA);
|
||||
|
||||
this.clusterNodes = Arrays.stream(nodes).map(node -> {
|
||||
|
||||
String[] segments = StringUtils.delimitedListToStringArray(node, COLON);
|
||||
|
||||
Assert.isTrue(segments.length == 2,
|
||||
() -> String.format("Invalid cluster node %s in %s! Must be in the format host:port!", node, source));
|
||||
|
||||
String host = segments[0].trim();
|
||||
String port = segments[1].trim();
|
||||
|
||||
Assert.hasText(host, () -> String.format("No host name given cluster node %s!", node));
|
||||
Assert.hasText(port, () -> String.format("No port given in cluster node %s!", node));
|
||||
|
||||
return new TransportAddress(toInetAddress(host), Integer.valueOf(port));
|
||||
|
||||
}).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new {@link ClusterNodes} by parsing the given source. The expected format is a comma separated list of
|
||||
* host-port-combinations separated by a colon: {@code host:port,host:port,…}.
|
||||
*
|
||||
* @param source must not be {@literal null} or empty.
|
||||
* @return
|
||||
*/
|
||||
public static ClusterNodes of(String source) {
|
||||
return new ClusterNodes(source);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see java.lang.Iterable#iterator()
|
||||
*/
|
||||
@Override
|
||||
public Iterator<TransportAddress> iterator() {
|
||||
return clusterNodes.iterator();
|
||||
}
|
||||
|
||||
private static InetAddress toInetAddress(String host) {
|
||||
|
||||
try {
|
||||
return InetAddress.getByName(host);
|
||||
} catch (UnknownHostException o_O) {
|
||||
throw new IllegalArgumentException(o_O);
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-2
@@ -18,7 +18,6 @@ package org.springframework.data.elasticsearch.client;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collection;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.client.Client;
|
||||
import org.elasticsearch.client.node.NodeClient;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
@@ -31,6 +30,8 @@ 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.StringUtils;
|
||||
|
||||
import static java.util.Arrays.*;
|
||||
|
||||
/**
|
||||
@@ -95,7 +96,7 @@ public class NodeClientFactoryBean implements FactoryBean<Client>, InitializingB
|
||||
}
|
||||
|
||||
private Settings loadConfig() throws IOException {
|
||||
if (StringUtils.isNotBlank(pathConfiguration)) {
|
||||
if (!StringUtils.isEmpty(pathConfiguration)) {
|
||||
InputStream stream = getClass().getClassLoader().getResourceAsStream(pathConfiguration);
|
||||
if (stream != null) {
|
||||
return Settings.builder().loadFromStream(pathConfiguration, getClass().getClassLoader().getResourceAsStream(pathConfiguration), false).build();
|
||||
|
||||
+9
-20
@@ -15,21 +15,16 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.client;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.*;
|
||||
|
||||
import java.net.InetAddress;
|
||||
import java.util.Properties;
|
||||
|
||||
import org.elasticsearch.client.transport.TransportClient;
|
||||
import org.elasticsearch.common.settings.Settings;
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.elasticsearch.transport.client.PreBuiltTransportClient;
|
||||
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 org.springframework.beans.factory.InitializingBean;
|
||||
|
||||
/**
|
||||
* TransportClientFactoryBean
|
||||
@@ -39,12 +34,12 @@ import org.springframework.util.Assert;
|
||||
* @author Jakub Vavrik
|
||||
* @author Piotr Betkier
|
||||
* @author Ilkang Na
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
public class TransportClientFactoryBean implements FactoryBean<TransportClient>, InitializingBean, DisposableBean {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(TransportClientFactoryBean.class);
|
||||
private String clusterNodes = "127.0.0.1:9300";
|
||||
private ClusterNodes clusterNodes = ClusterNodes.of("127.0.0.1:9300");
|
||||
private String clusterName = "elasticsearch";
|
||||
private Boolean clientTransportSniff = true;
|
||||
private Boolean clientIgnoreClusterName = Boolean.FALSE;
|
||||
@@ -52,8 +47,6 @@ public class TransportClientFactoryBean implements FactoryBean<TransportClient>,
|
||||
private String clientNodesSamplerInterval = "5s";
|
||||
private TransportClient client;
|
||||
private Properties properties;
|
||||
static final String COLON = ":";
|
||||
static final String COMMA = ",";
|
||||
|
||||
@Override
|
||||
public void destroy() throws Exception {
|
||||
@@ -90,15 +83,11 @@ public class TransportClientFactoryBean implements FactoryBean<TransportClient>,
|
||||
protected void buildClient() throws Exception {
|
||||
|
||||
client = new PreBuiltTransportClient(settings());
|
||||
Assert.hasText(clusterNodes, "[Assertion failed] clusterNodes settings missing.");
|
||||
for (String clusterNode : split(clusterNodes, COMMA)) {
|
||||
String hostName = substringBeforeLast(clusterNode, COLON);
|
||||
String port = substringAfterLast(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 TransportAddress(InetAddress.getByName(hostName), Integer.valueOf(port)));
|
||||
}
|
||||
|
||||
clusterNodes.stream() //
|
||||
.peek(it -> logger.info("Adding transport node : " + it.toString())) //
|
||||
.forEach(client::addTransportAddress);
|
||||
|
||||
client.connectedNodes();
|
||||
}
|
||||
|
||||
@@ -122,7 +111,7 @@ public class TransportClientFactoryBean implements FactoryBean<TransportClient>,
|
||||
}
|
||||
|
||||
public void setClusterNodes(String clusterNodes) {
|
||||
this.clusterNodes = clusterNodes;
|
||||
this.clusterNodes = ClusterNodes.of(clusterNodes);
|
||||
}
|
||||
|
||||
public void setClusterName(String clusterName) {
|
||||
|
||||
@@ -15,11 +15,11 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.*;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import org.springframework.data.elasticsearch.ElasticsearchException;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
@@ -29,11 +29,14 @@ public abstract class AbstractResultMapper implements ResultsMapper {
|
||||
private EntityMapper entityMapper;
|
||||
|
||||
public AbstractResultMapper(EntityMapper entityMapper) {
|
||||
|
||||
Assert.notNull(entityMapper, "EntityMapper must not be null!");
|
||||
|
||||
this.entityMapper = entityMapper;
|
||||
}
|
||||
|
||||
public <T> T mapEntity(String source, Class<T> clazz) {
|
||||
if (isBlank(source)) {
|
||||
if (StringUtils.isEmpty(source)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
|
||||
+110
-20
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -16,52 +16,142 @@
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.*;
|
||||
import com.fasterxml.jackson.databind.*;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.elasticsearch.core.geo.CustomGeoModule;
|
||||
import org.springframework.data.geo.*;
|
||||
import java.util.List;
|
||||
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 com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import com.fasterxml.jackson.core.Version;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||
import com.fasterxml.jackson.databind.BeanDescription;
|
||||
import com.fasterxml.jackson.databind.DeserializationFeature;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.SerializationConfig;
|
||||
import com.fasterxml.jackson.databind.module.SimpleModule;
|
||||
|
||||
import com.fasterxml.jackson.databind.ser.BeanPropertyWriter;
|
||||
import com.fasterxml.jackson.databind.ser.BeanSerializerModifier;
|
||||
|
||||
/**
|
||||
* DocumentMapper using jackson
|
||||
* EntityMapper based on a Jackson {@link ObjectMapper}.
|
||||
*
|
||||
* @author Artur Konczak
|
||||
* @author Petar Tahchiev
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultEntityMapper implements EntityMapper {
|
||||
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
public DefaultEntityMapper() {
|
||||
/**
|
||||
* Creates a new {@link DefaultEntityMapper} using the given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public DefaultEntityMapper(
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> context) {
|
||||
|
||||
Assert.notNull(context, "MappingContext must not be null!");
|
||||
|
||||
objectMapper = new ObjectMapper();
|
||||
|
||||
objectMapper.registerModule(new SpringDataElasticsearchModule(context));
|
||||
objectMapper.registerModule(new CustomGeoModule());
|
||||
|
||||
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
||||
objectMapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
|
||||
objectMapper.registerModule(new CustomGeoModule());
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.EntityMapper#mapToString(java.lang.Object)
|
||||
*/
|
||||
@Override
|
||||
public String mapToString(Object object) throws IOException {
|
||||
return objectMapper.writeValueAsString(object);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.EntityMapper#mapToObject(java.lang.String, java.lang.Class)
|
||||
*/
|
||||
@Override
|
||||
public <T> T mapToObject(String source, Class<T> clazz) throws IOException {
|
||||
return objectMapper.readValue(source, clazz);
|
||||
}
|
||||
|
||||
/**
|
||||
* A simple Jackson module to register the {@link SpringDataSerializerModifier}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 3.1
|
||||
*/
|
||||
private static class SpringDataElasticsearchModule extends SimpleModule {
|
||||
|
||||
private static final long serialVersionUID = -9168968092458058966L;
|
||||
|
||||
/**
|
||||
* Creates a new {@link SpringDataElasticsearchModule} using the given {@link MappingContext}.
|
||||
*
|
||||
* @param context must not be {@literal null}.
|
||||
*/
|
||||
public SpringDataElasticsearchModule(
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> context) {
|
||||
|
||||
Assert.notNull(context, "MappingContext must not be null!");
|
||||
|
||||
setSerializerModifier(new SpringDataSerializerModifier(context));
|
||||
}
|
||||
|
||||
/**
|
||||
* A {@link BeanSerializerModifier} that will drop properties annotated with {@link ReadOnlyProperty} for
|
||||
* serialization.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
* @since 3.1
|
||||
*/
|
||||
private static class SpringDataSerializerModifier extends BeanSerializerModifier {
|
||||
|
||||
private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> context;
|
||||
|
||||
public SpringDataSerializerModifier(
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> context) {
|
||||
|
||||
Assert.notNull(context, "MappingContext must not be null!");
|
||||
|
||||
this.context = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see com.fasterxml.jackson.databind.ser.BeanSerializerModifier#changeProperties(com.fasterxml.jackson.databind.SerializationConfig, com.fasterxml.jackson.databind.BeanDescription, java.util.List)
|
||||
*/
|
||||
@Override
|
||||
public List<BeanPropertyWriter> changeProperties(SerializationConfig config, BeanDescription description,
|
||||
List<BeanPropertyWriter> properties) {
|
||||
|
||||
Class<?> type = description.getBeanClass();
|
||||
ElasticsearchPersistentEntity<?> entity = context.getPersistentEntity(type);
|
||||
|
||||
if (entity == null) {
|
||||
return super.changeProperties(config, description, properties);
|
||||
}
|
||||
|
||||
List<BeanPropertyWriter> result = new ArrayList<>(properties.size());
|
||||
|
||||
for (BeanPropertyWriter beanPropertyWriter : properties) {
|
||||
|
||||
ElasticsearchPersistentProperty property = entity.getPersistentProperty(beanPropertyWriter.getName());
|
||||
|
||||
if (property != null && property.isWritable()) {
|
||||
result.add(beanPropertyWriter);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+48
-16
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2014-2017 the original author or authors.
|
||||
* Copyright 2014-2018 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.
|
||||
@@ -23,7 +23,6 @@ import java.util.Collection;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.action.get.GetResponse;
|
||||
import org.elasticsearch.action.get.MultiGetItemResponse;
|
||||
import org.elasticsearch.action.get.MultiGetResponse;
|
||||
@@ -38,12 +37,14 @@ import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
||||
import org.springframework.data.elasticsearch.core.aggregation.impl.AggregatedPageImpl;
|
||||
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.util.Assert;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonEncoding;
|
||||
import com.fasterxml.jackson.core.JsonFactory;
|
||||
import com.fasterxml.jackson.core.JsonGenerator;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
@@ -53,51 +54,67 @@ import com.fasterxml.jackson.core.JsonGenerator;
|
||||
* @author Chris White
|
||||
* @author Mark Paluch
|
||||
* @author Ilkang Na
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public class DefaultResultMapper extends AbstractResultMapper {
|
||||
|
||||
private MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;
|
||||
private final MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext;
|
||||
|
||||
public DefaultResultMapper() {
|
||||
super(new DefaultEntityMapper());
|
||||
this(new SimpleElasticsearchMappingContext());
|
||||
}
|
||||
|
||||
public DefaultResultMapper(MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext) {
|
||||
super(new DefaultEntityMapper());
|
||||
|
||||
super(new DefaultEntityMapper(mappingContext));
|
||||
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
public DefaultResultMapper(EntityMapper entityMapper) {
|
||||
super(entityMapper);
|
||||
this(new SimpleElasticsearchMappingContext(), entityMapper);
|
||||
}
|
||||
|
||||
public DefaultResultMapper(
|
||||
MappingContext<? extends ElasticsearchPersistentEntity<?>, ElasticsearchPersistentProperty> mappingContext,
|
||||
EntityMapper entityMapper) {
|
||||
|
||||
super(entityMapper);
|
||||
|
||||
Assert.notNull(mappingContext, "MappingContext must not be null!");
|
||||
|
||||
this.mappingContext = mappingContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||
|
||||
long totalHits = response.getHits().getTotalHits();
|
||||
float maxScore = response.getHits().getMaxScore();
|
||||
|
||||
List<T> results = new ArrayList<>();
|
||||
for (SearchHit hit : response.getHits()) {
|
||||
if (hit != null) {
|
||||
T result = null;
|
||||
if (StringUtils.isNotBlank(hit.getSourceAsString())) {
|
||||
if (!StringUtils.isEmpty(hit.getSourceAsString())) {
|
||||
result = mapEntity(hit.getSourceAsString(), clazz);
|
||||
} else {
|
||||
result = mapEntity(hit.getFields().values(), clazz);
|
||||
}
|
||||
|
||||
setPersistentEntityId(result, hit.getId(), clazz);
|
||||
setPersistentEntityVersion(result, hit.getVersion(), clazz);
|
||||
setPersistentEntityScore(result, hit.getScore(), clazz);
|
||||
|
||||
populateScriptFields(result, hit);
|
||||
results.add(result);
|
||||
}
|
||||
}
|
||||
|
||||
return new AggregatedPageImpl<T>(results, pageable, totalHits, response.getAggregations(), response.getScrollId());
|
||||
return new AggregatedPageImpl<T>(results, pageable, totalHits, response.getAggregations(), response.getScrollId(),
|
||||
maxScore);
|
||||
}
|
||||
|
||||
private <T> void populateScriptFields(T result, SearchHit hit) {
|
||||
@@ -112,8 +129,8 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
||||
try {
|
||||
field.set(result, searchHitField.getValue());
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new ElasticsearchException("failed to set scripted field: " + name + " with value: "
|
||||
+ searchHitField.getValue(), e);
|
||||
throw new ElasticsearchException(
|
||||
"failed to set scripted field: " + name + " with value: " + searchHitField.getValue(), e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new ElasticsearchException("failed to access scripted field: " + name, e);
|
||||
}
|
||||
@@ -177,9 +194,9 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
||||
}
|
||||
|
||||
private <T> void setPersistentEntityId(T result, String id, Class<T> clazz) {
|
||||
|
||||
if (mappingContext != null && clazz.isAnnotationPresent(Document.class)) {
|
||||
|
||||
|
||||
if (clazz.isAnnotationPresent(Document.class)) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getRequiredPersistentEntity(clazz);
|
||||
ElasticsearchPersistentProperty idProperty = persistentEntity.getIdProperty();
|
||||
|
||||
@@ -187,13 +204,13 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
||||
if (idProperty != null && idProperty.getType().isAssignableFrom(String.class)) {
|
||||
persistentEntity.getPropertyAccessor(result).setProperty(idProperty, id);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void setPersistentEntityVersion(T result, long version, Class<T> clazz) {
|
||||
if (mappingContext != null && clazz.isAnnotationPresent(Document.class)) {
|
||||
|
||||
|
||||
if (clazz.isAnnotationPresent(Document.class)) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> persistentEntity = mappingContext.getPersistentEntity(clazz);
|
||||
ElasticsearchPersistentProperty versionProperty = persistentEntity.getVersionProperty();
|
||||
|
||||
@@ -206,4 +223,19 @@ public class DefaultResultMapper extends AbstractResultMapper {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void setPersistentEntityScore(T result, float score, Class<T> clazz) {
|
||||
|
||||
if (clazz.isAnnotationPresent(Document.class)) {
|
||||
|
||||
ElasticsearchPersistentEntity<?> entity = mappingContext.getRequiredPersistentEntity(clazz);
|
||||
|
||||
if (!entity.hasScoreProperty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
entity.getPropertyAccessor(result) //
|
||||
.setProperty(entity.getScoreProperty(), score);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+98
-52
@@ -15,20 +15,23 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static org.apache.commons.lang.StringUtils.isBlank;
|
||||
import static org.apache.commons.lang.StringUtils.isNotBlank;
|
||||
import static org.elasticsearch.client.Requests.indicesExistsRequest;
|
||||
import static org.elasticsearch.client.Requests.refreshRequest;
|
||||
import static org.elasticsearch.index.VersionType.EXTERNAL;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.moreLikeThisQuery;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.wrapperQuery;
|
||||
import static org.springframework.data.elasticsearch.core.MappingBuilder.buildMapping;
|
||||
import static org.springframework.util.CollectionUtils.isEmpty;
|
||||
import static org.elasticsearch.client.Requests.*;
|
||||
import static org.elasticsearch.index.VersionType.*;
|
||||
import static org.elasticsearch.index.query.QueryBuilders.*;
|
||||
import static org.springframework.data.elasticsearch.core.MappingBuilder.*;
|
||||
import static org.springframework.util.CollectionUtils.*;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStreamReader;
|
||||
import java.util.*;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.NoSuchElementException;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.elasticsearch.action.ActionFuture;
|
||||
@@ -49,6 +52,7 @@ import org.elasticsearch.action.get.MultiGetResponse;
|
||||
import org.elasticsearch.action.index.IndexRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchRequestBuilder;
|
||||
import org.elasticsearch.action.search.SearchResponse;
|
||||
import org.elasticsearch.action.search.SearchScrollRequestBuilder;
|
||||
import org.elasticsearch.action.update.UpdateRequestBuilder;
|
||||
import org.elasticsearch.action.update.UpdateResponse;
|
||||
import org.elasticsearch.client.Client;
|
||||
@@ -67,6 +71,7 @@ import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.sort.FieldSortBuilder;
|
||||
import org.elasticsearch.search.sort.ScoreSortBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilders;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
@@ -93,9 +98,24 @@ import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
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.elasticsearch.core.query.*;
|
||||
import org.springframework.data.elasticsearch.core.query.AliasQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.DeleteQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.FetchSourceFilter;
|
||||
import org.springframework.data.elasticsearch.core.query.GetQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexBoost;
|
||||
import org.springframework.data.elasticsearch.core.query.IndexQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.MoreLikeThisQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
|
||||
import org.springframework.data.elasticsearch.core.query.Query;
|
||||
import org.springframework.data.elasticsearch.core.query.ScriptField;
|
||||
import org.springframework.data.elasticsearch.core.query.SearchQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.SourceFilter;
|
||||
import org.springframework.data.elasticsearch.core.query.StringQuery;
|
||||
import org.springframework.data.elasticsearch.core.query.UpdateQuery;
|
||||
import org.springframework.data.util.CloseableIterator;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* ElasticsearchTemplate
|
||||
@@ -114,10 +134,14 @@ import org.springframework.util.Assert;
|
||||
* @author Alen Turkovic
|
||||
* @author Sascha Woo
|
||||
* @author Ted Liang
|
||||
* @author Jean-Baptiste Nizet
|
||||
*/
|
||||
public class ElasticsearchTemplate implements ElasticsearchOperations, ApplicationContextAware {
|
||||
|
||||
private static final Logger logger = LoggerFactory.getLogger(ElasticsearchTemplate.class);
|
||||
private static final Logger QUERY_LOGGER = LoggerFactory.getLogger("org.springframework.data.elasticsearch.core.QUERY");
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(ElasticsearchTemplate.class);
|
||||
private static final String FIELD_SCORE = "_score";
|
||||
|
||||
private Client client;
|
||||
private ElasticsearchConverter elasticsearchConverter;
|
||||
private ResultsMapper resultsMapper;
|
||||
@@ -181,13 +205,13 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
public <T> boolean putMapping(Class<T> clazz) {
|
||||
if (clazz.isAnnotationPresent(Mapping.class)) {
|
||||
String mappingPath = clazz.getAnnotation(Mapping.class).mappingPath();
|
||||
if (isNotBlank(mappingPath)) {
|
||||
if (!StringUtils.isEmpty(mappingPath)) {
|
||||
String mappings = readFileFromClasspath(mappingPath);
|
||||
if (isNotBlank(mappings)) {
|
||||
if (!StringUtils.isEmpty(mappings)) {
|
||||
return putMapping(clazz, mappings);
|
||||
}
|
||||
} else {
|
||||
logger.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
|
||||
LOGGER.info("mappingPath in @Mapping has to be defined. Building mappings using @Field");
|
||||
}
|
||||
}
|
||||
ElasticsearchPersistentEntity<T> persistentEntity = getPersistentEntityFor(clazz);
|
||||
@@ -318,7 +342,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
if (query.getFilter() != null) {
|
||||
request.setPostFilter(query.getFilter());
|
||||
}
|
||||
SearchResponse response = getSearchResponse(request.execute());
|
||||
SearchResponse response = getSearchResponse(request);
|
||||
return extractIds(response);
|
||||
}
|
||||
|
||||
@@ -341,11 +365,8 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
|
||||
if (elasticsearchFilter != null)
|
||||
searchRequestBuilder.setPostFilter(elasticsearchFilter);
|
||||
if (logger.isDebugEnabled()) {
|
||||
logger.debug("doSearch query:\n" + searchRequestBuilder.toString());
|
||||
}
|
||||
|
||||
SearchResponse response = getSearchResponse(searchRequestBuilder.execute());
|
||||
SearchResponse response = getSearchResponse(searchRequestBuilder);
|
||||
return resultsMapper.mapResults(response, clazz, criteriaQuery.getPageable());
|
||||
}
|
||||
|
||||
@@ -356,7 +377,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
|
||||
@Override
|
||||
public <T> Page<T> queryForPage(StringQuery query, Class<T> clazz, SearchResultMapper mapper) {
|
||||
SearchResponse response = getSearchResponse(prepareSearch(query, clazz).setQuery(wrapperQuery(query.getSource())).execute());
|
||||
SearchResponse response = getSearchResponse(prepareSearch(query, clazz).setQuery(wrapperQuery(query.getSource())));
|
||||
return mapper.mapResults(response, clazz, query.getPageable());
|
||||
}
|
||||
|
||||
@@ -567,9 +588,9 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
}
|
||||
|
||||
private UpdateRequestBuilder prepareUpdate(UpdateQuery query) {
|
||||
String indexName = isNotBlank(query.getIndexName()) ? query.getIndexName()
|
||||
String indexName = !StringUtils.isEmpty(query.getIndexName()) ? query.getIndexName()
|
||||
: getPersistentEntityFor(query.getClazz()).getIndexName();
|
||||
String type = isNotBlank(query.getType()) ? query.getType()
|
||||
String type = !StringUtils.isEmpty(query.getType()) ? query.getType()
|
||||
: getPersistentEntityFor(query.getClazz()).getIndexType();
|
||||
Assert.notNull(indexName, "No index defined for Query");
|
||||
Assert.notNull(type, "No type define for Query");
|
||||
@@ -669,9 +690,9 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
@Override
|
||||
public <T> void delete(DeleteQuery deleteQuery, Class<T> clazz) {
|
||||
|
||||
String indexName = isNotBlank(deleteQuery.getIndex()) ? deleteQuery.getIndex()
|
||||
String indexName = !StringUtils.isEmpty(deleteQuery.getIndex()) ? deleteQuery.getIndex()
|
||||
: getPersistentEntityFor(clazz).getIndexName();
|
||||
String typeName = isNotBlank(deleteQuery.getType()) ? deleteQuery.getType()
|
||||
String typeName = !StringUtils.isEmpty(deleteQuery.getType()) ? deleteQuery.getType()
|
||||
: getPersistentEntityFor(clazz).getIndexType();
|
||||
Integer pageSize = deleteQuery.getPageSize() != null ? deleteQuery.getPageSize() : 1000;
|
||||
Long scrollTimeInMillis = deleteQuery.getScrollTimeInMillis() != null ? deleteQuery.getScrollTimeInMillis()
|
||||
@@ -772,7 +793,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
requestBuilder.setPostFilter(elasticsearchFilter);
|
||||
}
|
||||
|
||||
return getSearchResponse(requestBuilder.execute());
|
||||
return getSearchResponse(requestBuilder);
|
||||
}
|
||||
|
||||
private SearchResponse doScroll(SearchRequestBuilder requestBuilder, SearchQuery searchQuery) {
|
||||
@@ -784,7 +805,7 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
requestBuilder.setPostFilter(searchQuery.getFilter());
|
||||
}
|
||||
|
||||
return getSearchResponse(requestBuilder.setQuery(searchQuery.getQuery()).execute());
|
||||
return getSearchResponse(requestBuilder.setQuery(searchQuery.getQuery()));
|
||||
}
|
||||
|
||||
public <T> Page<T> startScroll(long scrollTimeInMillis, SearchQuery searchQuery, Class<T> clazz) {
|
||||
@@ -828,8 +849,8 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
public <T> Page<T> moreLikeThis(MoreLikeThisQuery query, Class<T> clazz) {
|
||||
|
||||
ElasticsearchPersistentEntity persistentEntity = getPersistentEntityFor(clazz);
|
||||
String indexName = isNotBlank(query.getIndexName()) ? query.getIndexName() : persistentEntity.getIndexName();
|
||||
String type = isNotBlank(query.getType()) ? query.getType() : persistentEntity.getIndexType();
|
||||
String indexName = !StringUtils.isEmpty(query.getIndexName()) ? query.getIndexName() : persistentEntity.getIndexName();
|
||||
String type = !StringUtils.isEmpty(query.getType()) ? query.getType() : persistentEntity.getIndexType();
|
||||
|
||||
Assert.notNull(indexName, "No 'indexName' defined for MoreLikeThisQuery");
|
||||
Assert.notNull(type, "No 'type' defined for MoreLikeThisQuery");
|
||||
@@ -885,8 +906,11 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
}
|
||||
}
|
||||
|
||||
if (searchQuery.getHighlightFields() != null) {
|
||||
HighlightBuilder highlightBuilder = new HighlightBuilder();
|
||||
if (searchQuery.getHighlightFields() != null || searchQuery.getHighlightBuilder() != null) {
|
||||
HighlightBuilder highlightBuilder = searchQuery.getHighlightBuilder();
|
||||
if (highlightBuilder == null) {
|
||||
highlightBuilder = new HighlightBuilder();
|
||||
}
|
||||
for (HighlightBuilder.Field highlightField : searchQuery.getHighlightFields()) {
|
||||
highlightBuilder.field(highlightField);
|
||||
}
|
||||
@@ -910,7 +934,16 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
searchRequest.addAggregation(aggregatedFacet.getFacet());
|
||||
}
|
||||
}
|
||||
return getSearchResponse(searchRequest.setQuery(searchQuery.getQuery()).execute());
|
||||
return getSearchResponse(searchRequest.setQuery(searchQuery.getQuery()));
|
||||
}
|
||||
|
||||
private SearchResponse getSearchResponse(SearchRequestBuilder requestBuilder) {
|
||||
|
||||
if (QUERY_LOGGER.isDebugEnabled()) {
|
||||
QUERY_LOGGER.debug(requestBuilder.toString());
|
||||
}
|
||||
|
||||
return getSearchResponse(requestBuilder.execute());
|
||||
}
|
||||
|
||||
private SearchResponse getSearchResponse(ActionFuture<SearchResponse> response) {
|
||||
@@ -924,13 +957,13 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
private <T> boolean createIndexWithSettings(Class<T> clazz) {
|
||||
if (clazz.isAnnotationPresent(Setting.class)) {
|
||||
String settingPath = clazz.getAnnotation(Setting.class).settingPath();
|
||||
if (isNotBlank(settingPath)) {
|
||||
if (!StringUtils.isEmpty(settingPath)) {
|
||||
String settings = readFileFromClasspath(settingPath);
|
||||
if (isNotBlank(settings)) {
|
||||
if (!StringUtils.isEmpty(settings)) {
|
||||
return createIndex(getPersistentEntityFor(clazz).getIndexName(), settings);
|
||||
}
|
||||
} else {
|
||||
logger.info("settingPath in @Setting has to be defined. Using default instead.");
|
||||
LOGGER.info("settingPath in @Setting has to be defined. Using default instead.");
|
||||
}
|
||||
}
|
||||
return createIndex(getPersistentEntityFor(clazz).getIndexName(), getDefaultSettings(getPersistentEntityFor(clazz)));
|
||||
@@ -991,7 +1024,8 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
SearchRequestBuilder searchRequestBuilder = client.prepareSearch(toArray(query.getIndices()))
|
||||
.setSearchType(query.getSearchType())
|
||||
.setTypes(toArray(query.getTypes()))
|
||||
.setVersion(true);
|
||||
.setVersion(true)
|
||||
.setTrackScores(query.getTrackScores());
|
||||
|
||||
if (query.getSourceFilter() != null) {
|
||||
SourceFilter sourceFilter = query.getSourceFilter();
|
||||
@@ -1014,15 +1048,27 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
|
||||
if (query.getSort() != null) {
|
||||
for (Sort.Order order : query.getSort()) {
|
||||
FieldSortBuilder sort = SortBuilders.fieldSort(order.getProperty())
|
||||
.order(order.getDirection().isDescending() ? SortOrder.DESC : SortOrder.ASC);
|
||||
if (order.getNullHandling() == Sort.NullHandling.NULLS_FIRST) {
|
||||
sort.missing("_first");
|
||||
SortOrder sortOrder = order.getDirection().isDescending() ? SortOrder.DESC : SortOrder.ASC;
|
||||
|
||||
if (FIELD_SCORE.equals(order.getProperty())) {
|
||||
ScoreSortBuilder sort = SortBuilders //
|
||||
.scoreSort() //
|
||||
.order(sortOrder);
|
||||
|
||||
searchRequestBuilder.addSort(sort);
|
||||
} else {
|
||||
FieldSortBuilder sort = SortBuilders //
|
||||
.fieldSort(order.getProperty()) //
|
||||
.order(sortOrder);
|
||||
|
||||
if (order.getNullHandling() == Sort.NullHandling.NULLS_FIRST) {
|
||||
sort.missing("_first");
|
||||
} else if (order.getNullHandling() == Sort.NullHandling.NULLS_LAST) {
|
||||
sort.missing("_last");
|
||||
}
|
||||
|
||||
searchRequestBuilder.addSort(sort);
|
||||
}
|
||||
else if (order.getNullHandling() == Sort.NullHandling.NULLS_LAST) {
|
||||
sort.missing("_last");
|
||||
}
|
||||
searchRequestBuilder.addSort(sort);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1034,16 +1080,16 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
|
||||
private IndexRequestBuilder prepareIndex(IndexQuery query) {
|
||||
try {
|
||||
String indexName = isBlank(query.getIndexName())
|
||||
String indexName = StringUtils.isEmpty(query.getIndexName())
|
||||
? retrieveIndexNameFromPersistentEntity(query.getObject().getClass())[0]
|
||||
: query.getIndexName();
|
||||
String type = isBlank(query.getType()) ? retrieveTypeFromPersistentEntity(query.getObject().getClass())[0]
|
||||
String type = StringUtils.isEmpty(query.getType()) ? retrieveTypeFromPersistentEntity(query.getObject().getClass())[0]
|
||||
: query.getType();
|
||||
|
||||
IndexRequestBuilder indexRequestBuilder = null;
|
||||
|
||||
if (query.getObject() != null) {
|
||||
String id = isBlank(query.getId()) ? getPersistentEntityId(query.getObject()) : query.getId();
|
||||
String id = StringUtils.isEmpty(query.getId()) ? getPersistentEntityId(query.getObject()) : query.getId();
|
||||
// If we have a query id and a document id, do not ask ES to generate one.
|
||||
if (id != null) {
|
||||
indexRequestBuilder = client.prepareIndex(indexName, type, id);
|
||||
@@ -1096,11 +1142,11 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
aliasAction.filter(query.getFilterBuilder());
|
||||
} else if (query.getFilter() != null) {
|
||||
aliasAction.filter(query.getFilter());
|
||||
} else if (isNotBlank(query.getRouting())) {
|
||||
} else if (!StringUtils.isEmpty(query.getRouting())) {
|
||||
aliasAction.routing(query.getRouting());
|
||||
} else if (isNotBlank(query.getSearchRouting())) {
|
||||
} else if (!StringUtils.isEmpty(query.getSearchRouting())) {
|
||||
aliasAction.searchRouting(query.getSearchRouting());
|
||||
} else if (isNotBlank(query.getIndexRouting())) {
|
||||
} else if (!StringUtils.isEmpty(query.getIndexRouting())) {
|
||||
aliasAction.indexRouting(query.getIndexRouting());
|
||||
}
|
||||
return client.admin().indices().prepareAliases().addAliasAction(aliasAction).execute().actionGet().isAcknowledged();
|
||||
@@ -1220,14 +1266,14 @@ public class ElasticsearchTemplate implements ElasticsearchOperations, Applicati
|
||||
stringBuilder.append(line).append(lineSeparator);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
logger.debug(String.format("Failed to load file from url: %s: %s", url, e.getMessage()));
|
||||
LOGGER.debug(String.format("Failed to load file from url: %s: %s", url, e.getMessage()));
|
||||
return null;
|
||||
} finally {
|
||||
if (bufferedReader != null)
|
||||
try {
|
||||
bufferedReader.close();
|
||||
} catch (IOException e) {
|
||||
logger.debug(String.format("Unable to close buffered reader.. %s", e.getMessage()));
|
||||
LOGGER.debug(String.format("Unable to close buffered reader.. %s", e.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,7 +37,8 @@ import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
import org.springframework.data.util.ClassTypeInformation;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import static org.apache.commons.lang.StringUtils.*;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import static org.elasticsearch.common.xcontent.XContentFactory.*;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
@@ -88,7 +89,7 @@ class MappingBuilder {
|
||||
// Properties
|
||||
XContentBuilder xContentBuilder = mapping.startObject(FIELD_PROPERTIES);
|
||||
|
||||
mapEntity(xContentBuilder, clazz, true, idFieldName, EMPTY, false, FieldType.Auto, null);
|
||||
mapEntity(xContentBuilder, clazz, true, idFieldName, "", false, FieldType.Auto, null);
|
||||
|
||||
return xContentBuilder.endObject().endObject().endObject();
|
||||
}
|
||||
@@ -119,7 +120,7 @@ class MappingBuilder {
|
||||
|
||||
if (field.isAnnotationPresent(Mapping.class)) {
|
||||
String mappingPath = field.getAnnotation(Mapping.class).mappingPath();
|
||||
if (isNotBlank(mappingPath)) {
|
||||
if (!StringUtils.isEmpty(mappingPath)) {
|
||||
ClassPathResource mappings = new ClassPathResource(mappingPath);
|
||||
if (mappings.exists()) {
|
||||
xContentBuilder.rawField(field.getName(), mappings.getInputStream());
|
||||
@@ -137,7 +138,7 @@ class MappingBuilder {
|
||||
continue;
|
||||
}
|
||||
boolean nestedOrObject = isNestedOrObjectField(field);
|
||||
mapEntity(xContentBuilder, getFieldType(field), false, EMPTY, field.getName(), nestedOrObject, singleField.type(), field.getAnnotation(Field.class));
|
||||
mapEntity(xContentBuilder, getFieldType(field), false, "", field.getName(), nestedOrObject, singleField.type(), field.getAnnotation(Field.class));
|
||||
if (nestedOrObject) {
|
||||
continue;
|
||||
}
|
||||
@@ -203,10 +204,10 @@ class MappingBuilder {
|
||||
xContentBuilder.field(COMPLETION_MAX_INPUT_LENGTH, annotation.maxInputLength());
|
||||
xContentBuilder.field(COMPLETION_PRESERVE_POSITION_INCREMENTS, annotation.preservePositionIncrements());
|
||||
xContentBuilder.field(COMPLETION_PRESERVE_SEPARATORS, annotation.preserveSeparators());
|
||||
if (isNotBlank(annotation.searchAnalyzer())) {
|
||||
if (!StringUtils.isEmpty(annotation.searchAnalyzer())) {
|
||||
xContentBuilder.field(FIELD_SEARCH_ANALYZER, annotation.searchAnalyzer());
|
||||
}
|
||||
if (isNotBlank(annotation.analyzer())) {
|
||||
if (!StringUtils.isEmpty(annotation.analyzer())) {
|
||||
xContentBuilder.field(FIELD_INDEX_ANALYZER, annotation.analyzer());
|
||||
}
|
||||
}
|
||||
@@ -311,10 +312,10 @@ class MappingBuilder {
|
||||
if (!index) {
|
||||
builder.field(FIELD_INDEX, index);
|
||||
}
|
||||
if (isNotBlank(analyzer)) {
|
||||
if (!StringUtils.isEmpty(analyzer)) {
|
||||
builder.field(FIELD_INDEX_ANALYZER, analyzer);
|
||||
}
|
||||
if (isNotBlank(searchAnalyzer)) {
|
||||
if (!StringUtils.isEmpty(searchAnalyzer)) {
|
||||
builder.field(FIELD_SEARCH_ANALYZER, searchAnalyzer);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* Copyright 2018 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.springframework.data.domain.Page;
|
||||
|
||||
/**
|
||||
* A score-aware page gaining information about max score.
|
||||
*
|
||||
* @param <T>
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public interface ScoredPage<T> extends Page<T> {
|
||||
|
||||
float getMaxScore();
|
||||
}
|
||||
+3
-1
@@ -3,12 +3,14 @@ package org.springframework.data.elasticsearch.core.aggregation;
|
||||
import org.elasticsearch.search.aggregations.Aggregation;
|
||||
import org.elasticsearch.search.aggregations.Aggregations;
|
||||
import org.springframework.data.elasticsearch.core.FacetedPage;
|
||||
import org.springframework.data.elasticsearch.core.ScoredPage;
|
||||
import org.springframework.data.elasticsearch.core.ScrolledPage;
|
||||
|
||||
/**
|
||||
* @author Petar Tahchiev
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public interface AggregatedPage<T> extends FacetedPage<T>, ScrolledPage<T> {
|
||||
public interface AggregatedPage<T> extends FacetedPage<T>, ScrolledPage<T>, ScoredPage<T> {
|
||||
|
||||
boolean hasAggregations();
|
||||
|
||||
|
||||
+43
-18
@@ -15,9 +15,7 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.aggregation.impl;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.elasticsearch.search.aggregations.Aggregation;
|
||||
import org.elasticsearch.search.aggregations.Aggregations;
|
||||
@@ -29,55 +27,77 @@ import org.springframework.data.elasticsearch.core.aggregation.AggregatedPage;
|
||||
* @author Petar Tahchiev
|
||||
* @author Artur Konczak
|
||||
* @author Mohsin Husen
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public class AggregatedPageImpl<T> extends FacetedPageImpl<T> implements AggregatedPage<T> {
|
||||
|
||||
private Aggregations aggregations;
|
||||
private Map<String, Aggregation> mapOfAggregations = new HashMap<>();
|
||||
private String scrollId;
|
||||
private String scrollId;
|
||||
private float maxScore;
|
||||
|
||||
public AggregatedPageImpl(List<T> content) {
|
||||
super(content);
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, float maxScore) {
|
||||
super(content);
|
||||
this.maxScore = maxScore;
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, String scrollId) {
|
||||
super(content);
|
||||
this.scrollId = scrollId;
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, String scrollId, float maxScore) {
|
||||
this(content, scrollId);
|
||||
this.maxScore = maxScore;
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total) {
|
||||
super(content, pageable, total);
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, float maxScore) {
|
||||
super(content, pageable, total);
|
||||
this.maxScore = maxScore;
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, String scrollId) {
|
||||
super(content, pageable, total);
|
||||
this.scrollId = scrollId;
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, String scrollId, float maxScore) {
|
||||
this(content, pageable, total, scrollId);
|
||||
this.maxScore = maxScore;
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, Aggregations aggregations) {
|
||||
super(content, pageable, total);
|
||||
this.aggregations = aggregations;
|
||||
if (aggregations != null) {
|
||||
for (Aggregation aggregation : aggregations) {
|
||||
mapOfAggregations.put(aggregation.getName(), aggregation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, Aggregations aggregations, String scrollId) {
|
||||
super(content, pageable, total);
|
||||
this.aggregations = aggregations;
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, Aggregations aggregations, float maxScore) {
|
||||
this(content, pageable, total, aggregations);
|
||||
this.maxScore = maxScore;
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, Aggregations aggregations,
|
||||
String scrollId) {
|
||||
this(content, pageable, total, aggregations);
|
||||
this.scrollId = scrollId;
|
||||
if (aggregations != null) {
|
||||
for (Aggregation aggregation : aggregations) {
|
||||
mapOfAggregations.put(aggregation.getName(), aggregation);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public AggregatedPageImpl(List<T> content, Pageable pageable, long total, Aggregations aggregations, String scrollId,
|
||||
float maxScore) {
|
||||
this(content, pageable, total, aggregations, scrollId);
|
||||
this.maxScore = maxScore;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasAggregations() {
|
||||
return aggregations != null && mapOfAggregations.size() > 0;
|
||||
return aggregations != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -94,4 +114,9 @@ public class AggregatedPageImpl<T> extends FacetedPageImpl<T> implements Aggrega
|
||||
public String getScrollId() {
|
||||
return scrollId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getMaxScore() {
|
||||
return maxScore;
|
||||
}
|
||||
}
|
||||
|
||||
+2
-3
@@ -16,14 +16,13 @@
|
||||
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.bucket.histogram.DateHistogramInterval;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
@@ -54,7 +53,7 @@ public class HistogramFacetRequest extends AbstractFacetRequest {
|
||||
|
||||
public AbstractAggregationBuilder getFacet() {
|
||||
Assert.notNull(getName(), "Facet name can't be a null !!!");
|
||||
Assert.isTrue(StringUtils.isNotBlank(field), "Please select field on which to build the facet !!!");
|
||||
Assert.isTrue(!StringUtils.isEmpty(field), "Please select field on which to build the facet !!!");
|
||||
Assert.isTrue(interval > 0, "Please provide interval as positive value greater them zero !!!");
|
||||
|
||||
DateHistogramAggregationBuilder dateHistogramBuilder = AggregationBuilders.dateHistogram(getName());
|
||||
|
||||
+3
-4
@@ -19,13 +19,12 @@ package org.springframework.data.elasticsearch.core.facet.request;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
||||
import org.elasticsearch.search.aggregations.bucket.range.RangeAggregationBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Range facet for numeric fields
|
||||
@@ -77,7 +76,7 @@ public class RangeFacetRequest extends AbstractFacetRequest {
|
||||
Assert.notNull(getName(), "Facet name can't be a null !!!");
|
||||
|
||||
RangeAggregationBuilder rangeBuilder = AggregationBuilders.range(getName());
|
||||
final String field = StringUtils.isNotBlank(keyField) ? keyField : this.field;
|
||||
final String field = !StringUtils.isEmpty(keyField) ? keyField : this.field;
|
||||
rangeBuilder.field(field);
|
||||
|
||||
for (Entry entry : entries) {
|
||||
@@ -86,7 +85,7 @@ public class RangeFacetRequest extends AbstractFacetRequest {
|
||||
}
|
||||
|
||||
rangeBuilder.subAggregation(AggregationBuilders.extendedStats(INTERNAL_STATS).field(field));
|
||||
if(StringUtils.isNotBlank(valueField)){
|
||||
if(!StringUtils.isEmpty(valueField)){
|
||||
rangeBuilder.subAggregation(AggregationBuilders.sum(RANGE_INTERNAL_SUM).field(valueField));
|
||||
}
|
||||
|
||||
|
||||
+2
-3
@@ -16,12 +16,11 @@
|
||||
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* @author Petar Tahchiev
|
||||
@@ -47,7 +46,7 @@ public class StatisticalFacetRequest extends AbstractFacetRequest {
|
||||
|
||||
public AbstractAggregationBuilder getFacet() {
|
||||
Assert.notNull(getName(), "Facet name can't be a null !!!");
|
||||
Assert.isTrue(StringUtils.isNotBlank(field) && fields == null, "Please select field or fields on which to build the facets !!!");
|
||||
Assert.isTrue(!StringUtils.isEmpty(field) && fields == null, "Please select field or fields on which to build the facets !!!");
|
||||
return AggregationBuilders.extendedStats(getName()).field(field);
|
||||
}
|
||||
}
|
||||
+6
-6
@@ -16,8 +16,6 @@
|
||||
|
||||
package org.springframework.data.elasticsearch.core.facet.request;
|
||||
|
||||
import org.apache.commons.lang.ArrayUtils;
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.apache.lucene.util.automaton.RegExp;
|
||||
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
|
||||
import org.elasticsearch.search.aggregations.AggregationBuilders;
|
||||
@@ -26,6 +24,8 @@ import org.elasticsearch.search.aggregations.bucket.terms.IncludeExclude;
|
||||
import org.elasticsearch.search.aggregations.bucket.terms.TermsAggregationBuilder;
|
||||
import org.springframework.data.elasticsearch.core.facet.AbstractFacetRequest;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Term facet
|
||||
@@ -48,8 +48,8 @@ public class TermFacetRequest extends AbstractFacetRequest {
|
||||
}
|
||||
|
||||
public void setFields(String... fields) {
|
||||
Assert.isTrue(ArrayUtils.isNotEmpty(fields), "Term agg need one field only");
|
||||
Assert.isTrue(ArrayUtils.getLength(fields) == 1, "Term agg need one field only");
|
||||
Assert.isTrue(!ObjectUtils.isEmpty(fields), "Term agg need one field only");
|
||||
Assert.isTrue(fields.length == 1, "Term agg need one field only");
|
||||
this.fields = fields;
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ public class TermFacetRequest extends AbstractFacetRequest {
|
||||
default:
|
||||
termsBuilder.order(BucketOrder.count(true));
|
||||
}
|
||||
if (ArrayUtils.isNotEmpty(excludeTerms)) {
|
||||
if (!ObjectUtils.isEmpty(excludeTerms)) {
|
||||
termsBuilder.includeExclude(new IncludeExclude(null, excludeTerms));
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@ public class TermFacetRequest extends AbstractFacetRequest {
|
||||
termsBuilder.size(Integer.MAX_VALUE);
|
||||
}
|
||||
|
||||
if (StringUtils.isNotBlank(regex)) {
|
||||
if (!StringUtils.isEmpty(regex)) {
|
||||
termsBuilder.includeExclude(new IncludeExclude(new RegExp(regex), null));
|
||||
}
|
||||
|
||||
|
||||
+24
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
* Copyright 2013-2018 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.
|
||||
@@ -16,6 +16,7 @@
|
||||
package org.springframework.data.elasticsearch.core.mapping;
|
||||
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.lang.Nullable;
|
||||
|
||||
/**
|
||||
* ElasticsearchPersistentEntity
|
||||
@@ -23,6 +24,8 @@ import org.springframework.data.mapping.PersistentEntity;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Mark Paluch
|
||||
* @author Sascha Woo
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, ElasticsearchPersistentProperty> {
|
||||
|
||||
@@ -49,4 +52,24 @@ public interface ElasticsearchPersistentEntity<T> extends PersistentEntity<T, El
|
||||
String settingPath();
|
||||
|
||||
boolean isCreateIndexAndMapping();
|
||||
|
||||
/**
|
||||
* Returns whether the {@link ElasticsearchPersistentEntity} has an score property. If this call returns
|
||||
* {@literal true}, {@link #getScoreProperty()} will return a non-{@literal null} value.
|
||||
*
|
||||
* @return false when {@link ElasticsearchPersistentEntity} does not define a score property.
|
||||
* @since 3.1
|
||||
*/
|
||||
boolean hasScoreProperty();
|
||||
|
||||
/**
|
||||
* Returns the score property of the {@link ElasticsearchPersistentEntity}. Can be {@literal null} in case no score
|
||||
* property is available on the entity.
|
||||
*
|
||||
* @return the score {@link ElasticsearchPersistentProperty} of the {@link PersistentEntity} or {@literal null} if not
|
||||
* defined.
|
||||
* @since 3.1
|
||||
*/
|
||||
@Nullable
|
||||
ElasticsearchPersistentProperty getScoreProperty();
|
||||
}
|
||||
|
||||
+15
-2
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013 the original author or authors.
|
||||
* Copyright 2013-2018 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.
|
||||
@@ -23,12 +23,25 @@ import org.springframework.data.mapping.PersistentProperty;
|
||||
*
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Sascha Woo
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
|
||||
public interface ElasticsearchPersistentProperty extends PersistentProperty<ElasticsearchPersistentProperty> {
|
||||
|
||||
String getFieldName();
|
||||
|
||||
/**
|
||||
* Returns whether the current property is a <em>potential</em> score property of the owning
|
||||
* {@link ElasticsearchPersistentEntity}. This method is mainly used by {@link ElasticsearchPersistentEntity}
|
||||
* implementation to discover score property candidates on {@link ElasticsearchPersistentEntity} creation you should
|
||||
* rather call {@link ElasticsearchPersistentEntity#isScoreProperty(PersistentProperty)} to determine whether the
|
||||
* current property is the version property of that {@link ElasticsearchPersistentEntity} under consideration.
|
||||
*
|
||||
* @return
|
||||
* @since 3.1
|
||||
*/
|
||||
boolean isScoreProperty();
|
||||
|
||||
public enum PropertyToFieldNameConverter implements Converter<ElasticsearchPersistentProperty, String> {
|
||||
|
||||
INSTANCE;
|
||||
|
||||
+43
-2
@@ -18,7 +18,6 @@ package org.springframework.data.elasticsearch.core.mapping;
|
||||
import static org.springframework.util.StringUtils.*;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -28,12 +27,16 @@ import org.springframework.context.expression.BeanFactoryResolver;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Parent;
|
||||
import org.springframework.data.elasticsearch.annotations.Setting;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentPropertyAccessor;
|
||||
import org.springframework.data.mapping.model.BasicPersistentEntity;
|
||||
import org.springframework.data.mapping.model.PersistentPropertyAccessorFactory;
|
||||
import org.springframework.data.util.TypeInformation;
|
||||
import org.springframework.expression.Expression;
|
||||
import org.springframework.expression.ParserContext;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.expression.spel.support.StandardEvaluationContext;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
@@ -43,6 +46,7 @@ import org.springframework.util.Assert;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Mark Paluch
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntity<T, ElasticsearchPersistentProperty>
|
||||
implements ElasticsearchPersistentEntity<T>, ApplicationContextAware {
|
||||
@@ -59,6 +63,7 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
private String indexStoreType;
|
||||
private String parentType;
|
||||
private ElasticsearchPersistentProperty parentIdProperty;
|
||||
private ElasticsearchPersistentProperty scoreProperty;
|
||||
private String settingPath;
|
||||
private boolean createIndexAndMapping;
|
||||
|
||||
@@ -150,6 +155,17 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
return createIndexAndMapping;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasScoreProperty() {
|
||||
return scoreProperty != null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public ElasticsearchPersistentProperty getScoreProperty() {
|
||||
return scoreProperty;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addPersistentProperty(ElasticsearchPersistentProperty property) {
|
||||
super.addPersistentProperty(property);
|
||||
@@ -165,7 +181,32 @@ public class SimpleElasticsearchPersistentEntity<T> extends BasicPersistentEntit
|
||||
}
|
||||
|
||||
if (property.isVersionProperty()) {
|
||||
Assert.isTrue(property.getType() == Long.class, "Version property should be Long");
|
||||
Assert.isTrue(property.getType() == Long.class, "Version property must be of type Long!");
|
||||
}
|
||||
|
||||
if (property.isScoreProperty()) {
|
||||
|
||||
ElasticsearchPersistentProperty scoreProperty = this.scoreProperty;
|
||||
|
||||
if (scoreProperty != null) {
|
||||
throw new MappingException(
|
||||
String.format("Attempt to add score property %s but already have property %s registered "
|
||||
+ "as version. Check your mapping configuration!", property.getField(), scoreProperty.getField()));
|
||||
}
|
||||
|
||||
this.scoreProperty = property;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.BasicPersistentEntity#setPersistentPropertyAccessorFactory(org.springframework.data.mapping.model.PersistentPropertyAccessorFactory)
|
||||
*/
|
||||
@Override
|
||||
public void setPersistentPropertyAccessorFactory(PersistentPropertyAccessorFactory factory) {
|
||||
|
||||
// Do nothing to avoid the usage of ClassGeneratingPropertyAccessorFactory for now
|
||||
// DATACMNS-1322 switches to proper immutability behavior which Spring Data Elasticsearch
|
||||
// cannot yet implement
|
||||
}
|
||||
}
|
||||
|
||||
+33
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
* Copyright 2013-2018 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.
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.mapping;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import org.springframework.data.elasticsearch.annotations.Score;
|
||||
import org.springframework.data.mapping.Association;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.PersistentEntity;
|
||||
import org.springframework.data.mapping.model.AnnotationBasedPersistentProperty;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
@@ -30,12 +33,16 @@ import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Mark Paluch
|
||||
* @author Sascha Woo
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleElasticsearchPersistentProperty extends
|
||||
AnnotationBasedPersistentProperty<ElasticsearchPersistentProperty> implements ElasticsearchPersistentProperty {
|
||||
|
||||
private static final Set<Class<?>> SUPPORTED_ID_TYPES = new HashSet<>();
|
||||
private static final Set<String> SUPPORTED_ID_PROPERTY_NAMES = new HashSet<>();
|
||||
|
||||
private final boolean isScore;
|
||||
|
||||
static {
|
||||
SUPPORTED_ID_TYPES.add(String.class);
|
||||
@@ -45,7 +52,14 @@ public class SimpleElasticsearchPersistentProperty extends
|
||||
|
||||
public SimpleElasticsearchPersistentProperty(Property property,
|
||||
PersistentEntity<?, ElasticsearchPersistentProperty> owner, SimpleTypeHolder simpleTypeHolder) {
|
||||
|
||||
super(property, owner, simpleTypeHolder);
|
||||
|
||||
this.isScore = isAnnotationPresent(Score.class);
|
||||
|
||||
if (isScore && !Arrays.asList(Float.TYPE, Float.class).contains(getType())) {
|
||||
throw new MappingException(String.format("Score property %s must be either of type float or Float!", property.getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -62,4 +76,22 @@ public class SimpleElasticsearchPersistentProperty extends
|
||||
protected Association<ElasticsearchPersistentProperty> createAssociation() {
|
||||
return null;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.mapping.ElasticsearchPersistentProperty#isScoreProperty()
|
||||
*/
|
||||
@Override
|
||||
public boolean isScoreProperty() {
|
||||
return isScore;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.mapping.model.AbstractPersistentProperty#isImmutable()
|
||||
*/
|
||||
@Override
|
||||
public boolean isImmutable() {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,10 +15,12 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import static java.util.Collections.addAll;
|
||||
import static java.util.Collections.*;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.action.search.SearchType;
|
||||
import org.elasticsearch.action.support.IndicesOptions;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
@@ -32,6 +34,7 @@ import org.springframework.util.Assert;
|
||||
* @author Mohsin Husen
|
||||
* @author Mark Paluch
|
||||
* @author Alen Turkovic
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
abstract class AbstractQuery implements Query {
|
||||
|
||||
@@ -46,6 +49,7 @@ abstract class AbstractQuery implements Query {
|
||||
protected String route;
|
||||
protected SearchType searchType = SearchType.DFS_QUERY_THEN_FETCH;
|
||||
protected IndicesOptions indicesOptions;
|
||||
protected boolean trackScores;
|
||||
|
||||
@Override
|
||||
public Sort getSort() {
|
||||
@@ -160,4 +164,23 @@ abstract class AbstractQuery implements Query {
|
||||
public void setIndicesOptions(IndicesOptions indicesOptions) {
|
||||
this.indicesOptions = indicesOptions;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
* @see org.springframework.data.elasticsearch.core.query.Query#getTrackScores()
|
||||
*/
|
||||
@Override
|
||||
public boolean getTrackScores() {
|
||||
return trackScores;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures whether to track scores.
|
||||
*
|
||||
* @param trackScores
|
||||
* @since 3.1
|
||||
*/
|
||||
public void setTrackScores(boolean trackScores) {
|
||||
this.trackScores = trackScores;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,8 @@ package org.springframework.data.elasticsearch.core.query;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.dao.InvalidDataAccessApiUsageException;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoBox;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
@@ -42,8 +43,8 @@ public class Criteria {
|
||||
"field=" + field.getName() +
|
||||
", boost=" + boost +
|
||||
", negating=" + negating +
|
||||
", queryCriteria=" + StringUtils.join(queryCriteria, '|') +
|
||||
", filterCriteria=" + StringUtils.join(filterCriteria, '|') +
|
||||
", queryCriteria=" + ObjectUtils.nullSafeToString(queryCriteria) +
|
||||
", filterCriteria=" + ObjectUtils.nullSafeToString(filterCriteria) +
|
||||
'}';
|
||||
}
|
||||
|
||||
@@ -437,7 +438,7 @@ public class Criteria {
|
||||
* @return
|
||||
*/
|
||||
public Criteria within(String geoLocation, String distance) {
|
||||
Assert.isTrue(StringUtils.isNotBlank(geoLocation), "geoLocation value must not be null");
|
||||
Assert.isTrue(!StringUtils.isEmpty(geoLocation), "geoLocation value must not be null");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.WITHIN, new Object[]{geoLocation, distance}));
|
||||
return this;
|
||||
}
|
||||
@@ -474,8 +475,8 @@ public class Criteria {
|
||||
* @return Criteria the chaind criteria with the new 'boundedBy' criteria included.
|
||||
*/
|
||||
public Criteria boundedBy(String topLeftGeohash, String bottomRightGeohash) {
|
||||
Assert.isTrue(StringUtils.isNotBlank(topLeftGeohash), "topLeftGeohash must not be empty");
|
||||
Assert.isTrue(StringUtils.isNotBlank(bottomRightGeohash), "bottomRightGeohash must not be empty");
|
||||
Assert.isTrue(!StringUtils.isEmpty(topLeftGeohash), "topLeftGeohash must not be empty");
|
||||
Assert.isTrue(!StringUtils.isEmpty(bottomRightGeohash), "bottomRightGeohash must not be empty");
|
||||
filterCriteria.add(new CriteriaEntry(OperationKey.BBOX, new Object[]{topLeftGeohash, bottomRightGeohash}));
|
||||
return this;
|
||||
}
|
||||
@@ -502,7 +503,7 @@ public class Criteria {
|
||||
}
|
||||
|
||||
private void assertNoBlankInWildcardedQuery(String searchString, boolean leadingWildcard, boolean trailingWildcard) {
|
||||
if (StringUtils.contains(searchString, CRITERIA_VALUE_SEPERATOR)) {
|
||||
if (searchString != null && searchString.contains(CRITERIA_VALUE_SEPERATOR)) {
|
||||
throw new InvalidDataAccessApiUsageException("Cannot constructQuery '" + (leadingWildcard ? "*" : "") + "\""
|
||||
+ searchString + "\"" + (trailingWildcard ? "*" : "") + "'. Use expression or multiple clauses instead.");
|
||||
}
|
||||
|
||||
+17
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
* Copyright 2013-2018 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.
|
||||
@@ -32,6 +32,7 @@ import java.util.Arrays;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jean-Baptiste Nizet
|
||||
*/
|
||||
public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
|
||||
@@ -41,6 +42,7 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
private final List<ScriptField> scriptFields = new ArrayList<>();
|
||||
private List<FacetRequest> facets;
|
||||
private List<AbstractAggregationBuilder> aggregations;
|
||||
private HighlightBuilder highlightBuilder;
|
||||
private HighlightBuilder.Field[] highlightFields;
|
||||
private List<IndexBoost> indicesBoost;
|
||||
|
||||
@@ -67,6 +69,15 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
this.highlightFields = highlightFields;
|
||||
}
|
||||
|
||||
public NativeSearchQuery(QueryBuilder query, QueryBuilder filter, List<SortBuilder> sorts,
|
||||
HighlightBuilder highlighBuilder, HighlightBuilder.Field[] highlightFields) {
|
||||
this.query = query;
|
||||
this.filter = filter;
|
||||
this.sorts = sorts;
|
||||
this.highlightBuilder = highlighBuilder;
|
||||
this.highlightFields = highlightFields;
|
||||
}
|
||||
|
||||
public QueryBuilder getQuery() {
|
||||
return query;
|
||||
}
|
||||
@@ -79,6 +90,11 @@ public class NativeSearchQuery extends AbstractQuery implements SearchQuery {
|
||||
return sorts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HighlightBuilder getHighlightBuilder() {
|
||||
return highlightBuilder;
|
||||
}
|
||||
|
||||
@Override
|
||||
public HighlightBuilder.Field[] getHighlightFields() {
|
||||
return highlightFields;
|
||||
|
||||
+35
-13
@@ -36,15 +36,18 @@ import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
* @author Artur Konczak
|
||||
* @author Mark Paluch
|
||||
* @author Alen Turkovic
|
||||
* @author Sascha Woo
|
||||
* @author Jean-Baptiste Nizet
|
||||
*/
|
||||
public class NativeSearchQueryBuilder {
|
||||
|
||||
private QueryBuilder queryBuilder;
|
||||
private QueryBuilder filterBuilder;
|
||||
private List<ScriptField> scriptFields = new ArrayList<>();
|
||||
private List<ScriptField> scriptFields = new ArrayList<>();
|
||||
private List<SortBuilder> sortBuilders = new ArrayList<>();
|
||||
private List<FacetRequest> facetRequests = new ArrayList<>();
|
||||
private List<AbstractAggregationBuilder> aggregationBuilders = new ArrayList<>();
|
||||
private HighlightBuilder highlightBuilder;
|
||||
private HighlightBuilder.Field[] highlightFields;
|
||||
private Pageable pageable = Pageable.unpaged();
|
||||
private String[] indices;
|
||||
@@ -53,6 +56,7 @@ public class NativeSearchQueryBuilder {
|
||||
private SourceFilter sourceFilter;
|
||||
private List<IndexBoost> indicesBoost;
|
||||
private float minScore;
|
||||
private boolean trackScores;
|
||||
private Collection<String> ids;
|
||||
private String route;
|
||||
private SearchType searchType;
|
||||
@@ -73,10 +77,10 @@ public class NativeSearchQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withScriptField(ScriptField scriptField) {
|
||||
this.scriptFields.add(scriptField);
|
||||
return this;
|
||||
}
|
||||
public NativeSearchQueryBuilder withScriptField(ScriptField scriptField) {
|
||||
this.scriptFields.add(scriptField);
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder addAggregation(AbstractAggregationBuilder aggregationBuilder) {
|
||||
this.aggregationBuilders.add(aggregationBuilder);
|
||||
@@ -88,6 +92,11 @@ public class NativeSearchQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withHighlightBuilder(HighlightBuilder highlightBuilder) {
|
||||
this.highlightBuilder = highlightBuilder;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withHighlightFields(HighlightBuilder.Field... highlightFields) {
|
||||
this.highlightFields = highlightFields;
|
||||
return this;
|
||||
@@ -119,8 +128,8 @@ public class NativeSearchQueryBuilder {
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withSourceFilter(SourceFilter sourceFilter) {
|
||||
this.sourceFilter = sourceFilter;
|
||||
return this;
|
||||
this.sourceFilter = sourceFilter;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withMinScore(float minScore) {
|
||||
@@ -128,6 +137,16 @@ public class NativeSearchQueryBuilder {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param trackScores whether to track scores.
|
||||
* @return
|
||||
* @since 3.1
|
||||
*/
|
||||
public NativeSearchQueryBuilder withTrackScores(boolean trackScores) {
|
||||
this.trackScores = trackScores;
|
||||
return this;
|
||||
}
|
||||
|
||||
public NativeSearchQueryBuilder withIds(Collection<String> ids) {
|
||||
this.ids = ids;
|
||||
return this;
|
||||
@@ -149,8 +168,11 @@ public class NativeSearchQueryBuilder {
|
||||
}
|
||||
|
||||
public NativeSearchQuery build() {
|
||||
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder, filterBuilder, sortBuilders, highlightFields);
|
||||
NativeSearchQuery nativeSearchQuery = new NativeSearchQuery(queryBuilder, filterBuilder, sortBuilders,
|
||||
highlightBuilder, highlightFields);
|
||||
|
||||
nativeSearchQuery.setPageable(pageable);
|
||||
nativeSearchQuery.setTrackScores(trackScores);
|
||||
|
||||
if (indices != null) {
|
||||
nativeSearchQuery.addIndices(indices);
|
||||
@@ -168,13 +190,13 @@ public class NativeSearchQueryBuilder {
|
||||
nativeSearchQuery.addSourceFilter(sourceFilter);
|
||||
}
|
||||
|
||||
if(indicesBoost != null) {
|
||||
nativeSearchQuery.setIndicesBoost(indicesBoost);
|
||||
if (indicesBoost != null) {
|
||||
nativeSearchQuery.setIndicesBoost(indicesBoost);
|
||||
}
|
||||
|
||||
if (!isEmpty(scriptFields)) {
|
||||
nativeSearchQuery.setScriptFields(scriptFields);
|
||||
}
|
||||
if (!isEmpty(scriptFields)) {
|
||||
nativeSearchQuery.setScriptFields(scriptFields);
|
||||
}
|
||||
|
||||
if (!isEmpty(facetRequests)) {
|
||||
nativeSearchQuery.setFacets(facetRequests);
|
||||
|
||||
@@ -30,6 +30,7 @@ import org.springframework.data.domain.Sort;
|
||||
* @author Mohsin Husen
|
||||
* @author Mark Paluch
|
||||
* @author Alen Turkovic
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
public interface Query {
|
||||
|
||||
@@ -114,8 +115,7 @@ public interface Query {
|
||||
void addSourceFilter(SourceFilter sourceFilter);
|
||||
|
||||
/**
|
||||
* Get SourceFilter to be returned to get include and exclude source
|
||||
* fields as part of search request.
|
||||
* Get SourceFilter to be returned to get include and exclude source fields as part of search request.
|
||||
*
|
||||
* @return SourceFilter
|
||||
*/
|
||||
@@ -128,6 +128,14 @@ public interface Query {
|
||||
*/
|
||||
float getMinScore();
|
||||
|
||||
/**
|
||||
* Get if scores will be computed and tracked, regardless of whether sorting on a field. Defaults to <tt>false</tt>.
|
||||
*
|
||||
* @return
|
||||
* @since 3.1
|
||||
*/
|
||||
boolean getTrackScores();
|
||||
|
||||
/**
|
||||
* Get Ids
|
||||
*
|
||||
@@ -142,7 +150,6 @@ public interface Query {
|
||||
*/
|
||||
String getRoute();
|
||||
|
||||
|
||||
/**
|
||||
* Type of search
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2016 the original author or authors.
|
||||
* Copyright 2013-2018 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.
|
||||
@@ -29,6 +29,7 @@ import org.springframework.data.elasticsearch.core.facet.FacetRequest;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Artur Konczak
|
||||
* @author Jean-Baptiste Nizet
|
||||
*/
|
||||
public interface SearchQuery extends Query {
|
||||
|
||||
@@ -43,6 +44,8 @@ public interface SearchQuery extends Query {
|
||||
|
||||
List<AbstractAggregationBuilder> getAggregations();
|
||||
|
||||
HighlightBuilder getHighlightBuilder();
|
||||
|
||||
HighlightBuilder.Field[] getHighlightFields();
|
||||
|
||||
List<IndexBoost> getIndicesBoost();
|
||||
|
||||
@@ -1,6 +1,88 @@
|
||||
Spring Data Elasticsearch Changelog
|
||||
===================================
|
||||
|
||||
Changes in version 3.1.2.RELEASE (2018-10-29)
|
||||
---------------------------------------------
|
||||
* DATAES-489 - Release 3.1.2 (Lovelace SR2).
|
||||
|
||||
|
||||
Changes in version 2.1.16.RELEASE (2018-10-15)
|
||||
----------------------------------------------
|
||||
* DATAES-484 - Release 2.1.16 (Ingalls SR16).
|
||||
|
||||
|
||||
Changes in version 3.0.11.RELEASE (2018-10-15)
|
||||
----------------------------------------------
|
||||
* DATAES-485 - Release 3.0.11 (Kay SR11).
|
||||
|
||||
|
||||
Changes in version 3.1.1.RELEASE (2018-10-15)
|
||||
---------------------------------------------
|
||||
* DATAES-486 - Release 3.1.1 (Lovelace SR1).
|
||||
|
||||
|
||||
Changes in version 3.1.0.RELEASE (2018-09-21)
|
||||
---------------------------------------------
|
||||
* DATAES-480 - Release 3.1 GA (Lovelace).
|
||||
* DATAES-479 - NativeSearchQueryBuilder should have a withHighlighter() method.
|
||||
|
||||
|
||||
Changes in version 3.0.10.RELEASE (2018-09-10)
|
||||
----------------------------------------------
|
||||
* DATAES-473 - Release 3.0.10 (Kay SR10).
|
||||
|
||||
|
||||
Changes in version 2.1.15.RELEASE (2018-09-10)
|
||||
----------------------------------------------
|
||||
* DATAES-474 - Release 2.1.15 (Ingalls SR15).
|
||||
|
||||
|
||||
Changes in version 3.1.0.RC2 (2018-08-20)
|
||||
-----------------------------------------
|
||||
* DATAES-472 - Release 3.1 RC2 (Lovelace).
|
||||
|
||||
|
||||
Changes in version 2.1.14.RELEASE (2018-07-27)
|
||||
----------------------------------------------
|
||||
* DATAES-463 - Release 2.1.14 (Ingalls SR14).
|
||||
* DATAES-283 - Remove dependency to Commons Lang.
|
||||
|
||||
|
||||
Changes in version 3.0.9.RELEASE (2018-07-26)
|
||||
---------------------------------------------
|
||||
* DATAES-470 - TransportClientFactoryBean does not parse clusterNodes correctly.
|
||||
* DATAES-469 - Is org.elasticsearch:elasticsearch a necessary dependency?.
|
||||
* DATAES-467 - No mapping found for [_score] in order to sort on.
|
||||
* DATAES-465 - Release 3.0.9 (Kay SR9).
|
||||
* DATAES-317 - Add query logging to ElasticsearchTemplate.
|
||||
* DATAES-283 - Remove dependency to Commons Lang.
|
||||
|
||||
|
||||
Changes in version 3.1.0.RC1 (2018-07-26)
|
||||
-----------------------------------------
|
||||
* DATAES-471 - Adapt to changes in immutable entities support.
|
||||
* DATAES-470 - TransportClientFactoryBean does not parse clusterNodes correctly.
|
||||
* DATAES-469 - Is org.elasticsearch:elasticsearch a necessary dependency?.
|
||||
* DATAES-467 - No mapping found for [_score] in order to sort on.
|
||||
* DATAES-464 - Add support for @ReadOnlyProperty to prevent properties from being written.
|
||||
* DATAES-462 - Add support for mapping document scores to entities.
|
||||
* DATAES-452 - Release 3.1 RC1 (Lovelace).
|
||||
* DATAES-317 - Add query logging to ElasticsearchTemplate.
|
||||
|
||||
|
||||
Changes in version 3.0.8.RELEASE (2018-06-13)
|
||||
---------------------------------------------
|
||||
* DATAES-460 - Avoid pulling in Netty 3 as dependency.
|
||||
* DATAES-448 - Release 3.0.8 (Kay SR8).
|
||||
* DATAES-420 - Analyzer of main field ignored when using @MultiField annotation.
|
||||
* DATAES-312 - NullHandling.NULLS_LAST not working in query.sort.
|
||||
|
||||
|
||||
Changes in version 2.1.13.RELEASE (2018-06-13)
|
||||
----------------------------------------------
|
||||
* DATAES-447 - Release 2.1.13 (Ingalls SR13).
|
||||
|
||||
|
||||
Changes in version 3.1.0.M3 (2018-05-17)
|
||||
----------------------------------------
|
||||
* DATAES-451 - Adapt to SpEL extension API changes in Spring Data Commons.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
Spring Data Elasticsearch 3.1 M3
|
||||
Spring Data Elasticsearch 3.1.2
|
||||
Copyright (c) [2013-2016] Pivotal Software, Inc.
|
||||
|
||||
This product is licensed to you under the Apache License, Version 2.0 (the "License").
|
||||
|
||||
+90
@@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright 2018 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.client;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.elasticsearch.common.transport.TransportAddress;
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link ClusterNodes}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class ClusterNodesUnitTests {
|
||||
|
||||
@Test // DATAES-470
|
||||
public void parsesSingleClusterNode() {
|
||||
|
||||
ClusterNodes nodes = ClusterNodes.DEFAULT;
|
||||
|
||||
assertThat(nodes).hasSize(1) //
|
||||
.first().satisfies(it -> {
|
||||
assertThat(it.getAddress()).isEqualTo("127.0.0.1");
|
||||
assertThat(it.getPort()).isEqualTo(9300);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAES-470
|
||||
public void parsesMultiClusterNode() {
|
||||
|
||||
ClusterNodes nodes = ClusterNodes.of("127.0.0.1:1234,10.1.0.1:5678");
|
||||
|
||||
assertThat(nodes.stream()).hasSize(2); //
|
||||
assertThat(nodes.stream()).element(0).satisfies(it -> {
|
||||
assertThat(it.getAddress()).isEqualTo("127.0.0.1");
|
||||
assertThat(it.getPort()).isEqualTo(1234);
|
||||
});
|
||||
assertThat(nodes.stream()).element(1).satisfies(it -> {
|
||||
assertThat(it.getAddress()).isEqualTo("10.1.0.1");
|
||||
assertThat(it.getPort()).isEqualTo(5678);
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAES-470
|
||||
public void rejectsEmptyHostName() {
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class) //
|
||||
.isThrownBy(() -> ClusterNodes.of(":8080")) //
|
||||
.withMessageContaining("host");
|
||||
}
|
||||
|
||||
@Test // DATAES-470
|
||||
public void rejectsEmptyPort() {
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class) //
|
||||
.isThrownBy(() -> ClusterNodes.of("localhost:")) //
|
||||
.withMessageContaining("port");
|
||||
}
|
||||
|
||||
@Test // DATAES-470
|
||||
public void rejectsMissingPort() {
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class) //
|
||||
.isThrownBy(() -> ClusterNodes.of("localhost")) //
|
||||
.withMessageContaining("host:port");
|
||||
}
|
||||
|
||||
@Test // DATAES-470
|
||||
public void rejectsUnresolvableHost() {
|
||||
|
||||
assertThatExceptionOfType(IllegalArgumentException.class) //
|
||||
.isThrownBy(() -> ClusterNodes.of("mylocalhost:80"));
|
||||
}
|
||||
}
|
||||
+44
-12
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2014 the original author or authors.
|
||||
* Copyright 2013-2018 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.
|
||||
@@ -15,15 +15,17 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core;
|
||||
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Locale;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.ReadOnlyProperty;
|
||||
import org.springframework.data.annotation.Transient;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import org.springframework.data.elasticsearch.core.mapping.SimpleElasticsearchMappingContext;
|
||||
import org.springframework.data.elasticsearch.entities.Car;
|
||||
import org.springframework.data.elasticsearch.entities.GeoEntity;
|
||||
import org.springframework.data.geo.Point;
|
||||
@@ -31,6 +33,7 @@ import org.springframework.data.geo.Point;
|
||||
/**
|
||||
* @author Artur Konczak
|
||||
* @author Mohsin Husen
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class DefaultEntityMapperTests {
|
||||
|
||||
@@ -41,7 +44,7 @@ public class DefaultEntityMapperTests {
|
||||
|
||||
@Before
|
||||
public void init() {
|
||||
entityMapper = new DefaultEntityMapper();
|
||||
entityMapper = new DefaultEntityMapper(new SimpleElasticsearchMappingContext());
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -52,7 +55,7 @@ public class DefaultEntityMapperTests {
|
||||
String jsonResult = entityMapper.mapToString(Car.builder().model(CAR_MODEL).name(CAR_NAME).build());
|
||||
|
||||
//Then
|
||||
assertThat(jsonResult, is(JSON_STRING));
|
||||
assertThat(jsonResult).isEqualTo(JSON_STRING);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -63,15 +66,14 @@ public class DefaultEntityMapperTests {
|
||||
Car result = entityMapper.mapToObject(JSON_STRING, Car.class);
|
||||
|
||||
//Then
|
||||
assertThat(result.getName(), is(CAR_NAME));
|
||||
assertThat(result.getModel(), is(CAR_MODEL));
|
||||
assertThat(result.getName()).isEqualTo(CAR_NAME);
|
||||
assertThat(result.getModel()).isEqualTo(CAR_MODEL);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldMapGeoPointElasticsearchNames() throws IOException {
|
||||
//given
|
||||
final Point point = new Point(10, 20);
|
||||
final int radius = 10;
|
||||
final String pointAsString = point.getX() + "," + point.getY();
|
||||
final double[] pointAsArray = {point.getX(), point.getY()};
|
||||
final GeoEntity geoEntity = GeoEntity.builder()
|
||||
@@ -81,13 +83,43 @@ public class DefaultEntityMapperTests {
|
||||
String jsonResult = entityMapper.mapToString(geoEntity);
|
||||
|
||||
//then
|
||||
assertThat(jsonResult, containsString(pointTemplate("pointA", point)));
|
||||
assertThat(jsonResult, containsString(pointTemplate("pointB", point)));
|
||||
assertThat(jsonResult, containsString(String.format(Locale.ENGLISH, "\"%s\":\"%s\"", "pointC", pointAsString)));
|
||||
assertThat(jsonResult, containsString(String.format(Locale.ENGLISH, "\"%s\":[%.1f,%.1f]", "pointD", pointAsArray[0], pointAsArray[1])));
|
||||
assertThat(jsonResult).contains(pointTemplate("pointA", point));
|
||||
assertThat(jsonResult).contains(pointTemplate("pointB", point));
|
||||
assertThat(jsonResult).contains(String.format(Locale.ENGLISH, "\"%s\":\"%s\"", "pointC", pointAsString));
|
||||
assertThat(jsonResult).contains(String.format(Locale.ENGLISH, "\"%s\":[%.1f,%.1f]", "pointD", pointAsArray[0], pointAsArray[1]));
|
||||
}
|
||||
|
||||
@Test // DATAES-464
|
||||
public void ignoresReadOnlyProperties() throws IOException {
|
||||
|
||||
// given
|
||||
Sample sample = new Sample();
|
||||
sample.readOnly = "readOnly";
|
||||
sample.property = "property";
|
||||
sample.transientProperty = "transient";
|
||||
sample.annotatedTransientProperty = "transient";
|
||||
|
||||
// when
|
||||
String result = entityMapper.mapToString(sample);
|
||||
|
||||
// then
|
||||
assertThat(result).contains("\"property\"");
|
||||
|
||||
assertThat(result).doesNotContain("readOnly");
|
||||
assertThat(result).doesNotContain("transientProperty");
|
||||
assertThat(result).doesNotContain("annotatedTransientProperty");
|
||||
}
|
||||
|
||||
private String pointTemplate(String name, Point point) {
|
||||
return String.format(Locale.ENGLISH, "\"%s\":{\"lat\":%.1f,\"lon\":%.1f}", name, point.getX(), point.getY());
|
||||
}
|
||||
|
||||
public static class Sample {
|
||||
|
||||
|
||||
public @ReadOnlyProperty String readOnly;
|
||||
public @Transient String annotatedTransientProperty;
|
||||
public transient String transientProperty;
|
||||
public String property;
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -46,6 +46,7 @@ import org.springframework.data.elasticsearch.entities.Car;
|
||||
import org.springframework.data.elasticsearch.entities.SampleEntity;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
import static org.hamcrest.Matchers.*;
|
||||
import static org.junit.Assert.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
+134
-1
@@ -36,6 +36,7 @@ import org.elasticsearch.search.SearchHit;
|
||||
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
|
||||
import org.elasticsearch.search.fetch.subphase.highlight.HighlightField;
|
||||
import org.elasticsearch.search.sort.FieldSortBuilder;
|
||||
import org.elasticsearch.search.sort.SortBuilders;
|
||||
import org.elasticsearch.search.sort.SortOrder;
|
||||
import org.hamcrest.Matchers;
|
||||
import org.junit.Before;
|
||||
@@ -76,6 +77,7 @@ import static org.springframework.data.elasticsearch.utils.IndexBuilder.*;
|
||||
* @author Ilkang Na
|
||||
* @author Alen Turkovic
|
||||
* @author Sascha Woo
|
||||
* @author Jean-Baptiste Nizet
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration("classpath:elasticsearch-template-test.xml")
|
||||
@@ -594,6 +596,29 @@ public class ElasticsearchTemplateTests {
|
||||
assertThat(sampleEntities.getContent().get(1).getMessage(), is(sampleEntity2.getMessage()));
|
||||
}
|
||||
|
||||
@Test // DATAES-467
|
||||
public void shouldSortResultsByScore() {
|
||||
// given
|
||||
List<SampleEntity> entities = Arrays.asList( //
|
||||
SampleEntity.builder().id("1").message("abc").build(), //
|
||||
SampleEntity.builder().id("2").message("def").build(), //
|
||||
SampleEntity.builder().id("3").message("ghi").build());
|
||||
|
||||
elasticsearchTemplate.bulkIndex(getIndexQueries(entities));
|
||||
elasticsearchTemplate.refresh(SampleEntity.class);
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(matchAllQuery())
|
||||
.withPageable(PageRequest.of(0, 10, Sort.by(Sort.Order.asc("_score"))))
|
||||
.build();
|
||||
|
||||
// when
|
||||
Page<SampleEntity> sampleEntities = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class);
|
||||
|
||||
// then
|
||||
assertThat(sampleEntities.getTotalElements(), equalTo(3L));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldExecuteStringQuery() {
|
||||
// given
|
||||
@@ -1391,6 +1416,88 @@ public class ElasticsearchTemplateTests {
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAES-479
|
||||
public void shouldHonorTheHighlightBuilderOptions() {
|
||||
|
||||
// given
|
||||
String documentId = randomNumeric(5);
|
||||
String actualMessage = "some test message with <html> unsafe <script> text";
|
||||
String highlightedMessage = "some <em>test</em> message with <html> unsafe <script> text";
|
||||
|
||||
SampleEntity sampleEntity = SampleEntity.builder()
|
||||
.id(documentId)
|
||||
.message(actualMessage)
|
||||
.version(System.currentTimeMillis())
|
||||
.build();
|
||||
|
||||
IndexQuery indexQuery = getIndexQuery(sampleEntity);
|
||||
|
||||
elasticsearchTemplate.index(indexQuery);
|
||||
elasticsearchTemplate.refresh(SampleEntity.class);
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(termQuery("message", "test"))
|
||||
.withHighlightBuilder(new HighlightBuilder().encoder("html"))
|
||||
.withHighlightFields(new HighlightBuilder.Field("message"))
|
||||
.build();
|
||||
// when
|
||||
elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
|
||||
@Override
|
||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||
for (SearchHit searchHit : response.getHits()) {
|
||||
Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
|
||||
HighlightField highlightFieldMessage = highlightFields.get("message");
|
||||
|
||||
// then
|
||||
assertNotNull(highlightFieldMessage);
|
||||
assertThat(highlightFieldMessage.fragments()[0].toString(), is(highlightedMessage));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test // DATAES-479
|
||||
public void shouldHighlightIfBuilderSetEvenIfFieldsNotSet() {
|
||||
|
||||
// given
|
||||
String documentId = randomNumeric(5);
|
||||
String actualMessage = "some test message text";
|
||||
String highlightedMessage = "some <em>test</em> message text";
|
||||
|
||||
SampleEntity sampleEntity = SampleEntity.builder()
|
||||
.id(documentId)
|
||||
.message(actualMessage)
|
||||
.version(System.currentTimeMillis())
|
||||
.build();
|
||||
|
||||
IndexQuery indexQuery = getIndexQuery(sampleEntity);
|
||||
|
||||
elasticsearchTemplate.index(indexQuery);
|
||||
elasticsearchTemplate.refresh(SampleEntity.class);
|
||||
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(termQuery("message", "test"))
|
||||
.withHighlightBuilder(new HighlightBuilder().field("message"))
|
||||
.withHighlightFields(new HighlightBuilder.Field("message"))
|
||||
.build();
|
||||
// when
|
||||
elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class, new SearchResultMapper() {
|
||||
@Override
|
||||
public <T> AggregatedPage<T> mapResults(SearchResponse response, Class<T> clazz, Pageable pageable) {
|
||||
for (SearchHit searchHit : response.getHits()) {
|
||||
Map<String, HighlightField> highlightFields = searchHit.getHighlightFields();
|
||||
HighlightField highlightFieldMessage = highlightFields.get("message");
|
||||
|
||||
// then
|
||||
assertNotNull(highlightFieldMessage);
|
||||
assertThat(highlightFieldMessage.fragments()[0].toString(), is(highlightedMessage));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDeleteDocumentBySpecifiedTypeUsingDeleteQuery() {
|
||||
// given
|
||||
@@ -1512,6 +1619,32 @@ public class ElasticsearchTemplateTests {
|
||||
assertThat(page.getContent().get(0).getMessage(), is("ab"));
|
||||
}
|
||||
|
||||
@Test // DATAES-462
|
||||
public void shouldReturnScores() {
|
||||
|
||||
// given
|
||||
List<IndexQuery> indexQueries = new ArrayList<>();
|
||||
|
||||
indexQueries.add(buildIndex(SampleEntity.builder().id("1").message("ab xz").build()));
|
||||
indexQueries.add(buildIndex(SampleEntity.builder().id("2").message("bc").build()));
|
||||
indexQueries.add(buildIndex(SampleEntity.builder().id("3").message("ac xz hi").build()));
|
||||
|
||||
elasticsearchTemplate.bulkIndex(indexQueries);
|
||||
elasticsearchTemplate.refresh(SampleEntity.class);
|
||||
|
||||
// when
|
||||
SearchQuery searchQuery = new NativeSearchQueryBuilder()
|
||||
.withQuery(termQuery("message", "xz"))
|
||||
.withSort(SortBuilders.fieldSort("message"))
|
||||
.withTrackScores(true)
|
||||
.build();
|
||||
|
||||
AggregatedPage<SampleEntity> page = elasticsearchTemplate.queryForPage(searchQuery, SampleEntity.class);
|
||||
|
||||
// then
|
||||
assertThat(page.getMaxScore(), greaterThan(0f));
|
||||
assertThat(page.getContent().get(0).getScore(), greaterThan(0f));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void shouldDoIndexWithoutId() {
|
||||
@@ -2200,4 +2333,4 @@ public class ElasticsearchTemplateTests {
|
||||
this.lastName = lastName;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-1
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2013-2017 the original author or authors.
|
||||
* Copyright 2013-2018 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.
|
||||
@@ -15,10 +15,13 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.core.mapping;
|
||||
|
||||
import static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import java.beans.IntrospectionException;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.elasticsearch.annotations.Score;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
import org.springframework.data.mapping.model.Property;
|
||||
import org.springframework.data.mapping.model.SimpleTypeHolder;
|
||||
@@ -30,6 +33,7 @@ import org.springframework.util.ReflectionUtils;
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Mark Paluch
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleElasticsearchPersistentEntityTests {
|
||||
|
||||
@@ -62,6 +66,17 @@ public class SimpleElasticsearchPersistentEntityTests {
|
||||
// when
|
||||
entity.addPersistentProperty(persistentProperty2);
|
||||
}
|
||||
|
||||
@Test // DATAES-462
|
||||
public void rejectsMultipleScoreProperties() {
|
||||
|
||||
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
|
||||
|
||||
assertThatExceptionOfType(MappingException.class) //
|
||||
.isThrownBy(() -> context.getRequiredPersistentEntity(TwoScoreProperties.class)) //
|
||||
.withMessageContaining("first") //
|
||||
.withMessageContaining("second");
|
||||
}
|
||||
|
||||
private static SimpleElasticsearchPersistentProperty createProperty(SimpleElasticsearchPersistentEntity<?> entity,
|
||||
String field) {
|
||||
@@ -106,4 +121,12 @@ public class SimpleElasticsearchPersistentEntityTests {
|
||||
this.version2 = version2;
|
||||
}
|
||||
}
|
||||
|
||||
// DATAES-462
|
||||
|
||||
static class TwoScoreProperties {
|
||||
|
||||
@Score float first;
|
||||
@Score float second;
|
||||
}
|
||||
}
|
||||
|
||||
+44
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright 2018 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 static org.assertj.core.api.Assertions.*;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.data.elasticsearch.annotations.Score;
|
||||
import org.springframework.data.mapping.MappingException;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link SimpleElasticsearchPersistentProperty}.
|
||||
*
|
||||
* @author Oliver Gierke
|
||||
*/
|
||||
public class SimpleElasticsearchPersistentPropertyUnitTests {
|
||||
|
||||
@Test // DATAES-462
|
||||
public void rejectsScorePropertyOfTypeOtherthanFloat() {
|
||||
|
||||
SimpleElasticsearchMappingContext context = new SimpleElasticsearchMappingContext();
|
||||
|
||||
assertThatExceptionOfType(MappingException.class) //
|
||||
.isThrownBy(() -> context.getRequiredPersistentEntity(InvalidScoreProperty.class)) //
|
||||
.withMessageContaining("scoreProperty");
|
||||
}
|
||||
|
||||
static class InvalidScoreProperty {
|
||||
@Score String scoreProperty;
|
||||
}
|
||||
}
|
||||
@@ -15,29 +15,29 @@
|
||||
*/
|
||||
package org.springframework.data.elasticsearch.entities;
|
||||
|
||||
import java.lang.Double;
|
||||
import java.lang.Long;
|
||||
import java.lang.Object;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Builder;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import lombok.Setter;
|
||||
import lombok.ToString;
|
||||
|
||||
import org.springframework.data.annotation.Id;
|
||||
import org.springframework.data.annotation.Version;
|
||||
import org.springframework.data.elasticsearch.annotations.Document;
|
||||
import org.springframework.data.elasticsearch.annotations.Field;
|
||||
import org.springframework.data.elasticsearch.annotations.Score;
|
||||
import org.springframework.data.elasticsearch.annotations.ScriptedField;
|
||||
import org.springframework.data.elasticsearch.core.geo.GeoPoint;
|
||||
import static org.springframework.data.elasticsearch.annotations.FieldType.*;
|
||||
|
||||
/**
|
||||
* @author Rizwan Idrees
|
||||
* @author Mohsin Husen
|
||||
* @author Chris White
|
||||
* @author Sascha Woo
|
||||
*/
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@@ -58,11 +58,11 @@ public class SampleEntity {
|
||||
private Double scriptedRate;
|
||||
private boolean available;
|
||||
private String highlightedMessage;
|
||||
|
||||
private GeoPoint location;
|
||||
|
||||
@Version
|
||||
private Long version;
|
||||
@Score
|
||||
private float score;
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
|
||||
Reference in New Issue
Block a user