Skip to content

Commit

Permalink
실행 시간 측정을 위한 StopWatch 기능 추가 및 TRIE 라이브러리 리팩토링 (#327 )
Browse files Browse the repository at this point in the history
  • Loading branch information
juno-junho authored May 14, 2024
2 parents fa2379d + 917ce04 commit 6444b1f
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@
import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import static com.spaceclub.global.annotation.profanity.BadWordExceptionMessage.BAD_WORD_DETECTED;

@Slf4j
@Component
@RequiredArgsConstructor
public class ProfanityCheckValidator implements ConstraintValidator<ProfanityCheck, String> {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.spaceclub.global.annotation.profanity;

import com.googlecode.concurrenttrees.radix.node.concrete.DefaultCharSequenceNodeFactory;
import com.googlecode.concurrenttrees.radix.node.concrete.SmartArrayBasedNodeFactory;
import com.googlecode.concurrenttrees.radix.node.concrete.voidvalue.VoidValue;
import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
import com.spaceclub.global.config.ProfanityConfig;
Expand All @@ -24,23 +25,24 @@
public class ProfanityLoader {

private final ProfanityConfig config;
private final InvertedRadixTree<String> TRIE = new ConcurrentInvertedRadixTree<>(new DefaultCharSequenceNodeFactory());
private final InvertedRadixTree<VoidValue> TRIE = new ConcurrentInvertedRadixTree<>(new SmartArrayBasedNodeFactory());

@PostConstruct
private void loadProfanityFromFile() {
try {
List<String> badWords = Files.readAllLines(Paths.get(config.filePath()));
badWords.forEach(badWord -> TRIE.put(badWord, badWord));
List<String> banWords = Files.readAllLines(Paths.get(config.filePath()));
banWords.forEach(banWord -> TRIE.put(banWord, VoidValue.SINGLETON)); // 메모리 효율을 위해 불필요한 value 설정 x
} catch (IOException e) {
log.error("비속어 목록 파일 읽기 실패", e);
throw new IllegalStateException(FAIL_BAD_WORD_SETUP.toString());
}
}

public List<String> profanityContained(String text) {
Spliterator<String> profanityFound = TRIE.getValuesForKeysContainedIn(text).spliterator();
Spliterator<CharSequence> profanityFound = TRIE.getKeysContainedIn(text).spliterator();

return StreamSupport.stream(profanityFound, false)
.map(CharSequence::toString)
.peek(word -> log.info("비속어 감지: {}", word))
.toList();
}
Expand Down
14 changes: 14 additions & 0 deletions src/main/java/com/spaceclub/global/timer/StopWatch.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.spaceclub.global.timer;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Documented
@Target({ElementType.METHOD, ElementType.CONSTRUCTOR})
@Retention(RetentionPolicy.RUNTIME)
public @interface StopWatch {

}
34 changes: 34 additions & 0 deletions src/main/java/com/spaceclub/global/timer/StopWatchExecutor.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.spaceclub.global.timer;

import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.context.annotation.Profile;
import org.springframework.stereotype.Component;
import org.springframework.util.StopWatch;

@Slf4j
@Aspect
@Component
@Profile("local")
public class StopWatchExecutor {

@Pointcut("@annotation(com.spaceclub.global.timer.StopWatch)")
private void stopWatch() {
}

@Around("stopWatch()")
public Object logExecutionTime(ProceedingJoinPoint joinPoint) throws Throwable {
StopWatch stopWatch = new StopWatch();
try {
stopWatch.start(joinPoint.toShortString() + "Timer started");
return joinPoint.proceed();
} finally {
stopWatch.stop();
log.info(stopWatch.prettyPrint());
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.spaceclub.global.profanity.study;

import com.googlecode.concurrenttrees.common.Iterables;
import com.googlecode.concurrenttrees.common.PrettyPrinter;
import com.googlecode.concurrenttrees.radix.node.concrete.SmartArrayBasedNodeFactory;
import com.googlecode.concurrenttrees.radix.node.concrete.voidvalue.VoidValue;
import com.googlecode.concurrenttrees.radix.node.util.PrettyPrintable;
import com.googlecode.concurrenttrees.radixinverted.ConcurrentInvertedRadixTree;
import com.googlecode.concurrenttrees.radixinverted.InvertedRadixTree;
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;

import java.util.List;
import java.util.Spliterator;
import java.util.stream.StreamSupport;

public class ConcurrentInvertedRadixTreeTest {

private final InvertedRadixTree<VoidValue> TRIE = new ConcurrentInvertedRadixTree<>(new SmartArrayBasedNodeFactory());

@Test
@Disabled
void concurrent_Inverted_Radix_tree_사용법_학습테스트() {
TRIE.put("TEST", VoidValue.SINGLETON); // value는 필요 없으면 VoidValue를 사용하면 메모리를 효율적으로 사용 가능 (Radix Tree류 경우)
TRIE.put("TOAST", VoidValue.SINGLETON);
TRIE.put("TEAM", VoidValue.SINGLETON);

System.out.println("Tree structure:");
PrettyPrinter.prettyPrint((PrettyPrintable) TRIE, System.out); // PrettyPrintable는 테스트를 위한 객체

System.out.println();
System.out.println("Value for 'TEST' (exact match): " + TRIE.getValueForExactKey("TEST"));
System.out.println("Value for 'TOAST' (exact match): " + TRIE.getValueForExactKey("TOAST"));
System.out.println();
System.out.println("Keys contained in 'MY TEAM LIKES TOAST': " + Iterables.toString(TRIE.getKeysContainedIn("MY TEAM LIKES TOAST")));
System.out.println("Keys contained in 'MY TEAM LIKES TOASTERS': " + Iterables.toString(TRIE.getKeysContainedIn("MY TEAM LIKES TOASTERS")));
System.out.println("Values for keys contained in 'MY TEAM LIKES TOAST': " + Iterables.toString(TRIE.getValuesForKeysContainedIn("MY TEAM LIKES TOAST")));
System.out.println("Key-value pairs for keys contained in 'MY TEAM LIKES TOAST': " + Iterables.toString(TRIE.getKeyValuePairsForKeysContainedIn("MY TEAM LIKES TOAST")));

// 예시
String text = "MY TEAM LIKES TOASTERS";
Spliterator<CharSequence> profanityFound = TRIE.getKeysContainedIn(text).spliterator();
List<String> profanityList = StreamSupport.stream(profanityFound, false)
.map(CharSequence::toString)
.toList();

System.out.println("비속어 감지: " + profanityList);
}

}

0 comments on commit 6444b1f

Please sign in to comment.