Skip to content

Commit

Permalink
Merge pull request #38 from Leets-Official/feat/#30/매칭-필터링-및-알고리즘-구현
Browse files Browse the repository at this point in the history
Feat #38 매칭 필터링 및 알고리즘 구현
  • Loading branch information
huncozyboy authored Jan 18, 2025
2 parents 4f991bf + c7889f6 commit 24d7f23
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 24 deletions.
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
package com.gachtaxi.domain.matching.algorithm.service;

import com.gachtaxi.domain.matching.algorithm.dto.FindRoomResult;
import com.gachtaxi.domain.matching.common.entity.MatchingRoom;
import com.gachtaxi.domain.matching.common.entity.enums.Tags;
import java.util.List;
import java.util.Optional;
import org.springframework.data.domain.Page;

public interface MatchingAlgorithmService {

/**
* 방을 찾는 메서드
* 이미 방에 들어가있는 멤버가 다시 요청했을 때 Optional.empty()를 반환하도록 로직을 구성해야함
* @param userId 방에 들어가려는 사용자 ID
* @param startPoint 매칭 시작 지점 좌표
* @param destinationPoint 도착지 좌표
* @param startLongitude 시작 지점 경도
* @param startLatitude 시작 지점 위도
* @param destinationLongitude 도착 지점 경도
* @param destinationLatitude 도착 지점 위도
* @param criteria 방 검색에 필요한 기타 조건 (태그 등)
* @return Optional<FindRoomResult> - 매칭 가능한 방 정보가 있으면 값이 있고, 없으면 empty
*/
Optional<FindRoomResult> findRoom(Long userId, String startPoint, String destinationPoint, List<Tags> criteria);
Optional<FindRoomResult> findRoom(Long userId, double startLongitude, double startLatitude, double destinationLongitude, double destinationLatitude, List<Tags> criteria);

/**
* 전체 매칭 방을 페이지 단위로 조회
*
* @param pageNumber 페이지 번호 (0부터 시작)
* @param pageSize 한 페이지에 포함될 매칭 방의 개수
* @return Page<MatchingRoom> - 페이지별 매칭 방 정보
*/
Page<MatchingRoom> findMatchingRooms(int pageNumber, int pageSize);
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,29 +3,85 @@
import com.gachtaxi.domain.matching.algorithm.dto.FindRoomResult;
import com.gachtaxi.domain.matching.common.entity.MatchingRoom;
import com.gachtaxi.domain.matching.common.entity.enums.Tags;
import com.gachtaxi.domain.matching.common.exception.DuplicatedMatchingRoomException;
import com.gachtaxi.domain.matching.common.exception.PageNotFoundException;
import com.gachtaxi.domain.matching.common.repository.MatchingRoomRepository;
import com.gachtaxi.domain.members.entity.Members;
import com.gachtaxi.domain.members.service.MemberService;
import java.util.List;
import java.util.Optional;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class MockMatchingAlgorithmService implements MatchingAlgorithmService {

private final MatchingRoomRepository matchingRoomRepository;
private final MemberService memberService;

private static final double SEARCH_RADIUS = 300.0;

@Override
public Optional<FindRoomResult> findRoom(Long userId, String startPoint, String destinationPoint, List<Tags> criteria) {
List<MatchingRoom> matchingRoomList = this.matchingRoomRepository.findAll();
if (!matchingRoomList.isEmpty()) {
MatchingRoom matchingRoom = matchingRoomList.get(0);
return Optional.of(
FindRoomResult.builder()
.roomId(matchingRoom.getId())
.maxCapacity(matchingRoom.getCapacity())
.build());
public Optional<FindRoomResult> findRoom(Long userId, double startLongitude, double startLatitude, double destinationLongitude, double destinationLatitude,
List<Tags> criteria) {
/*
사용자 ID로 사용자 정보 조회(이미 방에 참여하고 있는지 중복체크)
*/
Members user = memberService.findById(userId);

if (matchingRoomRepository.existsByMemberInMatchingRoom(user)) {
throw new DuplicatedMatchingRoomException(); // * 추후 논의 후 리팩토링 필요 * 똑같은 조건으로 방 생성시 예외 던져주기
}
/*
위치 정보를 이용한 방 검색(300M 이내)
*/
List<MatchingRoom> matchingRooms = matchingRoomRepository.findRoomsByStartAndDestination(
startLongitude,
startLatitude,
destinationLongitude,
destinationLatitude,
SEARCH_RADIUS
);
/*
ACTIVE 상태인 방만 필터링
*/
matchingRooms = matchingRooms.stream()
.filter(MatchingRoom::isActiveMatchingRoom)
.toList();
/*
태그 조건이 있는 경우에 태그정보까지 필터링
*/
if (criteria != null && !criteria.isEmpty()) {
matchingRooms = matchingRooms.stream()
.filter(room -> criteria.stream().anyMatch(room::containsTag))
.toList();
}
/*
조건에 맞는 방이 있으면 첫 번째 방의 상세 정보 반환
*/
if (!matchingRooms.isEmpty()) {
MatchingRoom room = matchingRooms.get(0);
return Optional.of(room.toFindRoomResult());
}
/*
조건에 맞는 방이 없으면 empty 반환
*/
return Optional.empty();
}
@Override
public Page<MatchingRoom> findMatchingRooms(int pageNumber, int pageSize) {

if (pageNumber < 0) {
throw new PageNotFoundException();
}

PageRequest pageable = PageRequest.of(pageNumber, pageSize, Sort.by(Sort.Direction.DESC, "id"));

return matchingRoomRepository.findAll(pageable);
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package com.gachtaxi.domain.matching.common.entity;

import com.gachtaxi.domain.matching.algorithm.dto.FindRoomResult;
import com.gachtaxi.domain.matching.common.entity.enums.MatchingRoomStatus;
import com.gachtaxi.domain.matching.common.entity.enums.Tags;
import com.gachtaxi.domain.members.entity.Members;
import com.gachtaxi.global.common.entity.BaseEntity;
import jakarta.persistence.CascadeType;
Expand Down Expand Up @@ -59,4 +61,14 @@ public class MatchingRoom extends BaseEntity {
public boolean isActiveMatchingRoom() {
return this.matchingRoomStatus == MatchingRoomStatus.ACTIVE;
}
public boolean containsTag(Tags tag) {
return this.matchingRoomTagInfo.stream()
.anyMatch(tagInfo -> tagInfo.matchesTag(tag));
}
public FindRoomResult toFindRoomResult() {
return FindRoomResult.builder()
.roomId(this.getId())
.maxCapacity(this.getCapacity())
.build();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,8 @@ public class MatchingRoomTagInfo extends BaseEntity {

@Enumerated(EnumType.STRING)
private Tags tags;

public boolean matchesTag(Tags tag) {
return this.tags == tag;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,11 @@
@AllArgsConstructor(access = AccessLevel.PRIVATE)
public class Route extends BaseEntity {

private String startLocationCoordinate;
private double startLongitude;
private double startLatitude;
private String startLocationName;

private String endLocationCoordinate;
private double endLongitude;
private double endLatitude;
private String endLocationName;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.gachtaxi.domain.matching.common.exception;

import static com.gachtaxi.domain.matching.common.exception.ErrorMessage.DUPLICATED_MATCHING_ROOM;
import static org.springframework.http.HttpStatus.BAD_REQUEST;

import com.gachtaxi.global.common.exception.BaseException;

public class DuplicatedMatchingRoomException extends BaseException {
public DuplicatedMatchingRoomException() {
super(BAD_REQUEST, DUPLICATED_MATCHING_ROOM.getMessage());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
public enum ErrorMessage {

NO_SUCH_MATCHING_ROOM("해당 매칭 방이 존재하지 않습니다."),
NOT_ACTIVE_MATCHING_ROOM("열린 매칭 방이 아닙니다.");
NOT_ACTIVE_MATCHING_ROOM("열린 매칭 방이 아닙니다."),
DUPLICATED_MATCHING_ROOM("이미 존재하는 매칭 방입니다."),
NOT_FOUND_PAGE("페이지 번호는 0 이상이어야 합니다.");

private final String message;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.gachtaxi.domain.matching.common.exception;

import com.gachtaxi.global.common.exception.BaseException;
import org.springframework.http.HttpStatus;

public class PageNotFoundException extends BaseException {
public PageNotFoundException() {
super(HttpStatus.NOT_FOUND, ErrorMessage.NOT_FOUND_PAGE.getMessage());
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,28 @@
package com.gachtaxi.domain.matching.common.repository;

import com.gachtaxi.domain.matching.common.entity.MatchingRoom;
import com.gachtaxi.domain.members.entity.Members;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.query.Param;
import org.springframework.stereotype.Repository;

@Repository
public interface MatchingRoomRepository extends JpaRepository<MatchingRoom, Long> {

@Query("SELECT r FROM MatchingRoom r " +
"WHERE " +
"FUNCTION('ST_Distance_Sphere', FUNCTION('POINT', :startLongitude, :startLatitude), FUNCTION('POINT', r.route.startLongitude, r.route.startLatitude)) <= :radius " +
"AND FUNCTION('ST_Distance_Sphere', FUNCTION('POINT', :destinationLongitude, :destinationLatitude), FUNCTION('POINT', r.route.endLongitude, r.route.endLatitude)) <= :radius ")
List<MatchingRoom> findRoomsByStartAndDestination(
@Param("startLongitude") double startLongitude,
@Param("startLatitude") double startLatitude,
@Param("destinationLongitude") double destinationLongitude,
@Param("destinationLatitude") double destinationLatitude,
@Param("radius") double radius
);
@Query("SELECT CASE WHEN COUNT(m) > 0 THEN true ELSE false END " +
"FROM MatchingRoom r JOIN r.memberMatchingRoomChargingInfo m " +
"WHERE m.members = :user")
boolean existsByMemberInMatchingRoom(@Param("user") Members user);
}
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,17 @@ public AutoMatchingPostResponse handlerAutoRequestMatching(
AutoMatchingPostRequest autoMatchingPostRequest
) {
List<Tags> criteria = autoMatchingPostRequest.getCriteria();

String[] startCoordinates = autoMatchingPostRequest.startPoint().split(",");
double startLongitude = Double.parseDouble(startCoordinates[0]);
double startLatitude = Double.parseDouble(startCoordinates[1]);

String[] destinationCoordinates = autoMatchingPostRequest.destinationPoint().split(",");
double destinationLongitude = Double.parseDouble(destinationCoordinates[0]);
double destinationLatitude = Double.parseDouble(destinationCoordinates[1]);

Optional<FindRoomResult> optionalRoom =
this.matchingAlgorithmService.findRoom(memberId, autoMatchingPostRequest.startPoint(),
autoMatchingPostRequest.destinationPoint(), criteria);
this.matchingAlgorithmService.findRoom(memberId, startLongitude, startLatitude, destinationLongitude, destinationLatitude, criteria);

optionalRoom
.ifPresentOrElse(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,13 +57,22 @@ public MatchingRoom save(MatchRoomCreatedEvent matchRoomCreatedEvent) {
}

private Route saveRoute(MatchRoomCreatedEvent matchRoomCreatedEvent) {
Route route = Route.builder()
.startLocationCoordinate(matchRoomCreatedEvent.startPoint())
.startLocationName(matchRoomCreatedEvent.startName())
.endLocationCoordinate(matchRoomCreatedEvent.destinationPoint())
.endLocationName(matchRoomCreatedEvent.destinationName())
.build();
String[] startCoordinates = matchRoomCreatedEvent.startPoint().split(",");
double startLongitude = Double.parseDouble(startCoordinates[0]);
double startLatitude = Double.parseDouble(startCoordinates[1]);

String[] endCoordinates = matchRoomCreatedEvent.destinationPoint().split(",");
double endLongitude = Double.parseDouble(endCoordinates[0]);
double endLatitude = Double.parseDouble(endCoordinates[1]);

Route route = Route.builder()
.startLongitude(startLongitude)
.startLatitude(startLatitude)
.startLocationName(matchRoomCreatedEvent.startName())
.endLongitude(endLongitude)
.endLatitude(endLatitude)
.endLocationName(matchRoomCreatedEvent.destinationName())
.build();
return this.routeRepository.save(route);
}

Expand Down

0 comments on commit 24d7f23

Please sign in to comment.