Skip to content

Commit a1332ce

Browse files
committed
Removed redundant "bool" wrapper clauses.
1 parent 117f38f commit a1332ce

File tree

4 files changed

+66
-33
lines changed

4 files changed

+66
-33
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ Once you have installed Elasticsearch, you can install zentity from a remote URL
3131

3232
Example:
3333

34-
`elasticsearch-plugin install https://zentity.io/releases/zentity-1.3.0-elasticsearch-7.2.0.zip`
34+
`elasticsearch-plugin install https://zentity.io/releases/zentity-1.3.1-beta1-elasticsearch-7.2.0.zip`
3535

3636
Read the [installation](https://zentity.io/docs/installation) docs for more details.
3737

pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
<zentity.author>Dave Moore</zentity.author>
1515
<zentity.classname>org.elasticsearch.plugin.zentity.ZentityPlugin</zentity.classname>
1616
<zentity.website>https://zentity.io</zentity.website>
17-
<zentity.version>1.3.0</zentity.version>
17+
<zentity.version>1.3.1-beta1</zentity.version>
1818
<!-- dependency versions -->
1919
<elasticsearch.version>7.2.0</elasticsearch.version>
2020
<jackson.version>2.9.9</jackson.version>

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

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -288,9 +288,11 @@ public static List<String> makeIndexFieldClauses(Model model, String indexName,
288288
continue;
289289

290290
// Combine each value clause into a single "should" or "filter" clause.
291-
String valuesClause = String.join(",", valueClauses);
291+
String valuesClause;
292292
if (valueClauses.size() > 1)
293-
valuesClause = "{\"bool\":{\"" + combiner + "\":[" + valuesClause + "]}}";
293+
valuesClause = "{\"bool\":{\"" + combiner + "\":[" + String.join(",", valueClauses) + "]}}";
294+
else
295+
valuesClause = valueClauses.get(0);
294296
indexFieldClauses.add(valuesClause);
295297
}
296298
return indexFieldClauses;
@@ -319,9 +321,11 @@ public static List<String> makeAttributeClauses(Model model, String indexName, M
319321
continue;
320322

321323
// Combine each matcher clause into a single "should" or "filter" clause.
322-
String indexFieldsClause = String.join(",", indexFieldClauses);
324+
String indexFieldsClause;
323325
if (indexFieldClauses.size() > 1)
324-
indexFieldsClause = "{\"bool\":{\"" + combiner + "\":[" + indexFieldsClause + "]}}";
326+
indexFieldsClause = "{\"bool\":{\"" + combiner + "\":[" + String.join(",", indexFieldClauses) + "]}}";
327+
else
328+
indexFieldsClause = indexFieldClauses.get(0);
325329
attributeClauses.add(indexFieldsClause);
326330
}
327331
return attributeClauses;
@@ -347,14 +351,16 @@ public static String populateResolversFilterTree(Model model, String indexName,
347351
if (indexFieldClauses.size() == 0)
348352
continue;
349353

350-
// Combine each matcher clause into a single "should" clause.
351-
String indexFieldsClause = String.join(",", indexFieldClauses);
354+
// Combine multiple matcher clauses into a single "should" clause.
355+
String indexFieldsClause;
352356
if (indexFieldClauses.size() > 1)
353-
indexFieldsClause = "{\"bool\":{\"should\":[" + indexFieldsClause + "]}}";
357+
indexFieldsClause = "{\"bool\":{\"should\":[" + String.join(",", indexFieldClauses) + "]}}";
358+
else
359+
indexFieldsClause = indexFieldClauses.get(0);
354360

355361
// Populate any child filters.
356362
String filter = populateResolversFilterTree(model, indexName, resolversFilterTree.get(attributeName), attributes, includeExplanation, _nameIdCounter);
357-
if (!filter.equals("{}"))
363+
if (!filter.isEmpty())
358364
attributeClauses.add("{\"bool\":{\"filter\":[" + indexFieldsClause + "," + filter + "]}}");
359365
else
360366
attributeClauses.add(indexFieldsClause);
@@ -366,9 +372,9 @@ public static String populateResolversFilterTree(Model model, String indexName,
366372
if (size > 1)
367373
return "{\"bool\":{\"should\":[" + String.join(",", attributeClauses) + "]}}";
368374
else if (size == 1)
369-
return "{\"bool\":{\"filter\":" + attributeClauses.get(0) + "}}";
375+
return attributeClauses.get(0);
370376
else
371-
return "{}";
377+
return "";
372378
}
373379

374380
/**
@@ -601,10 +607,11 @@ private void traverse() throws IOException, ValidationException {
601607

602608
// Construct query for this index.
603609
String query;
604-
String queryClause = "{}";
605-
List<String> queryClauses = new ArrayList<>();
610+
String queryClause;
606611
List<String> queryMustNotClauses = new ArrayList<>();
612+
String queryMustNotClause = "";
607613
List<String> queryFilterClauses = new ArrayList<>();
614+
String queryFilterClause = "";
608615
List<String> topLevelClauses = new ArrayList<>();
609616
topLevelClauses.add("\"_source\":true");
610617

@@ -624,8 +631,10 @@ else if (size == 1)
624631
}
625632

626633
// Construct the top-level "must_not" clause.
627-
if (!queryMustNotClauses.isEmpty())
628-
queryClauses.add("\"must_not\":[" + String.join(",", queryMustNotClauses) + "]");
634+
if (queryMustNotClauses.size() > 1)
635+
queryMustNotClause = "\"must_not\":[" + String.join(",", queryMustNotClauses) + "]";
636+
else if (queryMustNotClauses.size() == 1)
637+
queryMustNotClause = "\"must_not\":" + queryMustNotClauses.get(0);
629638

630639
// Construct "scope.include.attributes" clauses. Combine them into a single "filter" clause.
631640
if (!this.input.scope().include().attributes().isEmpty()) {
@@ -638,14 +647,14 @@ else if (size == 1)
638647
}
639648

640649
// Construct the "ids" clause if this is the first hop and if any ids are specified for this index.
641-
String idsClause = "{}";
650+
String idsClause = "";
642651
if (filterIds) {
643652
Set<String> ids = this.input().ids().get(indexName);
644653
idsClause = "{\"bool\":{\"filter\":[{\"ids\":{\"values\":[" + String.join(",", ids) + "]}}]}}";
645654
}
646655

647656
// Construct the resolvers clause.
648-
String resolversClause = "{}";
657+
String resolversClause = "";
649658
TreeMap<String, TreeMap> resolversFilterTree;
650659
TreeMap<Integer, TreeMap<String, TreeMap>> resolversFilterTreeGrouped= new TreeMap<>(Collections.reverseOrder());
651660
if (!this.attributes.isEmpty()) {
@@ -695,35 +704,59 @@ else if (size == 1)
695704
// Construct a "should" clause for the above two clauses.
696705
parentResolverClauses.add("{\"bool\":{\"should\":[" + attributesExistsClause + "," + parentResolverClause + "]}}");
697706
}
698-
699-
// Construct a "filter" clause for every higher weight resolver clause.
700-
parentResolversClauses.add("{\"bool\":{\"filter\":[" + String.join(",", parentResolverClauses) + "]}}");
707+
if (parentResolverClauses.size() > 1)
708+
parentResolversClauses.add("{\"bool\":{\"filter\":[" + String.join(",", parentResolverClauses) + "]}}");
709+
else if (parentResolverClauses.size() == 1)
710+
parentResolversClauses.add(parentResolverClauses.get(0));
701711
}
702712
}
713+
714+
// Combine the resolvers clause and parent resolvers clause in a "filter" query if necessary.
703715
if (parentResolversClauses.size() > 0)
704716
resolversClause = "{\"bool\":{\"filter\":[" + resolversClause + "," + String.join(",", parentResolversClauses) + "]}}";
705717
}
706718
}
707719

708720
// Combine the ids clause and resolvers clause in a "should" clause if necessary.
709-
if (!idsClause.equals("{}") && !resolversClause.equals("{}"))
721+
if (!idsClause.isEmpty() && !resolversClause.isEmpty())
710722
queryFilterClauses.add("{\"bool\":{\"should\":[" + idsClause + "," + resolversClause + "]}}");
711-
else if (!idsClause.equals("{}"))
723+
else if (!idsClause.isEmpty())
712724
queryFilterClauses.add(idsClause);
713-
else
725+
else if (!resolversClause.isEmpty())
714726
queryFilterClauses.add(resolversClause);
715727

716-
// Construct the top-level "filter" clause.
717-
if (!queryFilterClauses.isEmpty()) {
728+
// Construct the "query" clause.
729+
if (!queryMustNotClause.isEmpty() && queryFilterClauses.size() > 0) {
730+
731+
// Construct the top-level "filter" clause. Combine this clause and the top-level "must_not" clause
732+
// in a "bool" clause and add it to the "query" field.
718733
if (queryFilterClauses.size() > 1)
719-
queryClauses.add("\"filter\":[" + String.join(",", queryFilterClauses) + "]");
734+
queryFilterClause = "\"filter\":[" + String.join(",", queryFilterClauses) + "]";
720735
else
721-
queryClauses.add("\"filter\":" + queryFilterClauses.get(0));
722-
}
736+
queryFilterClause = "\"filter\":" + queryFilterClauses.get(0);
737+
queryClause = "\"query\":{\"bool\":{" + queryMustNotClause + "," + queryFilterClause + "}}";
723738

724-
// Construct the "query" clause.
725-
if (!queryClauses.isEmpty())
726-
queryClause = "\"query\":{\"bool\":{" + String.join(",", queryClauses) + "}}";
739+
} else if (!queryMustNotClause.isEmpty()) {
740+
741+
// Wrap only the top-level "must_not" clause in a "bool" clause and add it to the "query" field.
742+
queryClause = "\"query\":{\"bool\":{" + queryMustNotClause + "}}";
743+
744+
} else if (queryFilterClauses.size() > 0) {
745+
746+
// Construct the top-level "filter" clause and add only this clause to the "query" field.
747+
// This prevents a redundant "bool"."filter" wrapper clause when the top-level "must_not" clause
748+
// does not exist.
749+
if (queryFilterClauses.size() > 1)
750+
queryFilterClause = "{\"bool\":{\"filter\":[" + String.join(",", queryFilterClauses) + "]}}";
751+
else
752+
queryFilterClause = queryFilterClauses.get(0);
753+
queryClause = "\"query\":" + queryFilterClause;
754+
755+
} else {
756+
757+
// This should never be reached, and if somehow it did, Elasticsearch would return an error.
758+
queryClause = "\"query\":{}";
759+
}
727760
topLevelClauses.add(queryClause);
728761

729762
// Construct the "script_fields" clause.

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ public void testMakeResolversClause() throws Exception {
4343
List<List<String>> resolversSorted = Job.sortResolverAttributes(model, resolversList, counts);
4444
TreeMap<String, TreeMap> resolversFilterTree = Job.makeResolversFilterTree(resolversSorted);
4545
String resolversClause = Job.populateResolversFilterTree(model, "index", resolversFilterTree, input.attributes(), false, new AtomicInteger());
46-
String expected = "{\"bool\":{\"should\":[{\"match\":{\"id\":\"1234567890\",\"fuzziness\":\"auto\"}},{\"bool\":{\"filter\":[{\"bool\":{\"should\":[{\"term\":{\"name\":\"Alice Jones\"}},{\"term\":{\"name\":\"Alice Jones-Smith\"}}]}},{\"bool\":{\"should\":[{\"match\":{\"phone\":\"555-123-4567\",\"fuzziness\":\"2\"}},{\"bool\":{\"filter\":[{\"term\":{\"street\":\"123 Main St\"}},{\"bool\":{\"should\":[{\"bool\":{\"filter\":[{\"term\":{\"city\":\"Beverly Hills\"}},{\"bool\":{\"filter\":{\"term\":{\"state\":\"CA\"}}}}]}},{\"term\":{\"zip\":\"90210\"}}]}}]}}]}}]}}]}}";
46+
String expected = "{\"bool\":{\"should\":[{\"match\":{\"id\":\"1234567890\",\"fuzziness\":\"auto\"}},{\"bool\":{\"filter\":[{\"bool\":{\"should\":[{\"term\":{\"name\":\"Alice Jones\"}},{\"term\":{\"name\":\"Alice Jones-Smith\"}}]}},{\"bool\":{\"should\":[{\"match\":{\"phone\":\"555-123-4567\",\"fuzziness\":\"2\"}},{\"bool\":{\"filter\":[{\"term\":{\"street\":\"123 Main St\"}},{\"bool\":{\"should\":[{\"bool\":{\"filter\":[{\"term\":{\"city\":\"Beverly Hills\"}},{\"term\":{\"state\":\"CA\"}}]}},{\"term\":{\"zip\":\"90210\"}}]}}]}}]}}]}}]}}";
4747
Assert.assertEquals(resolversClause, expected);
4848
}
4949

0 commit comments

Comments
 (0)