Skip to content

Commit e80e32e

Browse files
committed
Fix source filter setup in multiget requests.
Original Pull Request #1664 Closes #1659 (cherry picked from commit 1a02c1e)
1 parent ef2600f commit e80e32e

File tree

3 files changed

+274
-2
lines changed

3 files changed

+274
-2
lines changed

src/main/java/org/springframework/data/elasticsearch/core/RequestFactory.java

+30-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2019-2020 the original author or authors.
2+
* Copyright 2019-2021 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -59,6 +59,7 @@
5959
import org.elasticsearch.script.ScriptType;
6060
import org.elasticsearch.search.aggregations.AbstractAggregationBuilder;
6161
import org.elasticsearch.search.builder.SearchSourceBuilder;
62+
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
6263
import org.elasticsearch.search.fetch.subphase.highlight.HighlightBuilder;
6364
import org.elasticsearch.search.sort.FieldSortBuilder;
6465
import org.elasticsearch.search.sort.GeoDistanceSortBuilder;
@@ -760,13 +761,20 @@ private List<MultiGetRequest.Item> getMultiRequestItems(Query searchQuery, Index
760761
searchQuery.addSourceFilter(new FetchSourceFilter(toArray(searchQuery.getFields()), null));
761762
}
762763

764+
FetchSourceContext fetchSourceContext = getFetchSourceContext(searchQuery);
765+
763766
for (String id : searchQuery.getIds()) {
764767
MultiGetRequest.Item item = new MultiGetRequest.Item(index.getIndexName(), id);
765768

766769
if (searchQuery.getRoute() != null) {
767770
item = item.routing(searchQuery.getRoute());
768771
}
769-
items.add(item);
772+
773+
if (fetchSourceContext != null) {
774+
item.fetchSourceContext(fetchSourceContext);
775+
}
776+
777+
items.add(item);
770778
}
771779
return items;
772780
}
@@ -1047,4 +1055,24 @@ private String[] toArray(List<String> values) {
10471055
return values.toArray(valuesAsArray);
10481056
}
10491057

1058+
private FetchSourceContext getFetchSourceContext(Query searchQuery) {
1059+
FetchSourceContext fetchSourceContext = null;
1060+
SourceFilter sourceFilter = searchQuery.getSourceFilter();
1061+
1062+
if (!isEmpty(searchQuery.getFields())) {
1063+
if (sourceFilter == null) {
1064+
sourceFilter = new FetchSourceFilter(toArray(searchQuery.getFields()), null);
1065+
} else {
1066+
ArrayList<String> arrayList = new ArrayList<>();
1067+
Collections.addAll(arrayList, sourceFilter.getIncludes());
1068+
sourceFilter = new FetchSourceFilter(toArray(arrayList), null);
1069+
}
1070+
1071+
fetchSourceContext = new FetchSourceContext(true, sourceFilter.getIncludes(), sourceFilter.getExcludes());
1072+
} else if (sourceFilter != null) {
1073+
fetchSourceContext = new FetchSourceContext(true, sourceFilter.getIncludes(), sourceFilter.getExcludes());
1074+
}
1075+
return fetchSourceContext;
1076+
}
1077+
10501078
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,219 @@
1+
/*
2+
* Copyright 2021 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.core;
17+
18+
import static org.assertj.core.api.Assertions.*;
19+
20+
import lombok.AllArgsConstructor;
21+
import lombok.Builder;
22+
import lombok.Data;
23+
import lombok.NoArgsConstructor;
24+
25+
import java.util.Collections;
26+
import java.util.List;
27+
28+
import org.junit.jupiter.api.AfterEach;
29+
import org.junit.jupiter.api.BeforeEach;
30+
import org.junit.jupiter.api.DisplayName;
31+
import org.junit.jupiter.api.Test;
32+
import org.springframework.beans.factory.annotation.Autowired;
33+
import org.springframework.data.annotation.Id;
34+
import org.springframework.data.elasticsearch.annotations.Document;
35+
import org.springframework.data.elasticsearch.annotations.Field;
36+
import org.springframework.data.elasticsearch.annotations.FieldType;
37+
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
38+
import org.springframework.data.elasticsearch.core.query.NativeSearchQueryBuilder;
39+
import org.springframework.data.elasticsearch.core.query.Query;
40+
import org.springframework.data.elasticsearch.core.query.SourceFilter;
41+
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchRestTemplateConfiguration;
42+
import org.springframework.data.elasticsearch.junit.jupiter.SpringIntegrationTest;
43+
import org.springframework.test.context.ContextConfiguration;
44+
45+
/**
46+
* @author Peter-Josef Meisch
47+
*/
48+
@SpringIntegrationTest
49+
@ContextConfiguration(classes = { ElasticsearchRestTemplateConfiguration.class })
50+
public class SourceFilterIntegrationTests {
51+
52+
private static final String INDEX = "sourcefilter-tests";
53+
54+
@Autowired private ElasticsearchOperations operations;
55+
private IndexOperations indexOps;
56+
57+
@BeforeEach
58+
void setUp() {
59+
indexOps = operations.indexOps(Entity.class);
60+
indexOps.create();
61+
indexOps.putMapping(indexOps.createMapping());
62+
63+
operations.save(Entity.builder().id("42").field1("one").field2("two").field3("three").build());
64+
indexOps.refresh();
65+
}
66+
67+
@AfterEach
68+
void tearDown() {
69+
indexOps.delete();
70+
}
71+
72+
@Test // #1659
73+
@DisplayName("should only return requested fields on search")
74+
void shouldOnlyReturnRequestedFieldsOnSearch() {
75+
76+
Query query = Query.findAll();
77+
query.addFields("field2");
78+
79+
SearchHits<Entity> searchHits = operations.search(query, Entity.class);
80+
81+
assertThat(searchHits).hasSize(1);
82+
Entity entity = searchHits.getSearchHit(0).getContent();
83+
assertThat(entity.getField1()).isNull();
84+
assertThat(entity.getField2()).isEqualTo("two");
85+
assertThat(entity.getField3()).isNull();
86+
}
87+
88+
@Test // #1659
89+
@DisplayName("should only return requested fields on multiget")
90+
void shouldOnlyReturnRequestedFieldsOnGMultiGet() {
91+
92+
Query query = new NativeSearchQueryBuilder().withIds(Collections.singleton("42")).build();
93+
query.addFields("field2");
94+
95+
List<Entity> entities = operations.multiGet(query, Entity.class, IndexCoordinates.of(INDEX));
96+
97+
assertThat(entities).hasSize(1);
98+
Entity entity = entities.get(0);
99+
assertThat(entity.getField1()).isNull();
100+
assertThat(entity.getField2()).isEqualTo("two");
101+
assertThat(entity.getField3()).isNull();
102+
}
103+
104+
@Test // #1659
105+
@DisplayName("should not return excluded fields from SourceFilter on search")
106+
void shouldNotReturnExcludedFieldsFromSourceFilterOnSearch() {
107+
108+
Query query = Query.findAll();
109+
query.addSourceFilter(new SourceFilter() {
110+
@Override
111+
public String[] getIncludes() {
112+
return new String[] {};
113+
}
114+
115+
@Override
116+
public String[] getExcludes() {
117+
return new String[] { "field2" };
118+
}
119+
});
120+
121+
SearchHits<Entity> entities = operations.search(query, Entity.class);
122+
123+
assertThat(entities).hasSize(1);
124+
Entity entity = entities.getSearchHit(0).getContent();
125+
assertThat(entity.getField1()).isNotNull();
126+
assertThat(entity.getField2()).isNull();
127+
assertThat(entity.getField3()).isNotNull();
128+
}
129+
130+
@Test // #1659
131+
@DisplayName("should not return excluded fields from SourceFilter on multiget")
132+
void shouldNotReturnExcludedFieldsFromSourceFilterOnMultiGet() {
133+
134+
Query query = new NativeSearchQueryBuilder().withIds(Collections.singleton("42")).build();
135+
query.addSourceFilter(new SourceFilter() {
136+
@Override
137+
public String[] getIncludes() {
138+
return new String[] {};
139+
}
140+
141+
@Override
142+
public String[] getExcludes() {
143+
return new String[] { "field2" };
144+
}
145+
});
146+
147+
List<Entity> entities = operations.multiGet(query, Entity.class, IndexCoordinates.of(INDEX));
148+
149+
assertThat(entities).hasSize(1);
150+
Entity entity = entities.get(0);
151+
assertThat(entity.getField1()).isNotNull();
152+
assertThat(entity.getField2()).isNull();
153+
assertThat(entity.getField3()).isNotNull();
154+
}
155+
156+
@Test // #1659
157+
@DisplayName("should only return included fields from SourceFilter on search")
158+
void shouldOnlyReturnIncludedFieldsFromSourceFilterOnSearch() {
159+
160+
Query query = Query.findAll();
161+
query.addSourceFilter(new SourceFilter() {
162+
@Override
163+
public String[] getIncludes() {
164+
return new String[] { "field2" };
165+
}
166+
167+
@Override
168+
public String[] getExcludes() {
169+
return new String[] {};
170+
}
171+
});
172+
173+
SearchHits<Entity> entities = operations.search(query, Entity.class);
174+
175+
assertThat(entities).hasSize(1);
176+
Entity entity = entities.getSearchHit(0).getContent();
177+
assertThat(entity.getField1()).isNull();
178+
assertThat(entity.getField2()).isNotNull();
179+
assertThat(entity.getField3()).isNull();
180+
}
181+
182+
@Test // #1659
183+
@DisplayName("should only return included fields from SourceFilter on multiget")
184+
void shouldOnlyReturnIncludedFieldsFromSourceFilterOnMultiGet() {
185+
186+
Query query = new NativeSearchQueryBuilder().withIds(Collections.singleton("42")).build();
187+
query.addSourceFilter(new SourceFilter() {
188+
@Override
189+
public String[] getIncludes() {
190+
return new String[] { "field2" };
191+
}
192+
193+
@Override
194+
public String[] getExcludes() {
195+
return new String[] {};
196+
}
197+
});
198+
199+
List<Entity> entities = operations.multiGet(query, Entity.class, IndexCoordinates.of(INDEX));
200+
201+
assertThat(entities).hasSize(1);
202+
Entity entity = entities.get(0);
203+
assertThat(entity.getField1()).isNull();
204+
assertThat(entity.getField2()).isNotNull();
205+
assertThat(entity.getField3()).isNull();
206+
}
207+
208+
@Data
209+
@Builder
210+
@NoArgsConstructor
211+
@AllArgsConstructor
212+
@Document(indexName = INDEX)
213+
public static class Entity {
214+
@Id private String id;
215+
@Field(type = FieldType.Text) private String field1;
216+
@Field(type = FieldType.Text) private String field2;
217+
@Field(type = FieldType.Text) private String field3;
218+
}
219+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
/*
2+
* Copyright 2021 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.core;
17+
18+
import org.springframework.data.elasticsearch.junit.jupiter.ElasticsearchTemplateConfiguration;
19+
import org.springframework.test.context.ContextConfiguration;
20+
21+
/**
22+
* @author Peter-Josef Meisch
23+
*/
24+
@ContextConfiguration(classes = { ElasticsearchTemplateConfiguration.class })
25+
public class SourceFilterIntegrationTransportTests extends SourceFilterIntegrationTests {}

0 commit comments

Comments
 (0)