From 0e21e5b4d988d43040573a4fc71547829c815ec0 Mon Sep 17 00:00:00 2001 From: deiflaender Date: Fri, 10 Dec 2021 11:32:53 +0100 Subject: [PATCH] RED-3059: Fixed inital expansion overlaps --- .../redaction/utils/EntitySearchUtils.java | 30 +++++++++++++++--- .../v1/server/RedactionIntegrationTest.java | 17 ++++++++++ .../utils/EntitySearchUtilsTest.java | 6 ++-- .../resources/dictionaries/CBI_author.txt | 7 +++- .../files/Minimal Examples/ExpansionTest.pdf | Bin 0 -> 15322 bytes 5 files changed, 50 insertions(+), 10 deletions(-) create mode 100644 redaction-service-v1/redaction-service-server-v1/src/test/resources/files/Minimal Examples/ExpansionTest.pdf diff --git a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtils.java b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtils.java index 5597e8a4..c67b5644 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtils.java +++ b/redaction-service-v1/redaction-service-server-v1/src/main/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtils.java @@ -193,15 +193,35 @@ public class EntitySearchUtils { Set result = new HashSet<>(); if (existingEntities != null && foundEntities != null) { - for (Entity existingEntity : existingEntities) { - for (Entity foundEntity : foundEntities) { - if (existingEntity.getEnd() < foundEntity.getStart() || foundEntity.getEnd() < existingEntity.getStart()) { - result.add(foundEntity); - } + for (Entity foundEntity : foundEntities) { + + if (!overlaps(existingEntities, foundEntity)) { + result.add(foundEntity); } + } } return result; } + + private boolean overlaps(Set existingEntities, Entity found) { + + for (Entity existing : existingEntities) { + + if(existing.getStart().equals(found.getStart())){ + continue; + } + + for (int i = existing.getStart(); i <= existing.getEnd(); i++) { + for (int j = found.getStart(); j <= found.getEnd(); j++) { + if (i == j) { + return true; + } + } + } + } + return false; + } + } diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java index b4b388bd..1b74e85f 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java +++ b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/RedactionIntegrationTest.java @@ -611,6 +611,23 @@ public class RedactionIntegrationTest { } + @Test + public void redactionExpansionOverlap() throws IOException { + + ClassPathResource pdfFileResource = new ClassPathResource("files/Minimal Examples/ExpansionTest.pdf"); + AnalyzeRequest request = prepareStorage(pdfFileResource.getInputStream()); + + analyzeService.analyzeDocumentStructure(new StructureAnalyzeRequest(request.getDossierId(), request.getFileId())); + AnalyzeResult result = analyzeService.analyze(request); + + var redactionLog = redactionStorageService.getRedactionLog(TEST_DOSSIER_ID, TEST_FILE_ID); + + var values = redactionLog.getRedactionLogEntry().stream().map(RedactionLogEntry::getValue).collect(Collectors.toList()); + + assertThat(values).containsExactlyInAnyOrder("Lastname M.", "Doe", "Doe J.", "M. Mustermann", "Mustermann M.", "F. Lastname"); + } + + @Test @Ignore public void noExceptionShouldBeThrownForAnyFiles() throws IOException { diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtilsTest.java b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtilsTest.java index eec7d419..f1d419d4 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtilsTest.java +++ b/redaction-service-v1/redaction-service-server-v1/src/test/java/com/iqser/red/service/redaction/v1/server/redaction/utils/EntitySearchUtilsTest.java @@ -151,8 +151,7 @@ public class EntitySearchUtilsTest { Set result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities); // Assert - assertThat(result.size()).isEqualTo(1); - assertThat(result).contains(foundEntities2); + assertThat(result.size()).isEqualTo(0); } @@ -182,8 +181,7 @@ public class EntitySearchUtilsTest { Set result = EntitySearchUtils.findNonOverlappingMatchEntities(existingEntities, foundEntities); // Assert - assertThat(result.size()).isEqualTo(1); - assertThat(result).contains(foundEntities2); + assertThat(result.size()).isEqualTo(0); } diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_author.txt b/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_author.txt index 9cf34080..634f9d81 100644 --- a/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_author.txt +++ b/redaction-service-v1/redaction-service-server-v1/src/test/resources/dictionaries/CBI_author.txt @@ -8615,4 +8615,9 @@ Zoriki Hosomi R. Zoriki Hosomi Rosana Zuberer D Zubrod J -Zwicker R.E. \ No newline at end of file +Zwicker R.E. +Doe +M. Mustermann +F. Lastname +Mustermann +Lastname \ No newline at end of file diff --git a/redaction-service-v1/redaction-service-server-v1/src/test/resources/files/Minimal Examples/ExpansionTest.pdf b/redaction-service-v1/redaction-service-server-v1/src/test/resources/files/Minimal Examples/ExpansionTest.pdf new file mode 100644 index 0000000000000000000000000000000000000000..5d55d76a9a5e45efe9b1b019a7341ae6beb5fbbf GIT binary patch literal 15322 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