Spring Data Elastic 在 3.1.4 上失败 - uri 的 HTTP 方法不正确

问题描述 投票:0回答:1

我一直在将 Spring Boot Elastic 应用程序从 2.x 升级到 3.x - 我正在努力解决以下错误,我已经能够在新的 Spring Boot ES 应用程序中重现该错误(来自 Spring Boot Initializer) )。正如您将看到的,代码是基本的。

在持久化文档时会出现此问题,并且在 Spring Boot 3.x(在 Spring Boot 3.1.4 上执行的测试)代码库中失败,但在 Spring Boot 2.7(针对 ES 7.11)上测试的相同代码却成功。

有什么想法吗? gitrepo 位于 https://github.com/kellizer/spring-boot-es-failure-3.1.4


错误

原因: co.elastic.clients.elasticsearch._types.ElasticsearchException: [es/index] 失败:[null] uri 的 HTTP 方法不正确 [/vaultdoc/_doc/?refresh=false] 和方法 [PUT],允许:[POST]

堆栈跟踪:

Caused by: co.elastic.clients.elasticsearch._types.ElasticsearchException: [es/index] failed: [null] Incorrect HTTP method for uri [/vaultdoc/_doc/?refresh=false] and method [PUT], allowed: [POST]
    at co.elastic.clients.transport.rest_client.RestClientTransport.getHighLevelResponse(RestClientTransport.java:334)
    at co.elastic.clients.transport.rest_client.RestClientTransport.performRequest(RestClientTransport.java:154)
    at co.elastic.clients.elasticsearch.ElasticsearchClient.index(ElasticsearchClient.java:1116)
    at org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate.lambda$doIndex$6(ElasticsearchTemplate.java:220)
    at org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate.execute(ElasticsearchTemplate.java:623)

测试(Kotlin)

@Testcontainers
@SpringBootTest(classes = [TestApp::class], properties = ["logging.level.org.testcontainers=debug"])
@ContextConfiguration(initializers = [SetupContainers::class])
class VaultDocumentTest(@Autowired private val vaultDocumentRepo: VaultDocumentRepo) {
    @Test
    fun simpleTest() {
        println("Count Call Works-->${vaultDocumentRepo.count()}")//this works - returns 0
        println("findAll Works -->${vaultDocumentRepo.findAll().toList().size}") //this works - returns 0
        vaultDocumentRepo.save(VaultDocument("Test101")) //save fails with error '[es/index] failed: [null] Incorrect HTTP method for uri [/vaultdoc/_doc/?refresh=false] and method [PUT], allowed: [POST]'
    }
}

文档

@Document(indexName = "vaultdoc")
class VaultDocument(
    @Field(type = FieldType.Text, store = true, fielddata = true)
    val vaultDocumentName: String,
    @org.springframework.data.annotation.Id
    var id: String = "",
)

存储库

@Repository
interface VaultDocumentRepo : ElasticsearchRepository<VaultDocument, String> {
    fun findByVaultDocumentName(vaultDocumentName: String): VaultDocument?
}

最后,测试容器是如何设置的。

class SetupContainers : ApplicationContextInitializer<ConfigurableApplicationContext> {
override fun initialize(applicationContext: ConfigurableApplicationContext) {

    elasticsearchContainer.withEnv(
        mapOf(
            "xpack.security.enabled" to "false",
            "xpack.security.http.ssl.enabled" to "false",
            "action.destructive_requires_name" to "false",
            "reindex.remote.whitelist" to "localhost:9200"
        )
    )
    elasticsearchContainer.start()
    TestPropertyValues.of(
        "spring.elasticsearch.uris=http://${elasticsearchContainer.httpHostAddress}",
    ).applyTo(applicationContext.environment)
}


companion object {
    @Container
    val elasticsearchContainer: ElasticsearchContainer = ElasticsearchContainer(
        DockerImageName
            .parse("docker.elastic.co/elasticsearch/elasticsearch")
            .withTag("8.10.0")

    )
}

}

spring spring-boot elasticsearch spring-data-elasticsearch
1个回答
0
投票

下载错误来自过于严格的配置漏洞,阻止了“downloads.gradle.org”。

至于

PUT
POST
:我查看了
IndexRequest
的Elasticsearch客户端代码。当索引 id 不是
PUT
的文档时,它将发送
null
,否则发送
POST

            // Request method
            request -> {
                final int _index = 1 << 0;
                final int _id = 1 << 1;

                int propsSet = 0;

                propsSet |= _index;
                if (request.id() != null)
                    propsSet |= _id;

                if (propsSet == (_index | _id))
                    return "PUT";
                if (propsSet == (_index))
                    return "POST";
                throw SimpleEndpoint.noPathTemplateFound("method");

            },

在代码中,您将 id 设置为空字符串的默认值,当然它不为空

@Document(indexName = "vaultdoc")
class VaultDocument(
    @Field(type = FieldType.Text, store = true, fielddata = true)
    val vaultDocumentName: String,
    @org.springframework.data.annotation.Id
    var id: String = "",
)

并且在您的测试中您没有指定 id,因此我们有一个空字符串:

vaultDocumentRepo.save(VaultDocument("Test101"))

因此发送了

PUT
,但在 url
/vaultdoc/_doc/<empty id here>?refresh=false
中放入了空 id,但这是对没有 id 的新文档的请求,应该被
POST
ed。

您可以将 id 设为可为空并将默认值设置为

null
:

var id: String? = null

或者您删除默认的空字符串并为您保存的每个文档提供一个值。

为什么 Spring Data Elasticsearch 2 没有失败? 我没有挖掘 Elasticsearch 的旧代码,但我认为旧的

RestHighLevelClient
不仅检查 null,还检查空字符串

© www.soinside.com 2019 - 2024. All rights reserved.