feat: 실시간 경매장 정보 fetcher and sheduler 및 거대한 외침의 뿔피리 엘라스틱 서치 구현#91
feat: 실시간 경매장 정보 fetcher and sheduler 및 거대한 외침의 뿔피리 엘라스틱 서치 구현#91
Conversation
✅ 테스트 결과 for PRBuild: success 🧪 테스트 실행 with Gradle |
There was a problem hiding this comment.
Pull request overview
This PR implements real-time auction data fetching/scheduling and Elasticsearch integration for Horn Bugle search functionality in the Mabinogi Open API batch server.
Changes:
- Adds real-time auction data collection with 10-minute interval scheduling and duplicate detection logic
- Implements Elasticsearch integration with Korean full-text search (Ngram parser) for Horn Bugle history
- Refactors auction table structure, separating history (
auction_history_item_option) from realtime (auction_realtime_item,auction_realtime_item_option)
Reviewed changes
Copilot reviewed 157 out of 158 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| V15__refactor_auction_tables_for_realtime_history_separation.sql | Database migration to separate auction history and realtime tables |
| V16__update_unknown_item_name_and_segong_option_level.sql | Updates unknown item names and parses segong option levels |
| V17__add_fulltext_index_to_horn_bugle_world_history.sql | Adds MySQL FULLTEXT index for Horn Bugle search |
| HornBugleIndexService.java | Elasticsearch indexing service for Horn Bugle data |
| AuctionRealtimeScheduler.java | Scheduler for real-time auction data collection (10-minute intervals) |
| AuctionRealtimeFetcher.java | Fetcher with cursor-based pagination and duplicate detection |
| HornBugleService.java | Updated to support both Elasticsearch and MySQL FULLTEXT search |
| docker-compose-*.yml | Docker configurations updated with Elasticsearch services |
| build.gradle.kts | Added Elasticsearch dependency |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| -Xmx${JAVA_OPTS_XMX:-512m} | ||
| -XX:MaxMetaspaceSize=${JAVA_OPTS_MAX_METASPACE_SIZE:-150m} | ||
| -XX:ReservedCodeCacheSize=${JAVA_OPTS_RESERVED_CODE_CACHE_SIZE:-48m} | ||
| -XX:ReservedCodeCacheSize=${JAVA_OPTS_RESERVED_CODE_CACHE_SIZE:-48m} |
There was a problem hiding this comment.
Duplicate line: -XX:ReservedCodeCacheSize=${JAVA_OPTS_RESERVED_CODE_CACHE_SIZE:-48m} appears on both line 59 and line 60. Remove the duplicate.
| -XX:ReservedCodeCacheSize=${JAVA_OPTS_RESERVED_CODE_CACHE_SIZE:-48m} |
| @AfterMapping | ||
| default void afterMapping( | ||
| OpenApiAuctionRealtimeResponse dto, @MappingTarget AuctionRealtimeItem entity) { | ||
| // item_name이 "(Unknown)"인 경우 item_display_name으로 대체 | ||
| if (UNKNOWN_ITEM_NAME.equals(entity.getItemName())) { | ||
| entity.setItemName(dto.itemDisplayName()); | ||
| } | ||
| } |
There was a problem hiding this comment.
The mapper is using @AfterMapping to replace "(Unknown)" item names with display names. However, this logic exists in both OpenApiAuctionHistoryMapper and OpenApiAuctionRealtimeMapper with identical implementation. Consider extracting this to a shared helper method or abstract mapper to follow DRY principles.
|
|
||
| @AfterMapping | ||
| default void afterMapping( | ||
| OpenApiAuctionItemOptionResponse dto, @MappingTarget AuctionRealtimeItemOption entity) { | ||
| // option_type이 "세공 옵션"인 경우에만 파싱 수행 | ||
| if (!SEGONG_OPTION_TYPE.equals(entity.getOptionType()) || entity.getOptionValue() == null) { | ||
| return; | ||
| } | ||
|
|
||
| String originalValue = entity.getOptionValue(); | ||
|
|
||
| // 패턴 1: "스킬명 숫자 레벨" 또는 "스킬명 숫자레벨" 형식 | ||
| Matcher matcher1 = PATTERN_LEVEL_SUFFIX.matcher(originalValue); | ||
| if (matcher1.matches()) { | ||
| entity.setOptionValue(matcher1.group(1)); | ||
| entity.setOptionValue2(matcher1.group(3)); | ||
| entity.setOptionDesc(matcher1.group(2)); | ||
| return; | ||
| } | ||
|
|
||
| // 패턴 2: "스킬명(숫자레벨:효과)" 형식 | ||
| Matcher matcher2 = PATTERN_LEVEL_PARENTHESIS.matcher(originalValue); | ||
| if (matcher2.matches()) { | ||
| entity.setOptionValue(matcher2.group(1)); | ||
| entity.setOptionValue2(matcher2.group(3)); | ||
| entity.setOptionDesc(matcher2.group(2)); | ||
| } | ||
| // 두 패턴 모두 매칭되지 않으면 원본 값 유지 |
There was a problem hiding this comment.
The segong option parsing logic using regex patterns is duplicated across OpenApiItemOptionMapper and OpenApiRealtimeItemOptionMapper. Both mappers have identical Pattern constants (PATTERN_LEVEL_SUFFIX, PATTERN_LEVEL_PARENTHESIS) and afterMapping logic. Consider extracting this common parsing logic to a shared utility class to improve maintainability and avoid duplication.
|
|
||
| @OneToMany(mappedBy = "auctionHistory", cascade = CascadeType.ALL, orphanRemoval = true) | ||
| private List<AuctionItemOption> auctionItemOptions; | ||
| private List<AuctionHistoryItemOption> auctionHistoryItemOptions; |
There was a problem hiding this comment.
getAuctionHistoryItemOptions exposes the internal representation stored in field auctionHistoryItemOptions. The value may be modified after this call to getAuctionHistoryItemOptions.
getAuctionHistoryItemOptions exposes the internal representation stored in field auctionHistoryItemOptions. The value may be modified after this call to getAuctionHistoryItemOptions.
| private String itemTopCategory; | ||
|
|
||
| @OneToMany(mappedBy = "auctionRealtimeItem", cascade = CascadeType.ALL, orphanRemoval = true) | ||
| private List<AuctionRealtimeItemOption> auctionRealtimeItemOptions; |
There was a problem hiding this comment.
getAuctionRealtimeItemOptions exposes the internal representation stored in field auctionRealtimeItemOptions. The value may be modified after this call to getAuctionRealtimeItemOptions.
getAuctionRealtimeItemOptions exposes the internal representation stored in field auctionRealtimeItemOptions. The value may be modified after this call to getAuctionRealtimeItemOptions.
| @Getter | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @Builder |
There was a problem hiding this comment.
Default toString(): AuctionRealtimeItem inherits toString() from Object, and so is not suitable for printing.
Codecov Report❌ Patch coverage is 📢 Thoughts on this report? Let us know! |
📋 상세 설명
📊 체크리스트
pass이슈만 등록📆 마감일