Skip to content

Commit

Permalink
Also include the common root, even if it is absent. This avoids mixin…
Browse files Browse the repository at this point in the history
…g multiple roots from different levels in the tree.
  • Loading branch information
lrosenstrom committed Jan 27, 2025
1 parent 0b3f64d commit 7a7884a
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 2 deletions.
30 changes: 28 additions & 2 deletions whelk-core/src/main/groovy/whelk/search2/FacetTree.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
public class FacetTree {

private final JsonLd jsonLd;
private List<String> observationsAsTypeKeys = Collections.emptyList();
private List<String> observationsAsTypeKeys = new ArrayList<>();

public FacetTree(JsonLd jsonLd) {
this.jsonLd = jsonLd;
Expand All @@ -24,7 +24,9 @@ public List<Map<String, Object>> sortObservationsAsTree(List<Map<String, Object>

observationsAsTypeKeys = observations.stream()
.map(o -> jsonLd.toTermKey(get(o, List.of("object", "@id"), "")))
.toList();
.collect(Collectors.toList());

getAbsentRoot(observationsAsTypeKeys.getFirst()).ifPresent(s -> addToObservations(observations, s));

observations.forEach(observation -> {
if (isRootNode(observation)) {
Expand All @@ -50,6 +52,11 @@ public List<Map<String, Object>> sortObservationsAsTree(List<Map<String, Object>
return List.copyOf(tree);
}

private void addToObservations(List<Map<String, Object>> observations, String s) {
observationsAsTypeKeys.add(s);
observations.add(createFakeObservation(s));
}

private Map<String, Object> createFakeObservation(String termKey) {
Map<String, Object> fakeObservation = new LinkedHashMap<>();
String termId = jsonLd.toTermId(termKey);
Expand All @@ -69,6 +76,25 @@ private List<String> getAbsentSuperClasses(Map<String, Object> observation) {
.toList();
}

private Optional<String> getAbsentRoot(String typeKey) {
// Any observation will do
List<String> allSuperClasses = jsonLd.getSuperClasses(typeKey);
return allSuperClasses.stream()
.filter(this::includesAllSubClasses)
.filter(type -> !hasOneDirectSubClass(type))
.filter(c -> !observationsAsTypeKeys.contains(c))
.findFirst();
}

private boolean hasOneDirectSubClass(String type) {
return jsonLd.getDirectSubclasses(type).size() == 1;
}

private boolean includesAllSubClasses(String c) {
Set<String> subClasses = jsonLd.getSubClasses(c);
return subClasses.containsAll(observationsAsTypeKeys);
}

private boolean hasParentInObservations(Map<String, Object> observation) {
String typeKey = jsonLd.toTermKey(get(observation, List.of("object", "@id"), ""));
List<String> allSuperClasses = jsonLd.getSuperClasses(typeKey);
Expand Down
32 changes: 32 additions & 0 deletions whelk-core/src/test/groovy/whelk/search2/FacetTreeSpec.groovy
Original file line number Diff line number Diff line change
Expand Up @@ -49,12 +49,19 @@ class FacetTreeSpec extends Specification {
def "Sort one parent with two children, superclasses of root should be ignored"() {
given:
jsonLd.getDirectSubclasses("root") >> ["child1", "child2"]
jsonLd.getDirectSubclasses("Resource") >> ["root"]
jsonLd.getDirectSubclasses("child1") >> []
jsonLd.getDirectSubclasses("child2") >> []

jsonLd.getSuperClasses("child1") >> ["root", "Resource"]
jsonLd.getSuperClasses("child2") >> ["child1", "root", "Resource"]
jsonLd.getSuperClasses("root") >> ["Resource"]
jsonLd.getSuperClasses("Resource") >> []

jsonLd.getSubClasses("Resource") >> ["root", "child1", "child2"]
jsonLd.getSubClasses("root") >> ["child1", "child2"]
jsonLd.getSubClasses("child1") >> []
jsonLd.getSubClasses("child2") >> []


expect:
Expand Down Expand Up @@ -169,4 +176,29 @@ class FacetTreeSpec extends Specification {
"_children": [["object": ["@id": "child"]]]]]]]
}

def "Absent root, two children"() {
given:
jsonLd.getDirectSubclasses("root") >> ["child1", "child2"]
jsonLd.getDirectSubclasses("child1") >> []
jsonLd.getDirectSubclasses("child2") >> []

jsonLd.getSuperClasses("child1") >> ["root"]
jsonLd.getSuperClasses("child2") >> ["root"]
jsonLd.getSuperClasses("root") >> []

jsonLd.getSubClasses("root") >> ["child1", "child2"]
jsonLd.getSubClasses("child1") >> []
jsonLd.getSubClasses("child2") >> []

expect:
def tree = new FacetTree(jsonLd)
tree.sortObservationsAsTree(observations) == sorted

where:
observations | sorted
[["object": ["@id": "child1"]],
["object": ["@id": "child2"]]] | [["totalItems" : 0, "view": ["@id" : "fake"], "object": ["@id": "root"],
"_children" : [["object": ["@id": "child1"]],
["object": ["@id": "child2"]]]]]
}
}

0 comments on commit 7a7884a

Please sign in to comment.