Spring-data-elasticsearch 버전업 (4.4.18-> 5.2.0 ) 이슈

조갱·2025년 9월 7일
0

ElasticSearch

목록 보기
8/8

TL; DR;

Spring-Data-ElasticSearch 5.2.0 부터는 updateByScript 쿼리에 scriptType (INLINE / STORED) 가 필수가 됐다.

기존에 설정한게 없다면, 기본값 INLINE 가 들어가고 있었다.

그러니까, INLINE 으로 scriptType 을 설정해주면 된디.

AS-IS

UpdateQuery.builder(it.docId.toString()).withScript(
    "{Script}"
).withParams(
    mapOf("data" to it.data)
).withLang(
    ElasticsearchConstant.UPDATE_SCRIPT_LANG_PAINLESS
).withRetryOnConflict(
    elasticsearchConnectionProperties.retryOnConflictCnt
).build()

TO-BE

UpdateQuery.builder(it.docId.toString()).withScript(
    "{Script}"
).withParams(
    mapOf("data" to it.data)
).withLang(
    ElasticsearchConstant.UPDATE_SCRIPT_LANG_PAINLESS
).withRetryOnConflict(
    elasticsearchConnectionProperties.retryOnConflictCnt
).withScriptType( // 이 부분이 추가됐어요!
    ScriptType.INLINE
).build()

에러 로그

2025-08-29 10:15:06.930 [POOL(4)_DISPATCHER-3] [ERROR] 패키지명 : error : type must not be null
{엄청 긴 카프카 토픽}
java.lang.IllegalArgumentException: type must not be null
	at org.springframework.util.Assert.notNull(Assert.java:172)
	at org.springframework.data.elasticsearch.core.query.ScriptData.<init>(ScriptData.java:36)
	at org.springframework.data.elasticsearch.core.query.UpdateQuery.<init>(UpdateQuery.java:109)
	at org.springframework.data.elasticsearch.core.query.UpdateQuery$Builder.build(UpdateQuery.java:456)
	at 파일
	at 파일
	at 파일
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.RunnableWrapper.lambda$stopPropagation$0(RunnableWrapper.java:16)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:280)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at 파일
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.base/java.lang.reflect.Method.invoke(Unknown Source)
	at org.springframework.context.event.ApplicationListenerMethodAdapter.doInvoke(ApplicationListenerMethodAdapter.java:365)
	at org.springframework.context.event.ApplicationListenerMethodAdapter.processEvent(ApplicationListenerMethodAdapter.java:237)
	at org.springframework.transaction.event.TransactionalApplicationListenerSynchronization.processEventWithCallbacks(TransactionalApplicationListenerSynchronization.java:65)
	at org.springframework.transaction.event.TransactionalApplicationListenerSynchronization$PlatformSynchronization.beforeCommit(TransactionalApplicationListenerSynchronization.java:110)
	at org.springframework.transaction.support.TransactionSynchronizationUtils.triggerBeforeCommit(TransactionSynchronizationUtils.java:97)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.triggerBeforeCommit(AbstractPlatformTransactionManager.java:985)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:774)
	at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:757)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:669)
	at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:419)
	at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:119)
	at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:184)
	at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.proceed(CglibAopProxy.java:765)
	at org.springframework.aop.framework.CglibAopProxy$DynamicAdvisedInterceptor.intercept(CglibAopProxy.java:717)
	at 파일
	at 파일
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at io.opentelemetry.javaagent.instrumentation.kotlinxcoroutines.RunnableWrapper.lambda$stopPropagation$0(RunnableWrapper.java:16)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
	at java.base/java.lang.Thread.run(Unknown Source)

코드 비교하기

ScriptData.java

ScriptData 는 Elasticsearch 에서 Update 를 할 때, script 로 Update 를 할 때 사용되는 클래스이다.

이 클래스가 변경되면서, 에러가 발생했다고 봐도 무방하다.

생성자에 Nullable 이었던게 Not Null 이 됐기 때문.

4.4.18

5.2.0

UpdateQuery.java

그러면 이번에는, Script Type 은 어떻게 가져와서 사용되고 있는지,

그리고 기존에는 어떻게 기본값을 넣어주고 있는지 확인해보자.

4.4.18

4.4.18 버전에서는 UpdateQuery 클래스에서 scriptType 을 가져오는 메소드, getScriptType 을 보면 참조되는데가 저렇게 많다.

RequestFactory 를 보면, getScriptType(query.getScriptType()); 메소드로 스크립트 타입을 가져오는데

getScriptType 에서는 이렇게 getScriptType 으로 가져온게 null 일 경우, INLINE 으로 처리를 해주고 있다.

5.2.0

반면에 5.2.0 에서는 scriptType 을 default 로 넣어주는 부분이 사라진걸 볼 수 있다.

(당연히 이제 RequestFactory 클래스도 사라졌다..)

결론

위에 TL; DR; 에 언급했던것 처럼, Spring Boot 3 부터는 script 를 짤 때 별도로 scriptType 을 명시해줘야 한다.

profile
A fast learner.

0개의 댓글