package fr.ippon.tatami.service; import fr.ippon.tatami.domain.Group; import fr.ippon.tatami.domain.User; import fr.ippon.tatami.repository.UserGroupRepository; import fr.ippon.tatami.service.util.DomainUtil; import org.springframework.cache.annotation.Cacheable; import org.springframework.stereotype.Service; import javax.inject.Inject; import java.util.*; import static fr.ippon.tatami.service.util.AnalysisUtil.findMostUsedKeys; import static fr.ippon.tatami.service.util.AnalysisUtil.incrementKeyCounterInMap; import static fr.ippon.tatami.service.util.AnalysisUtil.reduceCollectionSize; /** * Analyses data to find suggestions of users, groups... for the current user. */ @Service public class SuggestionService { private static final int SAMPLE_SIZE = 20; private static final int SUB_SAMPLE_SIZE = 100; private static final int SUGGESTIONS_SIZE = 3; @Inject private FriendshipService friendshipService; @Inject private UserGroupRepository userGroupRepository; @Inject private UserService userService; @Inject private GroupService groupService; /** * Size of the sample data used to find the suggestions. */ @Cacheable("suggest-users-cache") public Collection<User> suggestUsers(String login) { Map<String, Integer> userCount = new HashMap<String, Integer>(); List<String> friendIds = friendshipService.getFriendIdsForUser(login); List<String> sampleFriendIds = reduceCollectionSize(friendIds, SAMPLE_SIZE); for (String friendId : sampleFriendIds) { List<String> friendsOfFriend = friendshipService.getFriendIdsForUser(friendId); friendsOfFriend = reduceCollectionSize(friendsOfFriend, SUB_SAMPLE_SIZE); for (String friendOfFriend : friendsOfFriend) { if (!friendIds.contains(friendOfFriend) && !friendOfFriend.equals(login)) { incrementKeyCounterInMap(userCount, friendOfFriend); } } } List<String> mostFollowedUsers = findMostUsedKeys(userCount); List<User> userSuggestions = new ArrayList<User>(); for (String mostFollowedUser : mostFollowedUsers) { User suggestion = userService.getUserByLogin(mostFollowedUser); if ( suggestion.getActivated() ){ userSuggestions.add(suggestion); } } if (userSuggestions.size() > SUGGESTIONS_SIZE) { return userSuggestions.subList(0, SUGGESTIONS_SIZE); } else { return userSuggestions; } } @Cacheable("suggest-groups-cache") public Collection<Group> suggestGroups(String login) { Map<String, Integer> groupCount = new HashMap<String, Integer>(); List<String> groupIds = userGroupRepository.findGroups(login); List<String> friendIds = friendshipService.getFriendIdsForUser(login); friendIds = reduceCollectionSize(friendIds, SAMPLE_SIZE); for (String friendId : friendIds) { List<String> groupsOfFriend = userGroupRepository.findGroups(friendId); for (String groupOfFriend : groupsOfFriend) { if (!groupIds.contains(groupOfFriend)) { incrementKeyCounterInMap(groupCount, groupOfFriend); } } } List<String> mostFollowedGroups = findMostUsedKeys(groupCount); List<Group> groupSuggestions = new ArrayList<Group>(); String domain = DomainUtil.getDomainFromLogin(login); for (String mostFollowedGroup : mostFollowedGroups) { Group suggestion = groupService.getGroupById(domain, mostFollowedGroup); if (suggestion.isPublicGroup()) { // Only suggest public groups for the moment groupSuggestions.add(suggestion); } } if (groupSuggestions.size() > SUGGESTIONS_SIZE) { return groupSuggestions.subList(0, SUGGESTIONS_SIZE); } else { return groupSuggestions; } } }