|
26 | 26 |
|
27 | 27 | import java.io.IOException; |
28 | 28 | import java.util.ArrayList; |
| 29 | +import java.util.Arrays; |
29 | 30 | import java.util.Collections; |
30 | 31 | import java.util.List; |
31 | 32 | import java.util.Map; |
@@ -420,6 +421,24 @@ public static Map<String, Integer> countAttributesAcrossResolvers(Model model, L |
420 | 421 | return counts; |
421 | 422 | } |
422 | 423 |
|
| 424 | + /** |
| 425 | + * Group resolvers by their level of priority. |
| 426 | + * |
| 427 | + * @param model The entity model. |
| 428 | + * @param resolvers The names of the resolvers to reference in the entity model. |
| 429 | + * @return For each priority level, the names of the resolvers in that priority level. |
| 430 | + */ |
| 431 | + public static TreeMap<Integer, List<String>> groupResolversByPriority(Model model, List<String> resolvers) { |
| 432 | + TreeMap<Integer, List<String>> resolverGroups = new TreeMap<>(); |
| 433 | + for (String resolverName : resolvers) { |
| 434 | + Integer priority = model.resolvers().get(resolverName).priority(); |
| 435 | + if (!resolverGroups.containsKey(priority)) |
| 436 | + resolverGroups.put(priority, new ArrayList<>()); |
| 437 | + resolverGroups.get(priority).add(resolverName); |
| 438 | + } |
| 439 | + return resolverGroups; |
| 440 | + } |
| 441 | + |
423 | 442 | /** |
424 | 443 | * Resets the variables that hold the state of the job, in case the same Job object is reused. |
425 | 444 | */ |
@@ -601,11 +620,61 @@ else if (size == 1) |
601 | 620 | // Construct the resolvers clause. |
602 | 621 | String resolversClause = "{}"; |
603 | 622 | TreeMap<String, TreeMap> resolversFilterTree = new TreeMap<>(); |
| 623 | + TreeMap<Integer, TreeMap<String, TreeMap>> resolversFilterTreeGrouped= new TreeMap<>(); |
604 | 624 | if (!this.attributes.isEmpty()) { |
605 | | - Map<String, Integer> counts = countAttributesAcrossResolvers(this.input.model(), resolvers); |
606 | | - List<List<String>> resolversSorted = sortResolverAttributes(this.input.model(), resolvers, counts); |
607 | | - resolversFilterTree = makeResolversFilterTree(resolversSorted); |
608 | | - resolversClause = populateResolversFilterTree(this.input.model(), indexName, resolversFilterTree, this.attributes); |
| 625 | + |
| 626 | + // Group the resolvers by their priority level. |
| 627 | + TreeMap<Integer, List<String>> resolverGroups = groupResolversByPriority(this.input.model(), resolvers); |
| 628 | + |
| 629 | + // Construct a clause for each priority level in descending order of priority. |
| 630 | + List<Integer> priorities = new ArrayList<>(resolverGroups.keySet()); |
| 631 | + Collections.reverse(priorities); |
| 632 | + for (int level = 0; level < priorities.size(); level++) { |
| 633 | + Integer priority = priorities.get(level); |
| 634 | + List<String> resolversGroup = resolverGroups.get(priority); |
| 635 | + Map<String, Integer> counts = countAttributesAcrossResolvers(this.input.model(), resolversGroup); |
| 636 | + List<List<String>> resolversSorted = sortResolverAttributes(this.input.model(), resolversGroup, counts); |
| 637 | + resolversFilterTree = makeResolversFilterTree(resolversSorted); |
| 638 | + resolversFilterTreeGrouped.put(level, resolversFilterTree); |
| 639 | + resolversClause = populateResolversFilterTree(this.input.model(), indexName, resolversFilterTree, this.attributes); |
| 640 | + |
| 641 | + // If there are multiple levels of priority, then each lower priority group of resolvers must ensure |
| 642 | + // that every higher priority resolver either matches or does not exist. |
| 643 | + List<String> parentResolversClauses = new ArrayList<>(); |
| 644 | + if (level > 0) { |
| 645 | + |
| 646 | + // This is a lower priority group of resolvers. |
| 647 | + // Every higher priority resolver either must match or must not exist. |
| 648 | + for (int parentLevel = 0; parentLevel < level; parentLevel++) { |
| 649 | + Integer parentPriority = priorities.get(parentLevel); |
| 650 | + List<String> parentResolversGroup = resolverGroups.get(parentPriority); |
| 651 | + List<String> parentResolverClauses = new ArrayList<>(); |
| 652 | + for (String parentResolverName : parentResolversGroup) { |
| 653 | + |
| 654 | + // Construct a clause that checks if every attribute of the resolver does not exist. |
| 655 | + List<String> attributeExistsClauses = new ArrayList<>(); |
| 656 | + for (String attributeName : this.input.model().resolvers().get(parentResolverName).attributes()) |
| 657 | + attributeExistsClauses.add("{\"exists\":{\"field\":\"" + attributeName + "\"}}"); |
| 658 | + String attributesExistsClause = "{\"bool\":{\"must_not\":[" + String.join(",", attributeExistsClauses) + "]}}"; |
| 659 | + |
| 660 | + // Construct a clause for the resolver. |
| 661 | + List<String> parentResolverGroup = new ArrayList<>(Arrays.asList(parentResolverName)); |
| 662 | + Map<String, Integer> parentCounts = countAttributesAcrossResolvers(this.input.model(), parentResolverGroup); |
| 663 | + List<List<String>> parentResolverSorted = sortResolverAttributes(this.input.model(), parentResolverGroup, parentCounts); |
| 664 | + TreeMap<String, TreeMap> parentResolverFilterTree = makeResolversFilterTree(parentResolverSorted); |
| 665 | + String parentResolverClause = populateResolversFilterTree(this.input.model(), indexName, parentResolverFilterTree, this.attributes); |
| 666 | + |
| 667 | + // Construct a "should" clause for the above two clauses. |
| 668 | + parentResolverClauses.add("{\"bool\":{\"should\":[" + attributesExistsClause + "," + parentResolverClause + "]}}"); |
| 669 | + } |
| 670 | + |
| 671 | + // Construct a "filter" clause for every higher priority resolver clause. |
| 672 | + parentResolversClauses.add("{\"bool\":{\"filter\":[" + String.join(",", parentResolverClauses) + "]}}"); |
| 673 | + } |
| 674 | + } |
| 675 | + if (parentResolversClauses.size() > 0) |
| 676 | + resolversClause = "{\"bool\":{\"filter\":[" + resolversClause + "," + String.join(",", parentResolversClauses) + "]}}"; |
| 677 | + } |
609 | 678 | } |
610 | 679 |
|
611 | 680 | // Combine the ids clause and resolvers clause in a "should" clause if necessary. |
@@ -661,7 +730,7 @@ else if (!idsClause.equals("{}")) |
661 | 730 | responseDataCopyObjHits.remove("hits"); |
662 | 731 | } |
663 | 732 | String resolversListLogged = Json.ORDERED_MAPPER.writeValueAsString(resolvers); |
664 | | - String resolversFilterTreeLogged = Json.ORDERED_MAPPER.writeValueAsString(resolversFilterTree); |
| 733 | + String resolversFilterTreeLogged = Json.ORDERED_MAPPER.writeValueAsString(resolversFilterTreeGrouped); |
665 | 734 | String resolversLogged = "{\"list\":" + resolversListLogged + ",\"tree\":" + resolversFilterTreeLogged + "}"; |
666 | 735 | String searchLogged = "{\"request\":" + query + ",\"response\":" + responseDataCopyObj + "}"; |
667 | 736 | String logged = "{\"_hop\":" + this.hop + ",\"_index\":\"" + indexName + "\",\"resolvers\":" + resolversLogged + ",\"search\":" + searchLogged + "}"; |
|
0 commit comments