Skip to content

Commit 28fcea5

Browse files
committed
Fixed logical error in "scope.include.attributes." Added integration tests for "scope.exclude.attributes" and "scope.include.attributes".
1 parent dd30d36 commit 28fcea5

File tree

2 files changed

+140
-14
lines changed

2 files changed

+140
-14
lines changed

src/main/java/io/zentity/resolution/Job.java

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -151,9 +151,12 @@ public static String populateMatcherClause(Matcher matcher, String indexFieldNam
151151
* @param indexName The name of the index to reference in the entity model.
152152
* @param attributeSet The names and values of the input attributes.
153153
* @param attributeName The name of the attribute to reference in the attributeSet.
154+
* @param combiner Combine clauses with "should" or "filter".
154155
* @return
155156
*/
156-
public static List<String> makeIndexFieldClauses(Model model, String indexName, Map<String, Set<Object>> attributeSet, String attributeName) {
157+
public static List<String> makeIndexFieldClauses(Model model, String indexName, Map<String, Set<Object>> attributeSet, String attributeName, String combiner) throws ValidationException {
158+
if (!combiner.equals("should") && !combiner.equals("filter"))
159+
throw new ValidationException("'" + combiner + "' is not a supported clause combiner.");
157160
List<String> indexFieldClauses = new ArrayList<>();
158161
for (String indexFieldName : model.indices().get(indexName).attributeIndexFieldsMap().get(attributeName).keySet()) {
159162

@@ -177,10 +180,10 @@ public static List<String> makeIndexFieldClauses(Model model, String indexName,
177180
if (valueClauses.size() == 0)
178181
continue;
179182

180-
// Combine each value clause into a single "should" clause.
183+
// Combine each value clause into a single "should" or "filter" clause.
181184
String valuesClause = String.join(",", valueClauses);
182185
if (valueClauses.size() > 1)
183-
valuesClause = "{\"bool\":{\"should\":[" + valuesClause + "]}}";
186+
valuesClause = "{\"bool\":{\"" + combiner + "\":[" + valuesClause + "]}}";
184187
indexFieldClauses.add(valuesClause);
185188
}
186189
return indexFieldClauses;
@@ -194,21 +197,24 @@ public static List<String> makeIndexFieldClauses(Model model, String indexName,
194197
* @param model The entity model.
195198
* @param indexName The name of the index to reference in the entity model.
196199
* @param attributeSet The names and values of the input attributes.
200+
* @param combiner Combine clauses with "should" or "filter".
197201
* @return
198202
*/
199-
public static List<String> makeAttributeClauses(Model model, String indexName, Map<String, Set<Object>> attributeSet) {
203+
public static List<String> makeAttributeClauses(Model model, String indexName, Map<String, Set<Object>> attributeSet, String combiner) throws ValidationException {
204+
if (!combiner.equals("should") && !combiner.equals("filter"))
205+
throw new ValidationException("'" + combiner + "' is not a supported clause combiner.");
200206
List<String> attributeClauses = new ArrayList<>();
201207
for (String attributeName : attributeSet.keySet()) {
202208

203-
// Construct a "should" clause for each index field mapped to this attribute.
204-
List<String> indexFieldClauses = makeIndexFieldClauses(model, indexName, attributeSet, attributeName);
209+
// Construct a "should" or "filter" clause for each index field mapped to this attribute.
210+
List<String> indexFieldClauses = makeIndexFieldClauses(model, indexName, attributeSet, attributeName, combiner);
205211
if (indexFieldClauses.size() == 0)
206212
continue;
207213

208-
// Combine each matcher clause into a single "should" clause.
214+
// Combine each matcher clause into a single "should" or "filter" clause.
209215
String indexFieldsClause = String.join(",", indexFieldClauses);
210216
if (indexFieldClauses.size() > 1)
211-
indexFieldsClause = "{\"bool\":{\"should\":[" + indexFieldsClause + "]}}";
217+
indexFieldsClause = "{\"bool\":{\"" + combiner + "\":[" + indexFieldsClause + "]}}";
212218
attributeClauses.add(indexFieldsClause);
213219
}
214220
return attributeClauses;
@@ -223,14 +229,14 @@ public static List<String> makeAttributeClauses(Model model, String indexName, M
223229
* @param attributeSet The names and values for the input attributes.
224230
* @return A "bool" clause for all applicable resolvers.
225231
*/
226-
public static String populateResolversFilterTree(Model model, String indexName, TreeMap<String, TreeMap> resolversFilterTree, Map<String, Set<Object>> attributeSet) {
232+
public static String populateResolversFilterTree(Model model, String indexName, TreeMap<String, TreeMap> resolversFilterTree, Map<String, Set<Object>> attributeSet) throws ValidationException {
227233

228234
// Construct a "filter" clause for each attribute at this level of the filter tree.
229235
List<String> attributeClauses = new ArrayList<>();
230236
for (String attributeName : resolversFilterTree.keySet()) {
231237

232238
// Construct a "should" clause for each index field mapped to this attribute.
233-
List<String> indexFieldClauses = makeIndexFieldClauses(model, indexName, attributeSet, attributeName);
239+
List<String> indexFieldClauses = makeIndexFieldClauses(model, indexName, attributeSet, attributeName, "should");
234240
if (indexFieldClauses.size() == 0)
235241
continue;
236242

@@ -503,7 +509,7 @@ private void traverse() throws IOException, ValidationException {
503509

504510
// Create "scope.exclude.attributes" clauses. Combine them into a single "should" clause.
505511
if (!this.scopeExcludeAttributes.isEmpty()) {
506-
List<String> attributeClauses = makeAttributeClauses(this.model, indexName, this.scopeExcludeAttributes);
512+
List<String> attributeClauses = makeAttributeClauses(this.model, indexName, this.scopeExcludeAttributes, "should");
507513
int size = attributeClauses.size();
508514
if (size > 1)
509515
queryMustNotClauses.add("{\"bool\":{\"should\":[" + String.join(",", attributeClauses) + "]}}");
@@ -515,12 +521,12 @@ else if (size == 1)
515521
if (!queryMustNotClauses.isEmpty())
516522
queryClauses.add("\"must_not\":[" + String.join(",", queryMustNotClauses) + "]");
517523

518-
// Create "scope.include.attributes" clauses. Combine them into a single "should" clause.
524+
// Create "scope.include.attributes" clauses. Combine them into a single "filter" clause.
519525
if (!this.scopeIncludeAttributes.isEmpty()) {
520-
List<String> attributeClauses = makeAttributeClauses(this.model, indexName, this.scopeIncludeAttributes);
526+
List<String> attributeClauses = makeAttributeClauses(this.model, indexName, this.scopeIncludeAttributes, "filter");
521527
int size = attributeClauses.size();
522528
if (size > 1)
523-
queryFilterClauses.add("{\"bool\":{\"should\":[" + String.join(",", attributeClauses) + "]}}");
529+
queryFilterClauses.add("{\"bool\":{\"filter\":[" + String.join(",", attributeClauses) + "]}}");
524530
else if (size == 1)
525531
queryFilterClauses.add(attributeClauses.get(0));
526532
}

src/test/java/io/zentity/resolution/JobIT.java

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,50 @@ public class JobIT extends AbstractITCase {
155155
" }\n" +
156156
"}", ContentType.APPLICATION_JSON);
157157

158+
private final StringEntity TEST_PAYLOAD_JOB_SCOPE_EXCLUDE_ATTRIBUTES = new StringEntity("{\n" +
159+
" \"attributes\": {\n" +
160+
" \"attribute_a\": \"a_00\"\n" +
161+
" },\n" +
162+
" \"scope\": {\n" +
163+
" \"exclude\": {\n" +
164+
" \"attributes\": { \"attribute_a\":[ \"a_11\" ], \"attribute_c\": \"c_03\" }\n" +
165+
" },\n" +
166+
" \"include\": {\n" +
167+
" \"indices\": [ \".zentity_test_index_a\", \".zentity_test_index_b\", \".zentity_test_index_c\" ],\n" +
168+
" \"resolvers\": [ \"resolver_a\", \"resolver_b\", \"resolver_c\" ]\n" +
169+
" }\n" +
170+
" }\n" +
171+
"}", ContentType.APPLICATION_JSON);
172+
173+
private final StringEntity TEST_PAYLOAD_JOB_SCOPE_INCLUDE_ATTRIBUTES = new StringEntity("{\n" +
174+
" \"attributes\": {\n" +
175+
" \"attribute_d\": \"d_00\"\n" +
176+
" },\n" +
177+
" \"scope\": {\n" +
178+
" \"include\": {\n" +
179+
" \"attributes\": { \"attribute_d\": [ \"d_00\" ], \"attribute_type_double\": 3.141592653589793 },\n" +
180+
" \"indices\": [ \".zentity_test_index_a\", \".zentity_test_index_b\", \".zentity_test_index_c\", \".zentity_test_index_d\" ],\n" +
181+
" \"resolvers\": [ \"resolver_a\", \"resolver_b\", \"resolver_c\" ]\n" +
182+
" }\n" +
183+
" }\n" +
184+
"}", ContentType.APPLICATION_JSON);
185+
186+
private final StringEntity TEST_PAYLOAD_JOB_SCOPE_EXCLUDE_AND_INCLUDE_ATTRIBUTES = new StringEntity("{\n" +
187+
" \"attributes\": {\n" +
188+
" \"attribute_d\": \"d_00\"\n" +
189+
" },\n" +
190+
" \"scope\": {\n" +
191+
" \"exclude\": {\n" +
192+
" \"attributes\": { \"attribute_c\": [ \"c_00\", \"c_01\" ] }\n" +
193+
" },\n" +
194+
" \"include\": {\n" +
195+
" \"attributes\": { \"attribute_d\": [ \"d_00\" ], \"attribute_type_double\": 3.141592653589793 },\n" +
196+
" \"indices\": [ \".zentity_test_index_a\", \".zentity_test_index_b\", \".zentity_test_index_c\", \".zentity_test_index_d\" ],\n" +
197+
" \"resolvers\": [ \"resolver_a\", \"resolver_b\", \"resolver_c\" ]\n" +
198+
" }\n" +
199+
" }\n" +
200+
"}", ContentType.APPLICATION_JSON);
201+
158202
private byte[] readFile(String filename) throws IOException {
159203
InputStream stream = this.getClass().getResourceAsStream("/" + filename);
160204
return IOUtils.toByteArray(stream);
@@ -378,4 +422,80 @@ public void testJobObject() throws Exception {
378422
destroyTestResources();
379423
}
380424
}
425+
426+
public void testJobScopeExcludeAttributes() throws Exception {
427+
try {
428+
prepareTestResources();
429+
String endpoint = "_zentity/resolution/zentity_test_entity_a";
430+
Response response = client.performRequest("POST", endpoint, params, TEST_PAYLOAD_JOB_SCOPE_EXCLUDE_ATTRIBUTES);
431+
JsonNode json = mapper.readTree(response.getEntity().getContent());
432+
assertEquals(json.get("hits").get("total").asInt(), 16);
433+
434+
Set<String> docsExpected = new HashSet<>();
435+
docsExpected.add("a0,0");
436+
docsExpected.add("b0,0");
437+
docsExpected.add("a2,1");
438+
docsExpected.add("b2,1");
439+
docsExpected.add("c0,1");
440+
docsExpected.add("c1,1");
441+
docsExpected.add("c2,1");
442+
docsExpected.add("a3,2");
443+
docsExpected.add("a4,2");
444+
docsExpected.add("a5,2");
445+
docsExpected.add("b3,2");
446+
docsExpected.add("b4,2");
447+
docsExpected.add("b5,2");
448+
docsExpected.add("c3,2");
449+
docsExpected.add("c4,2");
450+
docsExpected.add("c5,2");
451+
452+
assertEquals(docsExpected, getActual(json));
453+
} finally {
454+
destroyTestResources();
455+
}
456+
}
457+
458+
public void testJobScopeIncludeAttributes() throws Exception {
459+
try {
460+
prepareTestResources();
461+
String endpoint = "_zentity/resolution/zentity_test_entity_a";
462+
Response response = client.performRequest("POST", endpoint, params, TEST_PAYLOAD_JOB_SCOPE_INCLUDE_ATTRIBUTES);
463+
JsonNode json = mapper.readTree(response.getEntity().getContent());
464+
assertEquals(json.get("hits").get("total").asInt(), 8);
465+
466+
Set<String> docsExpected = new HashSet<>();
467+
docsExpected.add("a0,0");
468+
docsExpected.add("a2,0");
469+
docsExpected.add("b0,0");
470+
docsExpected.add("b2,0");
471+
docsExpected.add("c0,0");
472+
docsExpected.add("c2,0");
473+
docsExpected.add("d0,0");
474+
docsExpected.add("d2,0");
475+
476+
assertEquals(docsExpected, getActual(json));
477+
} finally {
478+
destroyTestResources();
479+
}
480+
}
481+
482+
public void testJobScopeExcludeAndIncludeAttributes() throws Exception {
483+
try {
484+
prepareTestResources();
485+
String endpoint = "_zentity/resolution/zentity_test_entity_a";
486+
Response response = client.performRequest("POST", endpoint, params, TEST_PAYLOAD_JOB_SCOPE_EXCLUDE_AND_INCLUDE_ATTRIBUTES);
487+
JsonNode json = mapper.readTree(response.getEntity().getContent());
488+
assertEquals(json.get("hits").get("total").asInt(), 4);
489+
490+
Set<String> docsExpected = new HashSet<>();
491+
docsExpected.add("a2,0");
492+
docsExpected.add("b2,0");
493+
docsExpected.add("c2,0");
494+
docsExpected.add("d2,0");
495+
496+
assertEquals(docsExpected, getActual(json));
497+
} finally {
498+
destroyTestResources();
499+
}
500+
}
381501
}

0 commit comments

Comments
 (0)