Spring-Data-ElasticSearch 5.2.0 부터는 updateByScript 쿼리에 scriptType (INLINE / STORED) 가 필수가 됐다.
기존에 설정한게 없다면, 기본값 INLINE
가 들어가고 있었다.
그러니까, INLINE 으로 scriptType 을 설정해주면 된디.
UpdateQuery.builder(it.docId.toString()).withScript(
"{Script}"
).withParams(
mapOf("data" to it.data)
).withLang(
ElasticsearchConstant.UPDATE_SCRIPT_LANG_PAINLESS
).withRetryOnConflict(
elasticsearchConnectionProperties.retryOnConflictCnt
).build()
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 는 Elasticsearch 에서 Update 를 할 때, script 로 Update 를 할 때 사용되는 클래스이다.
이 클래스가 변경되면서, 에러가 발생했다고 봐도 무방하다.
생성자에 Nullable 이었던게 Not Null 이 됐기 때문.
그러면 이번에는, Script Type 은 어떻게 가져와서 사용되고 있는지,
그리고 기존에는 어떻게 기본값을 넣어주고 있는지 확인해보자.
4.4.18 버전에서는 UpdateQuery 클래스에서 scriptType 을 가져오는 메소드, getScriptType
을 보면 참조되는데가 저렇게 많다.
RequestFactory 를 보면, getScriptType
(query.getScriptType
()); 메소드로 스크립트 타입을 가져오는데
getScriptType
에서는 이렇게 getScriptType
으로 가져온게 null 일 경우, INLINE 으로 처리를 해주고 있다.
반면에 5.2.0 에서는 scriptType 을 default 로 넣어주는 부분이 사라진걸 볼 수 있다.
(당연히 이제 RequestFactory 클래스도 사라졌다..)
위에 TL; DR; 에 언급했던것 처럼, Spring Boot 3 부터는 script 를 짤 때 별도로 scriptType 을 명시해줘야 한다.