Skip to content

Commit 8cef503

Browse files
authored
Add more implementations using the new client.
Original Pull Request #2136 See #1973
1 parent ea4d3f9 commit 8cef503

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

43 files changed

+1760
-511
lines changed

Diff for: src/main/java/org/springframework/data/elasticsearch/NoSuchIndexException.java

+8
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@ public class NoSuchIndexException extends NonTransientDataAccessResourceExceptio
2525

2626
private final String index;
2727

28+
/**
29+
* @since 4.4
30+
*/
31+
public NoSuchIndexException(String index) {
32+
super(String.format("Index %s not found.", index));
33+
this.index = index;
34+
}
35+
2836
public NoSuchIndexException(String index, Throwable cause) {
2937
super(String.format("Index %s not found.", index), cause);
3038
this.index = index;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.client.elc;
17+
18+
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
19+
20+
/**
21+
* Class to combine an Elasticsearch {@link co.elastic.clients.elasticsearch._types.aggregations.Aggregate} with its
22+
* name. Necessary as the Elasticsearch Aggregate does not know i"s name.
23+
*
24+
* @author Peter-Josef Meisch
25+
* @since 4.4
26+
*/
27+
public class Aggregation {
28+
29+
private final String name;
30+
private final Aggregate aggregate;
31+
32+
public Aggregation(String name, Aggregate aggregate) {
33+
this.name = name;
34+
this.aggregate = aggregate;
35+
}
36+
37+
public String getName() {
38+
return name;
39+
}
40+
41+
public Aggregate getAggregate() {
42+
return aggregate;
43+
}
44+
}

Diff for: src/main/java/org/springframework/data/elasticsearch/client/elc/DocumentAdapters.java

+21-8
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
import java.util.LinkedHashMap;
2929
import java.util.List;
3030
import java.util.Map;
31+
import java.util.function.Function;
3132
import java.util.stream.Collectors;
3233

3334
import org.apache.commons.logging.Log;
@@ -77,18 +78,12 @@ public static SearchDocument from(Hit<?> hit, JsonpMapper jsonpMapper) {
7778

7879
NestedMetaData nestedMetaData = from(hit.nested());
7980

80-
// todo #1973 explanation
8181
Explanation explanation = from(hit.explanation());
8282

8383
// todo #1973 matchedQueries
8484
List<String> matchedQueries = null;
85-
// todo #1973 documentFields
86-
Map<String, List<Object>> documentFields = Collections.emptyMap();
8785

88-
Document document;
89-
Object source = hit.source();
90-
if (source == null) {
91-
// Elasticsearch provides raw JsonData, so we build the fields into a JSON string
86+
Function<Map<String, JsonData>, EntityAsMap> fromFields = fields -> {
9287
StringBuilder sb = new StringBuilder("{");
9388
final boolean[] firstField = { true };
9489
hit.fields().forEach((key, jsonData) -> {
@@ -100,7 +95,25 @@ public static SearchDocument from(Hit<?> hit, JsonpMapper jsonpMapper) {
10095
firstField[0] = false;
10196
});
10297
sb.append('}');
103-
document = Document.parse(sb.toString());
98+
return new EntityAsMap().fromJson(sb.toString());
99+
};
100+
101+
EntityAsMap hitFieldsAsMap = fromFields.apply(hit.fields());
102+
103+
Map<String, List<Object>> documentFields = new LinkedHashMap<>();
104+
hitFieldsAsMap.entrySet().forEach(entry -> {
105+
if (entry.getValue() instanceof List) {
106+
// noinspection unchecked
107+
documentFields.put(entry.getKey(), (List<Object>) entry.getValue());
108+
} else {
109+
documentFields.put(entry.getKey(), Collections.singletonList(entry.getValue()));
110+
}
111+
});
112+
113+
Document document;
114+
Object source = hit.source();
115+
if (source == null) {
116+
document = Document.from(hitFieldsAsMap);
104117
} else {
105118
if (source instanceof EntityAsMap) {
106119
document = Document.from((EntityAsMap) source);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
/*
2+
* Copyright 2022 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.elasticsearch.client.elc;
17+
18+
import org.springframework.data.elasticsearch.core.AggregationContainer;
19+
20+
/**
21+
* {@link AggregationContainer} for a {@link Aggregation} that holds Elasticsearch data.
22+
* @author Peter-Josef Meisch
23+
* @since 4.4
24+
*/
25+
public class ElasticsearchAggregation implements AggregationContainer<Aggregation> {
26+
27+
private final Aggregation aggregation;
28+
29+
public ElasticsearchAggregation(Aggregation aggregation) {
30+
this.aggregation = aggregation;
31+
}
32+
33+
@Override
34+
public Aggregation aggregation() {
35+
return aggregation;
36+
}
37+
}

Diff for: src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchAggregations.java

+24-4
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,46 @@
1717

1818
import co.elastic.clients.elasticsearch._types.aggregations.Aggregate;
1919

20+
import java.util.ArrayList;
21+
import java.util.List;
2022
import java.util.Map;
2123

2224
import org.springframework.data.elasticsearch.core.AggregationsContainer;
25+
import org.springframework.util.Assert;
2326

2427
/**
2528
* AggregationsContainer implementation for the Elasticsearch aggregations.
2629
*
2730
* @author Peter-Josef Meisch
2831
* @since 4.4
2932
*/
30-
public class ElasticsearchAggregations implements AggregationsContainer<Map<String, Aggregate>> {
33+
public class ElasticsearchAggregations implements AggregationsContainer<List<ElasticsearchAggregation>> {
3134

32-
private final Map<String, Aggregate> aggregations;
35+
private final List<ElasticsearchAggregation> aggregations;
36+
37+
public ElasticsearchAggregations(List<ElasticsearchAggregation> aggregations) {
38+
39+
Assert.notNull(aggregations, "aggregations must not be null");
3340

34-
public ElasticsearchAggregations(Map<String, Aggregate> aggregations) {
3541
this.aggregations = aggregations;
3642
}
3743

44+
/**
45+
* convenience constructor taking a map as it is returned from the new Elasticsearch client.
46+
*
47+
* @param aggregationsMap aggregate map
48+
*/
49+
public ElasticsearchAggregations(Map<String, Aggregate> aggregationsMap) {
50+
51+
Assert.notNull(aggregationsMap, "aggregationsMap must not be null");
52+
53+
aggregations = new ArrayList<>(aggregationsMap.size());
54+
aggregationsMap
55+
.forEach((name, aggregate) -> aggregations.add(new ElasticsearchAggregation(new Aggregation(name, aggregate))));
56+
}
57+
3858
@Override
39-
public Map<String, Aggregate> aggregations() {
59+
public List<ElasticsearchAggregation> aggregations() {
4060
return aggregations;
4161
}
4262
}

Diff for: src/main/java/org/springframework/data/elasticsearch/client/elc/ElasticsearchExceptionTranslator.java

+30-9
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,18 @@
2020
import co.elastic.clients.json.JsonpMapper;
2121

2222
import java.io.IOException;
23+
import java.util.regex.Matcher;
24+
import java.util.regex.Pattern;
2325

26+
import org.elasticsearch.client.ResponseException;
2427
import org.springframework.dao.DataAccessException;
2528
import org.springframework.dao.DataAccessResourceFailureException;
29+
import org.springframework.dao.DataIntegrityViolationException;
2630
import org.springframework.dao.OptimisticLockingFailureException;
2731
import org.springframework.dao.support.PersistenceExceptionTranslator;
28-
import org.springframework.data.elasticsearch.RestStatusException;
32+
import org.springframework.data.elasticsearch.NoSuchIndexException;
2933
import org.springframework.data.elasticsearch.UncategorizedElasticsearchException;
34+
import org.springframework.http.HttpStatus;
3035

3136
/**
3237
* Simple {@link PersistenceExceptionTranslator} for Elasticsearch. Convert the given runtime exception to an
@@ -67,14 +72,28 @@ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
6772
return new OptimisticLockingFailureException("Cannot index a document due to seq_no+primary_term conflict", ex);
6873
}
6974

70-
// todo #1973 index unavailable?
71-
7275
if (ex instanceof ElasticsearchException) {
7376
ElasticsearchException elasticsearchException = (ElasticsearchException) ex;
7477

7578
ErrorResponse response = elasticsearchException.response();
79+
80+
if (response.status() == HttpStatus.NOT_FOUND.value()
81+
&& "index_not_found_exception".equals(response.error().type())) {
82+
83+
Pattern pattern = Pattern.compile(".*no such index \\[(.*)\\]");
84+
String index = "";
85+
Matcher matcher = pattern.matcher(response.error().reason());
86+
if (matcher.matches()) {
87+
index = matcher.group(1);
88+
}
89+
return new NoSuchIndexException(index);
90+
}
7691
String body = JsonUtils.toJson(response, jsonpMapper);
7792

93+
if (response.error().type().contains("validation_exception")) {
94+
return new DataIntegrityViolationException(response.error().reason());
95+
}
96+
7897
return new UncategorizedElasticsearchException(ex.getMessage(), response.status(), body, ex);
7998
}
8099

@@ -86,20 +105,22 @@ public DataAccessException translateExceptionIfPossible(RuntimeException ex) {
86105
return null;
87106
}
88107

89-
private boolean isSeqNoConflict(Exception exception) {
108+
private boolean isSeqNoConflict(Throwable exception) {
90109
// todo #1973 check if this works
91110
Integer status = null;
92111
String message = null;
93112

94-
if (exception instanceof RestStatusException) {
95113

96-
RestStatusException statusException = (RestStatusException) exception;
97-
status = statusException.getStatus();
98-
message = statusException.getMessage();
114+
if (exception instanceof ResponseException) {
115+
ResponseException responseException = (ResponseException) exception;
116+
status = responseException.getResponse().getStatusLine().getStatusCode();
117+
message = responseException.getMessage();
118+
} else if (exception.getCause() != null) {
119+
return isSeqNoConflict(exception.getCause());
99120
}
100121

101122
if (status != null && message != null) {
102-
return status == 409 && message.contains("type=version_conflict_engine_exception")
123+
return status == 409 && message.contains("type\":\"version_conflict_engine_exception")
103124
&& message.contains("version conflict, required seqNo");
104125
}
105126

0 commit comments

Comments
 (0)