From af85338d7e99870ab00d478a526305dc2e398e2c Mon Sep 17 00:00:00 2001 From: lukaskabc Date: Tue, 30 Jul 2024 14:44:58 +0200 Subject: [PATCH 1/2] [Enhancement kbss-cvut/termit-ui#479] Remove lang filter from root term selects --- .../kbss/termit/persistence/dao/TermDao.java | 21 +++++++++++++------ .../termit/service/business/TermService.java | 4 ++++ .../repository/TermRepositoryService.java | 6 ++++++ .../termit/persistence/dao/TermDaoTest.java | 13 ++++++++++++ 4 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java index 07fae2fe1..4000e2b5d 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java @@ -390,6 +390,8 @@ public List findAllIncludingImported(Vocabulary vocabulary) { /** * Loads a page of root terms (terms without a parent) contained in the specified vocabulary. + *

+ * Terms with a label in the instance language are prepended. * * @param vocabulary Vocabulary whose root terms should be returned * @param pageSpec Page specification @@ -401,13 +403,14 @@ public List findAllRoots(Vocabulary vocabulary, Pageable pageSpec, Coll Objects.requireNonNull(vocabulary); Objects.requireNonNull(pageSpec); TypedQuery query = em.createNativeQuery("SELECT DISTINCT ?term WHERE {" + + "SELECT DISTINCT ?term ?hasLocaleLabel WHERE {" + "GRAPH ?context { " + "?term a ?type ;" + "?hasLabel ?label ." + "?vocabulary ?hasGlossary/?hasTerm ?term ." + - "FILTER (lang(?label) = ?labelLang) ." + + "BIND((lang(?label) = ?labelLang) as ?hasLocaleLabel) ." + "FILTER (?term NOT IN (?included))" + - "}} ORDER BY " + orderSentence("?label"), + "}} ORDER BY DESC(?hasLocaleLabel) " + orderSentence("?label") + "}", TermDto.class); query = setCommonFindAllRootsQueryParams(query, false); try { @@ -453,6 +456,8 @@ private static String r(String string, String from, String to) { /** * Loads a page of root terms (terms without a parent). + *

+ * Terms with a label in the instance language are prepended. * * @param pageSpec Page specification * @param includeTerms Identifiers of terms which should be a part of the result. Optional @@ -462,13 +467,14 @@ private static String r(String string, String from, String to) { public List findAllRoots(Pageable pageSpec, Collection includeTerms) { Objects.requireNonNull(pageSpec); TypedQuery query = em.createNativeQuery("SELECT DISTINCT ?term WHERE {" + + "SELECT DISTINCT ?term ?hasLocaleLabel WHERE {" + "?term a ?type ; " + "?hasLabel ?label . " + "?vocabulary ?hasGlossary/?hasTerm ?term . " + - "FILTER (lang(?label) = ?labelLang) . " + + "BIND((lang(?label) = ?labelLang) as ?hasLocaleLabel) ." + "FILTER (?term NOT IN (?included)) . " + "FILTER NOT EXISTS {?term a ?snapshot .} " + - "} ORDER BY " + orderSentence("?label"), + "} ORDER BY DESC(?hasLocaleLabel) " + orderSentence("?label") + "}", TermDto.class); query = setCommonFindAllRootsQueryParams(query, false); try { @@ -533,6 +539,8 @@ private void recursivelyLoadParentTermSubTerms(TermDto term) { *

* This method basically does a transitive closure of the vocabulary import relationship and retrieves a page of * root terms from this closure. + *

+ * Terms with a label in the instance language are prepended. * * @param vocabulary The last vocabulary in the vocabulary import chain * @param pageSpec Page specification @@ -544,13 +552,14 @@ public List findAllRootsIncludingImports(Vocabulary vocabulary, Pageabl Objects.requireNonNull(vocabulary); Objects.requireNonNull(pageSpec); TypedQuery query = em.createNativeQuery("SELECT DISTINCT ?term WHERE {" + + "SELECT DISTINCT ?term ?hasLocaleLabel WHERE {" + "?term a ?type ;" + "?hasLabel ?label ." + "?vocabulary ?imports* ?parent ." + "?parent ?hasGlossary/?hasTerm ?term ." + - "FILTER (lang(?label) = ?labelLang) ." + + "BIND((lang(?label) = ?labelLang) as ?hasLocaleLabel) ." + "FILTER (?term NOT IN (?included))" + - "} ORDER BY " + orderSentence("?label"), + "} ORDER BY DESC(?hasLocaleLabel) " + orderSentence("?label") + "}", TermDto.class); query = setCommonFindAllRootsQueryParams(query, true); try { diff --git a/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java b/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java index 624e7be13..50e561a1d 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/business/TermService.java @@ -175,6 +175,8 @@ public List findAllRoots(Vocabulary vocabulary, Pageable pageSpec, Coll * Retrieves root terms (terms without parent). *

* The page specification parameter allows configuration of the number of results and their offset. + *

+ * Terms with a label in the instance language are prepended. * * @param pageSpec Paging specification * @param includeTerms Identifiers of terms which should be a part of the result. Optional @@ -191,6 +193,8 @@ public List findAllRoots(Pageable pageSpec, Collection includeTerm *

* Basically, this does a transitive closure over the vocabulary import relationship, starting at the specified * vocabulary, and returns all parent-less terms. + *

+ * Terms with a label in the instance language are prepended. * * @param vocabulary Base vocabulary for the vocabulary import closure * @param pageSpec Page specifying result number and position diff --git a/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java b/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java index 23d5e2171..85fe06927 100644 --- a/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java +++ b/src/main/java/cz/cvut/kbss/termit/service/repository/TermRepositoryService.java @@ -240,6 +240,8 @@ public List findAllIncludingImported(Vocabulary vocabulary) { /** * Finds all root terms (terms without parent term) in the specified vocabulary. + *

+ * Terms with a label in the instance language are prepended. * * @param vocabulary Vocabulary whose terms should be returned * @param pageSpec Page specifying result number and position @@ -255,6 +257,8 @@ public List findAllRoots(Vocabulary vocabulary, Pageable pageSpec, /** * Finds all root terms (terms without parent term). + *

+ * Terms with a label in the instance language are prepended. * * @param pageSpec Page specifying result number and position * @param includeTerms Identifiers of terms which should be a part of the result. Optional @@ -273,6 +277,8 @@ public List findAllRoots(Pageable pageSpec, *

* Basically, this does a transitive closure over the vocabulary import relationship, starting at the specified * vocabulary, and returns all parent-less terms. + *

+ * Terms with a label in the instance language are prepended. * * @param vocabulary Base vocabulary for the vocabulary import closure * @param pageSpec Page specifying result number and position diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java index 9acc6a73f..3b70c160b 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java @@ -743,6 +743,19 @@ void findAllRootsOrdersResultsInLexicographicOrderForCzech() { .collect(Collectors.toList())); } + @Test + void findAllRootsReturnsTermsThatAreMissingDefaultLanguageLabel() { + configuration.getPersistence().setLanguage("cs"); + // these terms will be missing Czech labels + persistTerms("en", "Germany", "China", "Spain", "Syria"); + final List result = sut.findAllRoots(vocabulary, Constants.DEFAULT_PAGE_SPEC, Collections.emptyList()); + assertEquals(4, result.size()); + assertEquals(Arrays + .asList("China", "Germany", "Spain", "Syria"), + result.stream().map(r -> r.getLabel().get("en")) + .toList()); + } + private void persistTerms(String lang, String... labels) { transactional(() -> Arrays.stream(labels).forEach(label -> { final Term parent = Generator.generateTermWithId(); From a66deba444adb33ca10149bf9bf332f37c5f9d30 Mon Sep 17 00:00:00 2001 From: lukaskabc Date: Wed, 31 Jul 2024 14:02:55 +0200 Subject: [PATCH 2/2] Multilang label ordering --- .../kbss/termit/persistence/dao/TermDao.java | 6 ++-- .../termit/persistence/dao/TermDaoTest.java | 31 +++++++++++++++++++ 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java index 4000e2b5d..95d458480 100644 --- a/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java +++ b/src/main/java/cz/cvut/kbss/termit/persistence/dao/TermDao.java @@ -410,7 +410,7 @@ public List findAllRoots(Vocabulary vocabulary, Pageable pageSpec, Coll "?vocabulary ?hasGlossary/?hasTerm ?term ." + "BIND((lang(?label) = ?labelLang) as ?hasLocaleLabel) ." + "FILTER (?term NOT IN (?included))" + - "}} ORDER BY DESC(?hasLocaleLabel) " + orderSentence("?label") + "}", + "}} ORDER BY DESC(?hasLocaleLabel) lang(?label) " + orderSentence("?label") + "}", TermDto.class); query = setCommonFindAllRootsQueryParams(query, false); try { @@ -474,7 +474,7 @@ public List findAllRoots(Pageable pageSpec, Collection includeTerm "BIND((lang(?label) = ?labelLang) as ?hasLocaleLabel) ." + "FILTER (?term NOT IN (?included)) . " + "FILTER NOT EXISTS {?term a ?snapshot .} " + - "} ORDER BY DESC(?hasLocaleLabel) " + orderSentence("?label") + "}", + "} ORDER BY DESC(?hasLocaleLabel) lang(?label) " + orderSentence("?label") + "}", TermDto.class); query = setCommonFindAllRootsQueryParams(query, false); try { @@ -559,7 +559,7 @@ public List findAllRootsIncludingImports(Vocabulary vocabulary, Pageabl "?parent ?hasGlossary/?hasTerm ?term ." + "BIND((lang(?label) = ?labelLang) as ?hasLocaleLabel) ." + "FILTER (?term NOT IN (?included))" + - "} ORDER BY DESC(?hasLocaleLabel) " + orderSentence("?label") + "}", + "} ORDER BY DESC(?hasLocaleLabel) lang(?label) " + orderSentence("?label") + "}", TermDto.class); query = setCommonFindAllRootsQueryParams(query, true); try { diff --git a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java index 3b70c160b..62838ba45 100644 --- a/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java +++ b/src/test/java/cz/cvut/kbss/termit/persistence/dao/TermDaoTest.java @@ -756,6 +756,37 @@ void findAllRootsReturnsTermsThatAreMissingDefaultLanguageLabel() { .toList()); } + /** + * terms should be ordered - by language and then lexicographically, with the default language always first + */ + @Test + void findAllRootsReturnsTermsInMultipleLanguagesWithoutPrimaryLabelInCorrectOrder() { + configuration.getPersistence().setLanguage("cs"); + persistTerms("cs", "Německo", "Čína"); + persistTerms("af", "Duitsland", "Sjina"); + persistTerms("en", "Germany", "China"); + persistTerms("pl", "Niemcy", "Chiny"); + persistTerms("da", "Tyskland", "Kina"); + // lang order is: af, cs, da, en, pl + final List result = sut.findAllRoots(vocabulary, Constants.DEFAULT_PAGE_SPEC, Collections.emptyList()); + + // map results to another language than English if possible + final List labels = result.stream().map(r -> { + final Optional lang = r.getLabel().getLanguages().stream().filter(l -> !l.equals("en")).findAny(); + return r.getLabel().get(lang.orElse("en")); + }).toList(); + + final List expectedOrder = Arrays.asList( + "Čína", "Německo", // Czech as first, its default language + "Duitsland", "Sjina", + "Kina", "Tyskland", + "China", "Germany", + "Chiny", "Niemcy"); + + assertEquals(10, result.size()); + assertEquals(expectedOrder, labels); + } + private void persistTerms(String lang, String... labels) { transactional(() -> Arrays.stream(labels).forEach(label -> { final Term parent = Generator.generateTermWithId();