Skip to content
Snippets Groups Projects
Commit 43f6c587 authored by Thiemo Belmega's avatar Thiemo Belmega
Browse files

Modify lookup algorithm to find best match instead of exact match

parent aac609df
No related branches found
No related tags found
No related merge requests found
...@@ -3,13 +3,11 @@ package de.unipotsdam.cs.toolup.model; ...@@ -3,13 +3,11 @@ package de.unipotsdam.cs.toolup.model;
import de.unipotsdam.cs.toolup.database.DatabaseController; import de.unipotsdam.cs.toolup.database.DatabaseController;
import de.unipotsdam.cs.toolup.exceptions.InvalidIdException; import de.unipotsdam.cs.toolup.exceptions.InvalidIdException;
import de.unipotsdam.cs.toolup.util.SubsetUtil;
import java.io.IOException; import java.io.IOException;
import java.sql.SQLException; import java.sql.SQLException;
import java.util.Arrays; import java.util.*;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
public class ApplicationLookup { public class ApplicationLookup {
...@@ -23,8 +21,33 @@ public class ApplicationLookup { ...@@ -23,8 +21,33 @@ public class ApplicationLookup {
public Set<Application> getApplications() throws IOException, SQLException, InvalidIdException { public Set<Application> getApplications() throws IOException, SQLException, InvalidIdException {
throwExceptionIfNoFeaturesAreSpecified(); throwExceptionIfNoFeaturesAreSpecified();
Set<String> intersectionOfApps = buildIntersectionOfRelatedApplications(); Set<String> resultSetOfApps = getApplicationsWithLargestSubSetOfFeatures();
return loadApplicationsByIds(intersectionOfApps); return loadApplicationsByIds(resultSetOfApps);
}
/**
* This method gets all Applications that match the whole feature list;
* if there are none, it gets the Applications that match the feature subsets with one feature missing;
* if the are none, with two features missing and so on.
*/
private Set<String> getApplicationsWithLargestSubSetOfFeatures() throws SQLException, InvalidIdException, IOException {
Set<String> resultSetOfApps = new HashSet<>();
int sizeOfFeatureList = features.size();
while (resultSetOfApps.isEmpty() && sizeOfFeatureList > 0) {
addAllApplicationsThatMatchFeatureSubsetsOfGivenSize(resultSetOfApps, sizeOfFeatureList);
sizeOfFeatureList--;
}
return resultSetOfApps;
}
private void addAllApplicationsThatMatchFeatureSubsetsOfGivenSize(Set<String> resultSetOfApps, int sizeOfFeatureList) throws SQLException, InvalidIdException, IOException {
Set<Set<String>> allSubSetsOfFeatures = SubsetUtil.getAllSubsetsOfSize(new HashSet<String>(features), sizeOfFeatureList);
for (Set<String> subSetOfFeatures : allSubSetsOfFeatures) {
Set<String> applicationsForFeatureSubSet = buildIntersectionOfRelatedApplications(new ArrayList<String>(subSetOfFeatures));
resultSetOfApps.addAll(applicationsForFeatureSubSet);
}
} }
private void throwExceptionIfNoFeaturesAreSpecified() { private void throwExceptionIfNoFeaturesAreSpecified() {
...@@ -33,15 +56,15 @@ public class ApplicationLookup { ...@@ -33,15 +56,15 @@ public class ApplicationLookup {
} }
} }
private Set<String> buildIntersectionOfRelatedApplications() throws SQLException, InvalidIdException, IOException { private Set<String> buildIntersectionOfRelatedApplications(List<String> featureList) throws SQLException, InvalidIdException, IOException {
//load the related applications of the first feature //load the related applications of the first feature
String firstFeatureId = features.get(0).trim(); String firstFeatureId = featureList.get(0).trim();
Set<String> intersectionOfApps = DatabaseController.getInstance() Set<String> intersectionOfApps = DatabaseController.getInstance()
.loadRelatedApplicationsForFeat(firstFeatureId); .loadRelatedApplicationsForFeat(firstFeatureId);
//if there is more than one feature, make the intersection of the result sets //if there is more than one feature, make the intersection of the result sets
for (int i = 1; i < features.size(); i++) { for (int i = 1; i < featureList.size(); i++) {
String id = features.get(i).trim(); String id = featureList.get(i).trim();
Set<String> apps = DatabaseController.getInstance() Set<String> apps = DatabaseController.getInstance()
.loadRelatedApplicationsForFeat(id); .loadRelatedApplicationsForFeat(id);
intersectionOfApps.retainAll(apps); intersectionOfApps.retainAll(apps);
...@@ -49,6 +72,7 @@ public class ApplicationLookup { ...@@ -49,6 +72,7 @@ public class ApplicationLookup {
return intersectionOfApps; return intersectionOfApps;
} }
private Set<Application> loadApplicationsByIds(Set<String> intersectionOfApps) throws SQLException, InvalidIdException, IOException { private Set<Application> loadApplicationsByIds(Set<String> intersectionOfApps) throws SQLException, InvalidIdException, IOException {
Set<Application> resultSetOfApps = new HashSet<>(); Set<Application> resultSetOfApps = new HashSet<>();
for (String id: intersectionOfApps){ for (String id: intersectionOfApps){
......
package de.unipotsdam.cs.toolup.ws.resource; package de.unipotsdam.cs.toolup.ws.resource;
import de.unipotsdam.cs.toolup.model.Application;
import de.unipotsdam.cs.toolup.model.ApplicationLookup; import de.unipotsdam.cs.toolup.model.ApplicationLookup;
import de.unipotsdam.cs.toolup.ws.beans.ApplicationBean; import de.unipotsdam.cs.toolup.ws.beans.ApplicationBean;
...@@ -9,6 +10,7 @@ import javax.ws.rs.Path; ...@@ -9,6 +10,7 @@ import javax.ws.rs.Path;
import javax.ws.rs.Produces; import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType; import javax.ws.rs.core.MediaType;
import java.util.Collection; import java.util.Collection;
import java.util.Set;
@Path("lookup") @Path("lookup")
...@@ -17,7 +19,9 @@ public class LookupResource { ...@@ -17,7 +19,9 @@ public class LookupResource {
@POST @POST
@Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
public Collection<ApplicationBean> post(@FormParam("features") String features) throws Exception { public Collection<ApplicationBean> post(@FormParam("features") String features) throws Exception {
return ApplicationBean.getBeans(new ApplicationLookup(features).getApplications()); ApplicationLookup lookup = new ApplicationLookup(features);
Set<Application> applications = lookup.getApplications();
return ApplicationBean.getBeans(applications);
} }
......
...@@ -17,6 +17,7 @@ public class BusinessObjectTest { ...@@ -17,6 +17,7 @@ public class BusinessObjectTest {
public static final String FEATURE_TEST_ID_21 = "feature-test_id_21"; public static final String FEATURE_TEST_ID_21 = "feature-test_id_21";
public static final String FEATURE_TEST_ID_22 = "feature-test_id_22"; public static final String FEATURE_TEST_ID_22 = "feature-test_id_22";
public static final String FEATURE_TEST_ID_23 = "feature-test_id_23";
public static final String APPLICATION_TEST_ID_1 = "application-test_id_1"; public static final String APPLICATION_TEST_ID_1 = "application-test_id_1";
public static final String APPLICATION_TEST_ID_2 = "application-test_id_2"; public static final String APPLICATION_TEST_ID_2 = "application-test_id_2";
public static final String CATEGORY_TEST_ID_11 = "category-test_id_11"; public static final String CATEGORY_TEST_ID_11 = "category-test_id_11";
......
...@@ -4,41 +4,101 @@ package de.unipotsdam.cs.toolup.ws.resource; ...@@ -4,41 +4,101 @@ package de.unipotsdam.cs.toolup.ws.resource;
import de.unipotsdam.cs.toolup.ws.beans.ApplicationBean; import de.unipotsdam.cs.toolup.ws.beans.ApplicationBean;
import org.testng.annotations.Test; import org.testng.annotations.Test;
import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.List; import java.util.List;
import static de.unipotsdam.cs.toolup.model.BusinessObjectTest.*; import static de.unipotsdam.cs.toolup.model.BusinessObjectTest.*;
import static de.unipotsdam.cs.toolup.util.AssertionUtil.assertContainsAll;
import static org.testng.AssertJUnit.assertTrue; import static org.testng.AssertJUnit.assertTrue;
@SuppressWarnings("ALL")
public class LookupResourceTest { public class LookupResourceTest {
@Test @Test
public void testThatPostRequestReturnsMapOfApplicationBeans() throws Exception { public void testThatPostRequestReturnsMapOfApplicationBeans() throws Exception {
//arrange //arrange
ApplicationBean app = ApplicationBean.getBean(APPLICATION_TEST_ID_1); ApplicationBean app = ApplicationBean.getBean(APPLICATION_TEST_ID_1);
LookupResource lookupResource = new LookupResource(); LookupResource lookupResource = new LookupResource();
//act //act
Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_21 + ", " + FEATURE_TEST_ID_22); Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_21 + ", " + FEATURE_TEST_ID_22);
//assert //assert
assertTrue(apps.contains(app)); assertTrue(apps.contains(app));
} }
@Test @Test
public void testThatPostRequestReturnsMapOfApplicationBeans2() throws Exception { public void testThatPostRequestReturnsMapOfApplicationBeans2() throws Exception {
//arrange //arrange
ApplicationBean app1 = ApplicationBean.getBean(APPLICATION_TEST_ID_1); ApplicationBean app1 = ApplicationBean.getBean(APPLICATION_TEST_ID_1);
ApplicationBean app2 = ApplicationBean.getBean(APPLICATION_TEST_ID_2); ApplicationBean app2 = ApplicationBean.getBean(APPLICATION_TEST_ID_2);
List<ApplicationBean> expectedApps = Arrays.asList(app1, app2); List<ApplicationBean> expectedApps = Arrays.asList(app1, app2);
LookupResource lookupResource = new LookupResource(); LookupResource lookupResource = new LookupResource();
//act //act
Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_21); Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_21);
//assert //assert
assertTrue(apps.containsAll(expectedApps)); assertTrue(apps.containsAll(expectedApps));
} }
@Test
public void testThatLookUpWithoutMatchingResultReturnsBestMatch() throws Exception {
//arrange
ApplicationBean app1 = ApplicationBean.getBean(APPLICATION_TEST_ID_1);
List<ApplicationBean> expectedApps = Arrays.asList(app1);
LookupResource lookupResource = new LookupResource();
//act
Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_22 + ", " + FEATURE_TEST_ID_23);
//assert
assertContainsAll(apps, expectedApps);
}
@Test
public void testThatLookUpWithoutMatchingResultReturnsBestMatch2() throws Exception {
//arrange
ApplicationBean app1 = ApplicationBean.getBean(APPLICATION_TEST_ID_1);
List<ApplicationBean> expectedApps = Arrays.asList(app1);
LookupResource lookupResource = new LookupResource();
//act
Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_21 + ", " + FEATURE_TEST_ID_22 + ", " + FEATURE_TEST_ID_23);
//assert
assertContainsAll(apps, expectedApps);
}
@Test
public void testThatLookUpWithoutMatchingResultReturnsBestMatch3() throws Exception {
//arrange
ApplicationBean app1 = ApplicationBean.getBean(APPLICATION_TEST_ID_1);
ApplicationBean app2 = ApplicationBean.getBean(APPLICATION_TEST_ID_2);
List<ApplicationBean> expectedApps = Arrays.asList(app1, app2);
LookupResource lookupResource = new LookupResource();
//act
Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_21 + ", " + FEATURE_TEST_ID_23);
//assert
assertContainsAll(apps, expectedApps);
}
@Test
public void testThatLookUpWithoutMatchingResultReturnsEmptyArray() throws Exception {
//arrange
List<ApplicationBean> expectedApps = new ArrayList<>();
LookupResource lookupResource = new LookupResource();
//act
Collection<ApplicationBean> apps = lookupResource.post(FEATURE_TEST_ID_23);
//assert
assertContainsAll(apps, expectedApps);
}
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment