1. FunctionContributor 정의
나는 MatchFunctionContributor라고 선언했다.
class MatchFunctionContributor : FunctionContributor {
companion object {
private const val FUNCTION_NAME = "MATCH_AGAINST"
private const val FUNCTION_PATTERN = "MATCH (?1) AGAINST (?2 IN BOOLEAN MODE)"
}
override fun contributeFunctions(functionContributions: FunctionContributions) {
functionContributions.functionRegistry
.registerPattern(
FUNCTION_NAME,
FUNCTION_PATTERN,
functionContributions.typeConfiguration.basicTypeRegistry.resolve(DOUBLE)
)
}
}
2. MatchFunctionContributor 등록
resources/META-INF/services/org.hibernate.boot.model.FunctionContributor 파일을 생성한 후,
MatchFunctionContributor 전체 경로를 입력해 준다.
com.kw.data.common.contributor.MatchFunctionContributor
3. 유틸 메서드 생성
CustomFunction 이라는 유틸 클래스를 선언하고 match라는 메서드명으로 작성했다.
들어오는 키워드는 공백 문자 포함 시, 각 단어에 '+' boolean full-text 연산자를 붙여 모든 단어가 포함된 문자열을 검색할 수 있도록 했다.
class CustomFunction {
companion object {
fun match(target: StringPath, keyword: String): BooleanExpression? {
if (keyword.isEmpty()) {
return null
}
return Expressions.numberTemplate(
java.lang.Double::class.java,
"FUNCTION('MATCH_AGAINST', {0}, {1})",
target,
keyword.trim().split(" ").joinToString(" ") { "+$it" }
).gt(0)
}
}
}
4. 사용하기
쿼리에 아래와 같이 체이닝을 걸어 사용해 주면 된다.
.where(condition.keyword?.let { CustomFunction.match(bundle.name, it) })
추가로, 한 글자 검색이 가능하려면 DB 파라미터 설정에서
📌 ngram_token_size=1
📌 ft_min_word_len=1
📌 innodb_ft_min_token_size=1
로 설정해 주면 된다.
근데 영문 'a'와 같이 불용어인 키워드는 검색이 잘 되지 않을 수도 있다.
그럴 경우엔
📌 innodb_ft_enable_stopword=0
으로 추가로 설정해 주면 된다.
MySQL 8.0 이상 기준으로 불용어는 아래 쿼리로 확인해 보면 사진과 같은 값들이 지정되어 있다.
SELECT *
FROM information_schema.innodb_ft_default_stopword;
참고
사용자 정의 함수(match against) dialect 사용하기
'Backend' 카테고리의 다른 글
[NestJS] Interceptor를 활용한 TypeORM Transaction 코드 개선하기 (1) | 2023.02.13 |
---|