본문 바로가기

Backend

[QueryDSL] MATCH.. AGAINST.. dialect 사용하기 (Full-Text 검색 함수, 커스텀 함수 정의) with Kotlin

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;

 

MySQL8 불용어(Stopword) 목록

 


참고

사용자 정의 함수(match against) dialect 사용하기

Migration of dialect to Hibernate 6

14.9 Full-Text Search Functions