Scala项目导入不同版本Elasticsearch库失败及Shading方案异常
解决Scala中同时依赖Elasticsearch 6.x(Elastic4s)和7.x客户端的依赖冲突问题
我帮你梳理下这个问题:你要连接两个不同版本的ES集群,同时引入了Elastic4s 6.2.8(依赖ES 6.x客户端)和ES官方7.2.0的客户端,结果因为两者共用相同的包名导致依赖冲突。你尝试用sbt-assembly的shading来隔离,但配置有几个关键错误,导致shading没生效,导入类时报错。
问题根源
你的shading配置犯了两个核心错误:
- 规则被覆盖:每次使用
assemblyShadeRules in assembly := Seq(...)都是重新赋值,会覆盖之前的所有规则,最后只有最后一条规则生效,前面的7.x和6.x客户端的shading完全没被应用。 - 包匹配错误&遗漏依赖:你写的
org.elasticsearch.elasticsearch.**是错误的ES核心包路径,正确的根路径是org.elasticsearch.**;另外你只单独shaded了6.x的客户端,没处理Elastic4s本身依赖的ES 6.x相关包。
正确的解决方案
下面是修正后的build.sbt配置,以及代码中如何使用shaded后的客户端:
1. 完整的build.sbt配置
val elastic4sVersion = "6.2.8" val es7Version = "7.2.0" // 声明所有依赖 libraryDependencies ++= Seq( // Elasticsearch 7.x 官方核心库与高级客户端 "org.elasticsearch" % "elasticsearch" % es7Version, "org.elasticsearch.client" % "elasticsearch-rest-high-level-client" % es7Version, // Elastic4s 6.x 客户端库 "com.sksamuel.elastic4s" %% "elastic4s-core" % elastic4sVersion, "com.sksamuel.elastic4s" %% "elastic4s-http" % elastic4sVersion ) // 配置Shading规则:用++=追加规则,避免覆盖 assemblyShadeRules in assembly ++= Seq( // 将ES 7.x的所有相关包重命名到shaded.es7路径下 ShadeRule.rename("org.elasticsearch.**" -> "shaded.es7.@1") .inLibrary("org.elasticsearch" % "elasticsearch" % es7Version) .inLibrary("org.elasticsearch.client" % "elasticsearch-rest-high-level-client" % es7Version) .inAll, // 应用到所有依赖和项目代码中 // 将Elastic4s依赖的ES 6.x相关包重命名到shaded.es6路径下 // 先通过`sbt dependencyTree`确认Elastic4s依赖的ES版本,这里是6.2.2 ShadeRule.rename("org.elasticsearch.**" -> "shaded.es6.@1") .inLibrary("org.elasticsearch" % "elasticsearch" % "6.2.2") .inLibrary("org.elasticsearch.client" % "elasticsearch-rest-client" % "6.2.2") .inLibrary("com.sksamuel.elastic4s" %% "elastic4s-core" % elastic4sVersion) .inLibrary("com.sksamuel.elastic4s" %% "elastic4s-http" % elastic4sVersion) .inAll )
2. 代码中使用Shaded后的客户端
- 连接ES 7.x集群:导入shaded后的7.x客户端类
import shaded.es7.org.elasticsearch.client.RestHighLevelClient import shaded.es7.org.elasticsearch.client.RestClient // 构建ES 7.x客户端 val es7Client = new RestHighLevelClient( RestClient.builder(new HttpHost("es7-host", 9200, "http")) ) // 执行查询 val searchResponse = es7Client.search(...)
- 连接ES 6.x集群(使用Elastic4s):导入shaded后的Elastic4s类
import shaded.es6.com.sksamuel.elastic4s.http.HttpClient import shaded.es6.com.sksamuel.elastic4s.ElasticDsl._ // 构建Elastic4s客户端 val es6Client = HttpClient("http://es6-host:9200") // 执行Elastic4s查询 val result = es6Client.execute { search("my-index-6").query(matchAllQuery) }.await println(result.hits.hits.map(_.source))
3. 注意事项
- 必须使用
sbt assembly打包后运行,shading规则只在assembly阶段生效,直接用sbt run不会应用shading,仍然会报错。 - 用
sbt dependencyTree命令确认Elastic4s依赖的ES具体版本,确保shading规则中的版本号和实际依赖一致。 - 如果还有其他依赖ES客户端的第三方库,也要把它们加入对应的shading规则中。
内容的提问来源于stack exchange,提问作者Ashutosh C
相关产品推荐
相关产品推荐

