diff --git a/src/main/java/com/wayble/server/ServerApplication.java b/src/main/java/com/wayble/server/ServerApplication.java index 9f0a50f6..2729f1c1 100644 --- a/src/main/java/com/wayble/server/ServerApplication.java +++ b/src/main/java/com/wayble/server/ServerApplication.java @@ -1,6 +1,6 @@ package com.wayble.server; -import com.wayble.server.direction.external.tmap.TMapProperties; +import com.wayble.server.common.client.tmap.TMapProperties; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.data.elasticsearch.ReactiveElasticsearchRepositoriesAutoConfiguration; @@ -15,7 +15,9 @@ ) @EnableJpaAuditing @EnableScheduling -@EnableElasticsearchRepositories(basePackages = {"com.wayble.server.explore.repository", "com.wayble.server.logging.repository"}) +@EnableElasticsearchRepositories(basePackages = { + "com.wayble.server.explore.repository", "com.wayble.server.direction.repository", "com.wayble.server.logging.repository" +}) @EnableConfigurationProperties(TMapProperties.class) @EntityScan(basePackages = "com.wayble.server") public class ServerApplication { diff --git a/src/main/java/com/wayble/server/direction/external/tmap/TMapClient.java b/src/main/java/com/wayble/server/common/client/tmap/TMapClient.java similarity index 79% rename from src/main/java/com/wayble/server/direction/external/tmap/TMapClient.java rename to src/main/java/com/wayble/server/common/client/tmap/TMapClient.java index de82b483..09a3212b 100644 --- a/src/main/java/com/wayble/server/direction/external/tmap/TMapClient.java +++ b/src/main/java/com/wayble/server/common/client/tmap/TMapClient.java @@ -1,7 +1,7 @@ -package com.wayble.server.direction.external.tmap; +package com.wayble.server.common.client.tmap; -import com.wayble.server.direction.external.tmap.dto.request.TMapRequest; -import com.wayble.server.direction.external.tmap.dto.response.TMapResponse; +import com.wayble.server.common.client.tmap.dto.request.TMapRequest; +import com.wayble.server.common.client.tmap.dto.response.TMapResponse; import lombok.RequiredArgsConstructor; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; diff --git a/src/main/java/com/wayble/server/direction/external/tmap/TMapProperties.java b/src/main/java/com/wayble/server/common/client/tmap/TMapProperties.java similarity index 80% rename from src/main/java/com/wayble/server/direction/external/tmap/TMapProperties.java rename to src/main/java/com/wayble/server/common/client/tmap/TMapProperties.java index 16589a2c..7f8e30ad 100644 --- a/src/main/java/com/wayble/server/direction/external/tmap/TMapProperties.java +++ b/src/main/java/com/wayble/server/common/client/tmap/TMapProperties.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.external.tmap; +package com.wayble.server.common.client.tmap; import org.springframework.boot.context.properties.ConfigurationProperties; diff --git a/src/main/java/com/wayble/server/direction/external/tmap/dto/request/TMapRequest.java b/src/main/java/com/wayble/server/common/client/tmap/dto/request/TMapRequest.java similarity index 76% rename from src/main/java/com/wayble/server/direction/external/tmap/dto/request/TMapRequest.java rename to src/main/java/com/wayble/server/common/client/tmap/dto/request/TMapRequest.java index a10f9d12..d10d8e3f 100644 --- a/src/main/java/com/wayble/server/direction/external/tmap/dto/request/TMapRequest.java +++ b/src/main/java/com/wayble/server/common/client/tmap/dto/request/TMapRequest.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.external.tmap.dto.request; +package com.wayble.server.common.client.tmap.dto.request; import lombok.Builder; diff --git a/src/main/java/com/wayble/server/direction/external/tmap/dto/response/TMapParsingResponse.java b/src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapParsingResponse.java similarity index 97% rename from src/main/java/com/wayble/server/direction/external/tmap/dto/response/TMapParsingResponse.java rename to src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapParsingResponse.java index 028b06b9..91ffeefd 100644 --- a/src/main/java/com/wayble/server/direction/external/tmap/dto/response/TMapParsingResponse.java +++ b/src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapParsingResponse.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.external.tmap.dto.response; +package com.wayble.server.common.client.tmap.dto.response; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Builder; diff --git a/src/main/java/com/wayble/server/direction/external/tmap/dto/response/TMapResponse.java b/src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapResponse.java similarity index 93% rename from src/main/java/com/wayble/server/direction/external/tmap/dto/response/TMapResponse.java rename to src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapResponse.java index 3d8d4ff9..ee35731a 100644 --- a/src/main/java/com/wayble/server/direction/external/tmap/dto/response/TMapResponse.java +++ b/src/main/java/com/wayble/server/common/client/tmap/dto/response/TMapResponse.java @@ -1,4 +1,4 @@ -package com.wayble.server.direction.external.tmap.dto.response; +package com.wayble.server.common.client.tmap.dto.response; import java.util.List; diff --git a/src/main/java/com/wayble/server/direction/external/tmap/mapper/TMapMapper.java b/src/main/java/com/wayble/server/common/client/tmap/mapper/TMapMapper.java similarity index 94% rename from src/main/java/com/wayble/server/direction/external/tmap/mapper/TMapMapper.java rename to src/main/java/com/wayble/server/common/client/tmap/mapper/TMapMapper.java index 2111d396..625e018d 100644 --- a/src/main/java/com/wayble/server/direction/external/tmap/mapper/TMapMapper.java +++ b/src/main/java/com/wayble/server/common/client/tmap/mapper/TMapMapper.java @@ -1,7 +1,7 @@ -package com.wayble.server.direction.external.tmap.mapper; +package com.wayble.server.common.client.tmap.mapper; -import com.wayble.server.direction.external.tmap.dto.response.TMapParsingResponse; -import com.wayble.server.direction.external.tmap.dto.response.TMapResponse; +import com.wayble.server.common.client.tmap.dto.response.TMapResponse; +import com.wayble.server.common.client.tmap.dto.response.TMapParsingResponse; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Component; diff --git a/src/main/java/com/wayble/server/common/config/WebClientConfig.java b/src/main/java/com/wayble/server/common/config/WebClientConfig.java index afe087b9..db69178a 100644 --- a/src/main/java/com/wayble/server/common/config/WebClientConfig.java +++ b/src/main/java/com/wayble/server/common/config/WebClientConfig.java @@ -1,6 +1,6 @@ package com.wayble.server.common.config; -import com.wayble.server.direction.external.tmap.TMapProperties; +import com.wayble.server.common.client.tmap.TMapProperties; import lombok.RequiredArgsConstructor; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; diff --git a/src/main/java/com/wayble/server/direction/controller/DirectionController.java b/src/main/java/com/wayble/server/direction/controller/DirectionController.java index 2e0f99ab..42565fb0 100644 --- a/src/main/java/com/wayble/server/direction/controller/DirectionController.java +++ b/src/main/java/com/wayble/server/direction/controller/DirectionController.java @@ -1,29 +1,33 @@ package com.wayble.server.direction.controller; import com.wayble.server.common.response.CommonResponse; +import com.wayble.server.direction.controller.swagger.DirectionSwagger; +import com.wayble.server.direction.dto.request.PlaceSaveRequest; +import com.wayble.server.direction.dto.response.DirectionSearchResponse; import com.wayble.server.direction.service.DirectionService; +import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RestController; +import org.springframework.web.bind.annotation.*; + +import java.util.List; @RestController @RequiredArgsConstructor -@RequestMapping("/directions") -public class DirectionController { +@RequestMapping("/api/v1/directions") +public class DirectionController implements DirectionSwagger { private final DirectionService directionService; - // 참고용 컨트롤러(지우셔도 돼요) - @GetMapping("/hello") - public CommonResponse hello() { - return CommonResponse.success("hello"); + @Override + @PostMapping("/place") + public CommonResponse savePlace(@RequestBody @Valid PlaceSaveRequest request) { + directionService.savePlaceAndIndexDocument(request.requests()); + return CommonResponse.success("Place Save successful"); } - // 예외 사용 참고용 컨트롤러(지우셔도 돼요) - @GetMapping("/ex") - public CommonResponse exception() { - directionService.makeException(); - return CommonResponse.success("예외 발생!"); + @Override + @GetMapping("/auto-complete") + public CommonResponse> getDirectionKeywords(@RequestParam String keyword) { + return CommonResponse.success(directionService.searchDirection(keyword)); } } diff --git a/src/main/java/com/wayble/server/direction/controller/WalkingController.java b/src/main/java/com/wayble/server/direction/controller/WalkingController.java index 327d3d4c..725c0af1 100644 --- a/src/main/java/com/wayble/server/direction/controller/WalkingController.java +++ b/src/main/java/com/wayble/server/direction/controller/WalkingController.java @@ -3,8 +3,8 @@ import com.wayble.server.common.response.CommonResponse; import com.wayble.server.direction.controller.swagger.WalkingSwagger; import com.wayble.server.direction.dto.response.WayblePathResponse; -import com.wayble.server.direction.external.tmap.dto.request.TMapRequest; -import com.wayble.server.direction.external.tmap.dto.response.TMapParsingResponse; +import com.wayble.server.common.client.tmap.dto.request.TMapRequest; +import com.wayble.server.common.client.tmap.dto.response.TMapParsingResponse; import com.wayble.server.direction.service.WalkingService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; diff --git a/src/main/java/com/wayble/server/direction/controller/swagger/DirectionSwagger.java b/src/main/java/com/wayble/server/direction/controller/swagger/DirectionSwagger.java new file mode 100644 index 00000000..f897b56e --- /dev/null +++ b/src/main/java/com/wayble/server/direction/controller/swagger/DirectionSwagger.java @@ -0,0 +1,45 @@ +package com.wayble.server.direction.controller.swagger; + +import com.wayble.server.common.response.CommonResponse; +import com.wayble.server.direction.dto.request.PlaceSaveRequest; +import com.wayble.server.direction.dto.response.DirectionSearchResponse; +import io.swagger.v3.oas.annotations.Operation; +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.responses.ApiResponses; +import io.swagger.v3.oas.annotations.tags.Tag; +import jakarta.validation.Valid; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestParam; + +import java.util.List; + +@Tag(name = "[길찾기 - 검색]", description = "길찾기 검색 등 API") +public interface DirectionSwagger { + @Operation( + summary = "길찾기에서 검색한 장소 저장 및 place -> directionDocument 변환 API", + description = "네이버 검색 API 호출 후, 검색한 장소를 저장 및 변환 + 색인 과정을 진행합니다." + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "장소 저장 및 변환이 성공적으로 실행되었습니다." + ) + }) + CommonResponse savePlace( + @RequestBody @Valid PlaceSaveRequest request + ); + + @Operation( + summary = "길찾기 검색 연관어 자동완성 API", + description = "길찾기 장소 검색 시, 연관어 자동완성을 진행합니다." + ) + @ApiResponses(value = { + @ApiResponse( + responseCode = "200", + description = "길찾기 검색 연관어 자동완성이 성공적으로 실행되었습니다." + ) + }) + CommonResponse> getDirectionKeywords( + @RequestParam String keyword + ); +} diff --git a/src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java b/src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java index 401c5db4..ba8f3889 100644 --- a/src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java +++ b/src/main/java/com/wayble/server/direction/controller/swagger/WalkingSwagger.java @@ -2,14 +2,14 @@ import com.wayble.server.common.response.CommonResponse; import com.wayble.server.direction.dto.response.WayblePathResponse; -import com.wayble.server.direction.external.tmap.dto.response.TMapParsingResponse; +import com.wayble.server.common.client.tmap.dto.response.TMapParsingResponse; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.responses.ApiResponse; import io.swagger.v3.oas.annotations.responses.ApiResponses; import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.web.bind.annotation.RequestParam; -@Tag(name = "[도보]", description = "도보 길찾기 관련 API") +@Tag(name = "[길찾기 - 도보]", description = "도보 길찾기 관련 API") public interface WalkingSwagger { @Operation( summary = "도보 최적 경로 길찾기 API", diff --git a/src/main/java/com/wayble/server/direction/dto/request/DirectionSearchRequest.java b/src/main/java/com/wayble/server/direction/dto/request/DirectionSearchRequest.java new file mode 100644 index 00000000..3e504f59 --- /dev/null +++ b/src/main/java/com/wayble/server/direction/dto/request/DirectionSearchRequest.java @@ -0,0 +1,11 @@ +package com.wayble.server.direction.dto.request; + +import lombok.Builder; + +@Builder +public record DirectionSearchRequest( + String name, + Double latitude, + Double longitude +) { +} diff --git a/src/main/java/com/wayble/server/direction/dto/request/PlaceSaveRequest.java b/src/main/java/com/wayble/server/direction/dto/request/PlaceSaveRequest.java new file mode 100644 index 00000000..35ae8922 --- /dev/null +++ b/src/main/java/com/wayble/server/direction/dto/request/PlaceSaveRequest.java @@ -0,0 +1,18 @@ +package com.wayble.server.direction.dto.request; + +import com.wayble.server.common.entity.Address; +import lombok.Builder; + +import java.util.List; + +@Builder +public record PlaceSaveRequest( + List requests +) { + + @Builder + public record PlaceDetailRequest( + String name, + Address address + ) {} +} diff --git a/src/main/java/com/wayble/server/direction/dto/response/DirectionSearchResponse.java b/src/main/java/com/wayble/server/direction/dto/response/DirectionSearchResponse.java new file mode 100644 index 00000000..07c11e20 --- /dev/null +++ b/src/main/java/com/wayble/server/direction/dto/response/DirectionSearchResponse.java @@ -0,0 +1,34 @@ +package com.wayble.server.direction.dto.response; + +import com.wayble.server.direction.entity.DirectionDocument; +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Builder; + +@Builder +@Schema(description = "지도 연관어 자동완성 API") +public record DirectionSearchResponse( + @Schema(description = "장소의 고유 ID", example = "1") + Long placeId, + + @Schema(description = "장소의 이름", example = "아임히어") + String name, + + @Schema(description = "주소", example = "서울시 용산구 청파동") + String address, + + @Schema(description = "위도", example = "37.84512") + Double latitude, + + @Schema(description = "경도", example = "127.87451") + Double longitude +) { + public static DirectionSearchResponse from(DirectionDocument directionDocument) { + return DirectionSearchResponse.builder() + .placeId(directionDocument.getId()) + .name(directionDocument.getName()) + .address(directionDocument.getEsAddress().getStreetAddress()) + .latitude(directionDocument.getEsAddress().getLocation().getLat()) + .longitude(directionDocument.getEsAddress().getLocation().getLon()) + .build(); + } +} diff --git a/src/main/java/com/wayble/server/direction/entity/DirectionDocument.java b/src/main/java/com/wayble/server/direction/entity/DirectionDocument.java new file mode 100644 index 00000000..aa6243b1 --- /dev/null +++ b/src/main/java/com/wayble/server/direction/entity/DirectionDocument.java @@ -0,0 +1,46 @@ +package com.wayble.server.direction.entity; + +import com.wayble.server.explore.entity.EsAddress; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.springframework.data.annotation.Id; +import org.springframework.data.elasticsearch.annotations.*; + +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Document(indexName = "direction", createIndex = true) +@Setting(settingPath = "/elasticsearch/settings/direction_settings.json") +@Mapping(mappingPath = "/elasticsearch/settings/direction_mappings.json") +public class DirectionDocument { + + @Id + @Field(type = FieldType.Long) + private Long id; + + @Field( + type = FieldType.Text, + analyzer = "korean_edge_ngram_analyzer", + searchAnalyzer = "korean_search_analyzer" + ) + private String name; + + @Field(type = FieldType.Object) + private EsAddress esAddress; + + @Builder + private DirectionDocument(Long id, String name, EsAddress esAddress) { + this.id = id; + this.name = name; + this.esAddress = esAddress; + } + + public static DirectionDocument from(Place place) { + return DirectionDocument.builder() + .id(place.getId()) + .name(place.getName()) + .esAddress(EsAddress.from(place.getAddress())) + .build(); + } +} diff --git a/src/main/java/com/wayble/server/direction/entity/Place.java b/src/main/java/com/wayble/server/direction/entity/Place.java new file mode 100644 index 00000000..43e2bbaf --- /dev/null +++ b/src/main/java/com/wayble/server/direction/entity/Place.java @@ -0,0 +1,38 @@ +package com.wayble.server.direction.entity; + +import com.wayble.server.common.entity.Address; +import com.wayble.server.common.entity.BaseEntity; +import jakarta.persistence.*; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Getter +@Entity +@NoArgsConstructor(access = AccessLevel.PROTECTED) +public class Place extends BaseEntity { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "name") + private String name; + + @Embedded + private Address address; + + @Builder + public Place(String name, Address address) { + this.name = name; + this.address = address; + } + + public static Place of(String name, Address address) { + return Place.builder() + .name(name) + .address(address) + .build(); + } +} diff --git a/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java b/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java index 18cd544c..bd5bdd2f 100644 --- a/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java +++ b/src/main/java/com/wayble/server/direction/exception/DirectionErrorCase.java @@ -8,8 +8,10 @@ @RequiredArgsConstructor public enum DirectionErrorCase implements ErrorCase { + PATH_NOT_FOUND(400, 4001, "해당하는 경로를 찾을 수 없습니다."), + ES_INDEXING_FAILED(500, 4002, "ElasticSearch 인덱싱에 실패했습니다."), HISTORY_NOT_FOUND(400, 4004, "검색 기록이 없습니다."), - PATH_NOT_FOUND(400, 4001, "해당하는 경로를 찾을 수 없습니다."); + ; private final Integer httpStatusCode; private final Integer errorCode; diff --git a/src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepository.java b/src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepository.java new file mode 100644 index 00000000..a3d109af --- /dev/null +++ b/src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepository.java @@ -0,0 +1,10 @@ +package com.wayble.server.direction.repository; + +import com.wayble.server.direction.dto.request.DirectionSearchRequest; +import com.wayble.server.direction.dto.response.DirectionSearchResponse; + +import java.util.List; + +public interface DirectionElasticSearchCustomRepository { + List searchDirection(DirectionSearchRequest request); +} diff --git a/src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepositoryImpl.java b/src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepositoryImpl.java new file mode 100644 index 00000000..02398daa --- /dev/null +++ b/src/main/java/com/wayble/server/direction/repository/DirectionElasticSearchCustomRepositoryImpl.java @@ -0,0 +1,37 @@ +package com.wayble.server.direction.repository; + +import com.wayble.server.direction.dto.request.DirectionSearchRequest; +import com.wayble.server.direction.dto.response.DirectionSearchResponse; +import com.wayble.server.direction.entity.DirectionDocument; +import lombok.RequiredArgsConstructor; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.SearchHit; +import org.springframework.data.elasticsearch.core.query.Criteria; +import org.springframework.data.elasticsearch.core.query.CriteriaQuery; +import org.springframework.stereotype.Repository; + +import java.util.List; + +@Repository +@RequiredArgsConstructor +public class DirectionElasticSearchCustomRepositoryImpl implements DirectionElasticSearchCustomRepository{ + + private final ElasticsearchOperations elasticsearchOperations; + + @Override + public List searchDirection(DirectionSearchRequest request) { + if (request.name() == null || request.name().trim().isEmpty()) return List.of(); + + Criteria criteria = new Criteria("name").matches(request.name()); + + CriteriaQuery query = new CriteriaQuery(criteria); + query.setMaxResults(5); + + return elasticsearchOperations + .search(query, DirectionDocument.class) + .map(SearchHit::getContent) + .map(DirectionSearchResponse::from) + .stream() + .toList(); + } +} diff --git a/src/main/java/com/wayble/server/direction/repository/DirectionElasticsearchRepository.java b/src/main/java/com/wayble/server/direction/repository/DirectionElasticsearchRepository.java new file mode 100644 index 00000000..d1c77b53 --- /dev/null +++ b/src/main/java/com/wayble/server/direction/repository/DirectionElasticsearchRepository.java @@ -0,0 +1,7 @@ +package com.wayble.server.direction.repository; + +import com.wayble.server.direction.entity.DirectionDocument; +import org.springframework.data.elasticsearch.repository.ElasticsearchRepository; + +public interface DirectionElasticsearchRepository extends ElasticsearchRepository, DirectionElasticSearchCustomRepository { +} diff --git a/src/main/java/com/wayble/server/direction/repository/PlaceRepository.java b/src/main/java/com/wayble/server/direction/repository/PlaceRepository.java new file mode 100644 index 00000000..0428938d --- /dev/null +++ b/src/main/java/com/wayble/server/direction/repository/PlaceRepository.java @@ -0,0 +1,7 @@ +package com.wayble.server.direction.repository; + +import com.wayble.server.direction.entity.Place; +import org.springframework.data.jpa.repository.JpaRepository; + +public interface PlaceRepository extends JpaRepository { +} diff --git a/src/main/java/com/wayble/server/direction/service/DirectionService.java b/src/main/java/com/wayble/server/direction/service/DirectionService.java index 05adf7e9..a74d9973 100644 --- a/src/main/java/com/wayble/server/direction/service/DirectionService.java +++ b/src/main/java/com/wayble/server/direction/service/DirectionService.java @@ -1,15 +1,68 @@ package com.wayble.server.direction.service; import com.wayble.server.common.exception.ApplicationException; +import com.wayble.server.direction.dto.request.DirectionSearchRequest; +import com.wayble.server.direction.dto.request.PlaceSaveRequest; +import com.wayble.server.direction.dto.response.DirectionSearchResponse; +import com.wayble.server.direction.entity.DirectionDocument; +import com.wayble.server.direction.entity.Place; import com.wayble.server.direction.exception.DirectionErrorCase; +import com.wayble.server.direction.repository.DirectionElasticsearchRepository; +import com.wayble.server.direction.repository.PlaceRepository; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.data.elasticsearch.core.ElasticsearchOperations; +import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates; +import org.springframework.data.elasticsearch.core.query.IndexQuery; +import org.springframework.data.elasticsearch.core.query.IndexQueryBuilder; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; +import java.util.List; + +@Slf4j @Service @RequiredArgsConstructor public class DirectionService { - public void makeException() { - throw new ApplicationException(DirectionErrorCase.PATH_NOT_FOUND); + private final PlaceRepository placeRepository; + private final DirectionElasticsearchRepository directionElasticsearchRepository; + private final ElasticsearchOperations elasticsearchOperations; + + @Transactional + public void savePlaceAndIndexDocument(List requests) { + List places = requests.stream() + .map(request -> + Place.of(request.name(), request.address()) + ) + .toList(); + + placeRepository.saveAll(places); + + try { + List queries = places.stream() + .map(place -> + new IndexQueryBuilder() + .withId(place.getId().toString()) + .withObject(DirectionDocument.from(place)) + .build() + ) + .toList(); + + elasticsearchOperations.bulkIndex(queries, IndexCoordinates.of("direction")); + } catch (Exception e) { + log.error("🚨 ES 인덱싱 실패: {}", e.getMessage()); + throw new ApplicationException(DirectionErrorCase.ES_INDEXING_FAILED); + } + } + + public List searchDirection(String keyword) { + DirectionSearchRequest request = DirectionSearchRequest.builder() + .name(keyword) + .build(); + + return directionElasticsearchRepository.searchDirection(request); } } diff --git a/src/main/java/com/wayble/server/direction/service/WalkingService.java b/src/main/java/com/wayble/server/direction/service/WalkingService.java index 5124ad41..460c714b 100644 --- a/src/main/java/com/wayble/server/direction/service/WalkingService.java +++ b/src/main/java/com/wayble/server/direction/service/WalkingService.java @@ -4,11 +4,11 @@ import com.wayble.server.direction.dto.response.WayblePathResponse; import com.wayble.server.direction.entity.Node; import com.wayble.server.direction.exception.WalkingErrorCase; -import com.wayble.server.direction.external.tmap.TMapClient; -import com.wayble.server.direction.external.tmap.dto.request.TMapRequest; -import com.wayble.server.direction.external.tmap.dto.response.TMapParsingResponse; -import com.wayble.server.direction.external.tmap.dto.response.TMapResponse; -import com.wayble.server.direction.external.tmap.mapper.TMapMapper; +import com.wayble.server.common.client.tmap.TMapClient; +import com.wayble.server.common.client.tmap.dto.request.TMapRequest; +import com.wayble.server.common.client.tmap.dto.response.TMapParsingResponse; +import com.wayble.server.common.client.tmap.dto.response.TMapResponse; +import com.wayble.server.common.client.tmap.mapper.TMapMapper; import com.wayble.server.direction.init.GraphInit; import com.wayble.server.direction.service.util.HaversineUtil; import lombok.RequiredArgsConstructor; diff --git a/src/main/resources/elasticsearch/settings/direction_mappings.json b/src/main/resources/elasticsearch/settings/direction_mappings.json new file mode 100644 index 00000000..6db0ecdd --- /dev/null +++ b/src/main/resources/elasticsearch/settings/direction_mappings.json @@ -0,0 +1,23 @@ +{ + "properties": { + "id": { + "type": "long" + }, + "name": { + "type": "text", + "analyzer": "korean_edge_ngram_analyzer", + "search_analyzer": "korean_search_analyzer" + }, + "esAddress": { + "properties": { + "streetAddress": { + "type": "text", + "analyzer": "korean_search_analyzer" + }, + "location": { + "type": "geo_point" + } + } + } + } +} \ No newline at end of file diff --git a/src/main/resources/elasticsearch/settings/direction_settings.json b/src/main/resources/elasticsearch/settings/direction_settings.json new file mode 100644 index 00000000..276cc212 --- /dev/null +++ b/src/main/resources/elasticsearch/settings/direction_settings.json @@ -0,0 +1,36 @@ +{ + "analysis": { + "tokenizer": { + "nori_tokenizer": { + "type": "nori_tokenizer", + "decompound_mode": "mixed" + } + }, + "filter": { + "edge_ngram_filter": { + "type": "edge_ngram", + "min_gram": 2, + "max_gram": 20 + } + }, + "analyzer": { + "korean_edge_ngram_analyzer": { + "type": "custom", + "tokenizer": "nori_tokenizer", + "filter": [ + "lowercase", + "trim", + "edge_ngram_filter" + ] + }, + "korean_search_analyzer": { + "type": "custom", + "tokenizer": "nori_tokenizer", + "filter": [ + "lowercase", + "trim" + ] + } + } + } +}