Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#2312 - Add support for new external recommender v2 #2313

Draft
wants to merge 77 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
77 commits
Select commit Hold shift + click to select a range
3dd2894
#2312 - Add support for new external recommender v2
jcklie May 30, 2021
e893679
#2312 - Add support for new external recommender v2
jcklie May 30, 2021
26738d1
#2312 - Add support for new external recommender v2
jcklie May 30, 2021
5dfdef3
#2312 - Add support for new external recommender v2
jcklie May 30, 2021
a8bc327
#2312 - Add support for new external recommender v2
jcklie May 30, 2021
b2f145c
#2312 - Add support for new external recommender v2
jcklie May 30, 2021
fe09442
#2312 - Add support for new external recommender v2
jcklie May 30, 2021
2f0085f
#2312 - Add support for new external recommender v2
jcklie Jun 5, 2021
dd9f8c8
#2312 - Add support for new external recommender v2
jcklie Jun 5, 2021
3a0d2cd
#2312 - Add support for new external recommender v2
jcklie Jun 5, 2021
31ee5fa
#2312 - Add support for new external recommender v2
jcklie Jun 5, 2021
d611fc8
Merge branch 'master' into feature/2312-external-recommender-v2
jcklie Jun 13, 2021
eebc383
#2312 - Add support for new external recommender v2
jcklie Jun 13, 2021
ba49d5a
#2312 - Add support for new external recommender v2
jcklie Jun 13, 2021
e741152
#2312 - Add support for new external recommender v2
jcklie Jun 16, 2021
0684d17
Merge branch 'master' into feature/2312-external-recommender-v2
jcklie Jun 23, 2021
6863195
#2312 - Add support for new external recommender v2
jcklie Jun 23, 2021
99bc6a8
#2312 - Add support for new external recommender v2
jcklie Jun 23, 2021
a605e94
#2312 - Add support for new external recommender v2
jcklie Jun 24, 2021
b0754cb
#2312 - Add support for new external recommender v2
jcklie Jun 26, 2021
043b89c
Merge branch 'master' into feature/2312-external-recommender-v2
reckart Jun 27, 2021
48667c1
Merge branch 'master' into feature/2312-external-recommender-v2
reckart Jul 22, 2021
c2137cf
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Aug 16, 2021
66cb386
Merge branch 'main' into feature/2312-external-recommender-v2
jcklie Aug 30, 2021
38293c5
Merge branch 'main' into feature/2312-external-recommender-v2
jcklie Sep 20, 2021
d07ae48
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 2, 2021
87aa7dc
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 19, 2021
71bfc6d
Merge branch 'main' into feature/2312-external-recommender-v2
jcklie Nov 18, 2021
4d893e6
#2312 - Add support for new external recommender v2
jcklie Nov 22, 2021
1c14de4
Merge branch 'main' into feature/2312-external-recommender-v2
jcklie Feb 15, 2022
01fb757
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Apr 15, 2022
07151ba
Merge branch 'main' into feature/2312-external-recommender-v2
jcklie May 18, 2022
0967aa6
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 1, 2022
717db29
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 1, 2022
0ce83f9
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 5, 2022
f247b38
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 10, 2022
fab8f79
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 12, 2022
91d9b4b
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 17, 2022
b7c993d
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 21, 2022
dc211df
#2312 - Add support for new external recommender v2
reckart Jun 21, 2022
6b44ee5
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 21, 2022
d0a6b51
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jun 21, 2022
bc95b96
#2312 - Add support for new external recommender v2
reckart Jun 21, 2022
b527d64
#2312 - Add support for new external recommender v2
reckart Jun 21, 2022
f3b21b8
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jul 5, 2022
03281a0
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jul 9, 2022
fbff448
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jul 18, 2022
8b616ce
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jul 19, 2022
fac46e6
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jul 30, 2022
9c03453
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jul 31, 2022
273ceca
#2312 - Add support for new external recommender v2
reckart Jul 31, 2022
b34ddaf
#2312 - Add support for new external recommender v2
reckart Jul 31, 2022
88e3a9d
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Aug 1, 2022
6ed5c5e
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Aug 2, 2022
e566a1e
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Aug 3, 2022
3964363
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Aug 23, 2022
4f634bc
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Sep 4, 2022
03bd612
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Sep 4, 2022
2016e99
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Sep 13, 2022
0df5f98
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 1, 2022
e3d97fb
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 3, 2022
dab8f67
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 10, 2022
47e7fe2
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 28, 2022
591f17e
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Dec 6, 2022
2ff4386
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jan 4, 2023
c97f612
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Feb 28, 2023
60d6ac6
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Mar 7, 2023
7b05ea1
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Mar 30, 2023
9ef052c
Merge branch 'main' into feature/2312-external-recommender-v2
reckart May 17, 2023
d4f2d1c
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Jul 30, 2023
527ac03
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 14, 2023
d8b115f
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Nov 21, 2023
9f23436
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Nov 24, 2023
ea684f7
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Nov 27, 2023
0012050
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Mar 9, 2024
208dc92
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Sep 8, 2024
168fd5e
Merge branch 'main' into feature/2312-external-recommender-v2
reckart Oct 1, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 17 additions & 5 deletions inception/inception-imls-external/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-annotation-storage-api</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-annotation-storage</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-api-render</artifactId>
Expand All @@ -47,6 +51,10 @@
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-support</artifactId>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-security</artifactId>
</dependency>

<dependency>
<groupId>commons-io</groupId>
Expand Down Expand Up @@ -79,6 +87,11 @@
<artifactId>uimafit-core</artifactId>
</dependency>

<dependency>
<groupId>org.dkpro.core</groupId>
<artifactId>dkpro-core-api-segmentation-asl</artifactId>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
Expand All @@ -100,6 +113,10 @@
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
Expand All @@ -122,11 +139,6 @@
<artifactId>inception-testing</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>de.tudarmstadt.ukp.inception.app</groupId>
<artifactId>inception-annotation-storage</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dkpro.core</groupId>
<artifactId>dkpro-core-io-conll-asl</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@
/**
* <p>
* This class is exposed as a Spring Component via
* {@link ExternalRecommenderAutoConfiguration#externalRecommenderFactory}.
* {@link ExternalRecommenderAutoConfiguration#externalRecommenderFactoryV1}.
* </p>
*/
public class ExternalRecommenderFactory
Expand Down Expand Up @@ -66,7 +66,7 @@ public RecommendationEngine build(Recommender aRecommender)
@Override
public String getName()
{
return "Remote classifier";
return "Remote classifier V1";
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,13 @@
import de.tudarmstadt.ukp.inception.recommendation.imls.external.v1.ExternalRecommenderFactory;

@Configuration
@ConditionalOnProperty(prefix = "recommender.external", name = "enabled", havingValue = "true", matchIfMissing = true)
@ConditionalOnProperty(prefix = "recommender.external.v1", name = "enabled", havingValue = "true", //
matchIfMissing = true)
@EnableConfigurationProperties(ExternalRecommenderPropertiesImpl.class)
public class ExternalRecommenderAutoConfiguration
{
@Bean
public ExternalRecommenderFactory externalRecommenderFactory(
public ExternalRecommenderFactory externalRecommenderFactoryV1(
ExternalRecommenderProperties aProperties)
{
return new ExternalRecommenderFactory(aProperties);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,260 @@
/*
* Licensed to the Technische Universität Darmstadt under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The Technische Universität Darmstadt
* licenses this file to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License.
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.tudarmstadt.ukp.inception.recommendation.imls.external.v2;

import static de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil.getDocumentTitle;
import static de.tudarmstadt.ukp.clarin.webanno.api.annotation.util.WebAnnoCasUtil.getRealCas;
import static de.tudarmstadt.ukp.inception.recommendation.api.recommender.TrainingCapability.TRAINING_NOT_SUPPORTED;
import static de.tudarmstadt.ukp.inception.recommendation.api.recommender.TrainingCapability.TRAINING_REQUIRED;

import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.uima.cas.CAS;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.tudarmstadt.ukp.clarin.webanno.model.Project;
import de.tudarmstadt.ukp.clarin.webanno.security.model.User;
import de.tudarmstadt.ukp.inception.annotation.storage.CasMetadataUtils;
import de.tudarmstadt.ukp.inception.recommendation.api.evaluation.DataSplitter;
import de.tudarmstadt.ukp.inception.recommendation.api.evaluation.EvaluationResult;
import de.tudarmstadt.ukp.inception.recommendation.api.model.Recommender;
import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationEngine;
import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommendationException;
import de.tudarmstadt.ukp.inception.recommendation.api.recommender.RecommenderContext;
import de.tudarmstadt.ukp.inception.recommendation.api.recommender.TrainingCapability;
import de.tudarmstadt.ukp.inception.recommendation.imls.external.v2.api.Document;
import de.tudarmstadt.ukp.inception.recommendation.imls.external.v2.api.DocumentList;
import de.tudarmstadt.ukp.inception.recommendation.imls.external.v2.api.ExternalRecommenderApiException;
import de.tudarmstadt.ukp.inception.recommendation.imls.external.v2.api.ExternalRecommenderV2Api;
import de.tudarmstadt.ukp.inception.recommendation.imls.external.v2.api.FormatConverter;
import de.tudarmstadt.ukp.inception.recommendation.imls.external.v2.config.ExternalRecommenderProperties;
import de.tudarmstadt.ukp.inception.rendering.model.Range;

public class ExternalRecommender
extends RecommendationEngine
{
private final static Logger LOG = LoggerFactory.getLogger(ExternalRecommender.class);

public static final RecommenderContext.Key<Boolean> KEY_TRAINING_COMPLETE = new RecommenderContext.Key<>(
"training_complete");

private final ExternalRecommenderProperties properties;
private final ExternalRecommenderTraits traits;
private final ExternalRecommenderV2Api api;

public ExternalRecommender(ExternalRecommenderProperties aProperties, Recommender aRecommender,
ExternalRecommenderTraits aTraits)
{
super(aRecommender);

properties = aProperties;
traits = aTraits;
api = new ExternalRecommenderV2Api(URI.create(traits.getRemoteUrl()),
properties.getConnectTimeout());
}

@Override
public void train(RecommenderContext aContext, List<CAS> aCasses) throws RecommendationException
{
if (aContext.getUser().isEmpty()) {
LOG.warn("No user found in context, skipping training...");
return;
}

User user = aContext.getUser().get();
Project project = recommender.getProject();
String datasetName = buildDatasetName(project, user);
String classifierName = buildClassifierName();
String modelName = buildModelName(project, user);

api.createDataset(datasetName);
synchronizeDocuments(aCasses, datasetName);
api.trainOnDataset(classifierName, modelName, datasetName);

aContext.put(KEY_TRAINING_COMPLETE, true);
}

private void synchronizeDocuments(List<CAS> aCasses, String aDatasetName)
throws RecommendationException
{
LOG.debug("Synchronizing documents for [{}]", aDatasetName);

// Get info about remote documents
DocumentList documentList = api.listDocumentsInDataset(aDatasetName);
Map<String, Long> remoteVersions = new HashMap<>();
if (documentList.getNames().size() != documentList.getVersions().size()) {
throw new RecommendationException(
"Names and versions in document list have unequal size");
}

for (int i = 0; i < documentList.getNames().size(); i++) {
remoteVersions.put(documentList.getNames().get(i), documentList.getVersions().get(i));
}

// Sync documents
List<CAS> documentsToSend = new ArrayList<>();
Set<String> seenLocalDocuments = new HashSet<>();

for (CAS cas : aCasses) {
String documentName = getDocumentName(cas);
seenLocalDocuments.add(documentName);

// If the document is not known to the remote server, then we need to update it
if (!remoteVersions.containsKey(documentName)) {
documentsToSend.add(cas);
continue;
}

// If the version is unclear or our local version is newer, then we need to update it
long localVersion = getVersion(cas);
long remoteVersion = remoteVersions.getOrDefault(documentName, -1L);
if (localVersion == -1L || remoteVersion == -1L || localVersion > remoteVersion) {
documentsToSend.add(cas);
continue;
}
}

// All documents that have not been seen locally but are listed remotely need to be deleted
Set<String> documentsToDelete = remoteVersions.keySet();
documentsToDelete.removeAll(seenLocalDocuments);

for (String name : documentsToDelete) {
api.deleteDocumentFromDataset(aDatasetName, name);
}

LOG.debug("Deleted [{}] documents", documentsToDelete.size());

// Finally, send new/updated documents
FormatConverter converter = new FormatConverter();
for (CAS cas : documentsToSend) {
String documentName = getDocumentName(cas);
long version = getVersion(cas);
String layerName = recommender.getLayer().getName();
String featureName = recommender.getFeature().getName();
Document document = converter.documentFromCas(cas, layerName, featureName, version);

api.addDocumentToDataset(aDatasetName, documentName, document);
}

LOG.debug("Sent [{}] documents", documentsToSend.size());
}

@Override
public Range predict(RecommenderContext aContext, CAS aCas, int aBegin, int aEnd)
throws RecommendationException
{
CAS cas = getRealCas(aCas);

if (aContext.getUser().isEmpty()) {
LOG.warn("No user found in context, skipping predictions...");
return Range.UNDEFINED;
}

long version = 0;

FormatConverter converter = new FormatConverter();
String layerName = recommender.getLayer().getName();
String featureName = recommender.getFeature().getName();

Document request = converter.documentFromCas(cas, layerName, featureName, version);

String modelName = buildModelName(recommender.getProject(), aContext.getUser().get());
String classifierName = traits.getClassifierInfo().getName();

try {
Document response = api.predict(classifierName, modelName, request);
converter.loadIntoCas(response, layerName, featureName, cas);
}
catch (ExternalRecommenderApiException e) {
LOG.error("Could not obtain predictions, skipping...");
}

return new Range(aBegin, aEnd);
}

@Override
public EvaluationResult evaluate(List<CAS> aCasses, DataSplitter aDataSplitter)
throws RecommendationException
{
return null;
}

@Override
public boolean isReadyForPrediction(RecommenderContext aContext)
{
if (traits.isTrainable()) {
return aContext.get(KEY_TRAINING_COMPLETE).orElse(false);
}
else {
return true;
}
}

@Override
public int estimateSampleCount(List<CAS> aCasses)
{
return 0;
}

@Override
public TrainingCapability getTrainingCapability()
{
if (traits.isTrainable()) {
//
// return TRAINING_SUPPORTED;
// We need to get at least one training CAS because we need to extract the type system
return TRAINING_REQUIRED;
}
else {
return TRAINING_NOT_SUPPORTED;
}
}

private String buildClassifierName()
{
return traits.getClassifierInfo().getName();
}

private String buildModelName(Project aProject, User aUser)
{
return aProject.getId() + "_" + aUser.getUsername() + "_" + recommender.getId();
}

private String buildDatasetName(Project aProject, User aUser)
{
return aProject.getId() + "_" + aUser.getUsername();
}

private String getDocumentName(CAS aCas)
{
return CasMetadataUtils.getSourceDocumentName(aCas).orElse(getDocumentTitle(aCas));
}

private long getVersion(CAS aCas)
{
return CasMetadataUtils.getLastChanged(aCas);
}

}
Loading
Loading