Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bulk indexing fails with INDENT_OUTPUT configured on JacksonJsonpMapper's ObjectMapper #644

Open
dconnelly opened this issue Aug 3, 2023 · 0 comments
Labels
Category: Bug Something isn't working

Comments

@dconnelly
Copy link

Java API client version

8.9.0

Java version

17

Elasticsearch Version

8.9.0

Problem description

Was trying to enable SerializationFeature.INDENT_OUTPUT with JacksonJsonpMapper's ObjectMapper in order to make traces easier to read during local testing and debugging. Unfortunately, this seems to cause the ES client to generate a malformed request:

20:31:52.690 [main] TRACE tracer - curl -iX POST 'https://localhost:52608/_bulk' -d '{"index":{"_index":"test"}}
{
  "name" : "book",
  "description" : "a small book"
}
'
# HTTP/1.1 400 Bad Request
# X-elastic-product: Elasticsearch
# content-type: application/vnd.elasticsearch+json;compatible-with=8
# content-length: 301
#
# {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"Malformed action/metadata line [3], expected START_OBJECT but found [VALUE_STRING]"}],"type":"illegal_argument_exception","reason":"Malformed action/metadata line [3], expected START_OBJECT but found [VALUE_STRING]"},"status":400}

Reproducer:

package com.yammer.embeddings.elastic;

import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch.core.BulkRequest;
import co.elastic.clients.json.jackson.JacksonJsonpMapper;
import co.elastic.clients.transport.rest_client.RestClientTransport;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.elasticsearch.client.RestClient;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
import org.testcontainers.elasticsearch.ElasticsearchContainer;
import org.testcontainers.utility.DockerImageName;

class BulkBugTest {
  static final ElasticsearchContainer container = new ElasticsearchContainer(
      DockerImageName.parse("docker.elastic.co/elasticsearch/elasticsearch")
          .withTag("8.9.0"));

  static final String INDEX_NAME = "test";

  static RestClient restClient;

  record Item(String name, String description) {}

  @BeforeAll
  static void init() throws Exception {
    container.start();
    var credentials = new BasicCredentialsProvider();
    credentials.setCredentials(
        AuthScope.ANY, new UsernamePasswordCredentials(
            "elastic", ElasticsearchContainer.ELASTICSEARCH_DEFAULT_PASSWORD)
    );
    restClient = RestClient.builder(HttpHost.create("https://" + container.getHttpHostAddress()))
        .setHttpClientConfigCallback(builder -> builder
            .setSSLContext(container.createSslContextFromCa())
            .setDefaultCredentialsProvider(credentials))
        .build();
    var client = new ElasticsearchClient(
        new RestClientTransport(restClient, new JacksonJsonpMapper()));
    client.indices().create(req -> req
        .index(INDEX_NAME)
        .mappings(mappings -> mappings
            .properties("name", b -> b.keyword(k -> k.index(true)))
            .properties("description", b -> b.keyword(k -> k.index(false)))
        )
    );
  }

  @AfterAll
  static void destroy() throws Exception {
    if (restClient != null) {
      restClient.close();
    }
    container.stop();
  }

  @Test
  void succeedsWithoutIndent() throws Exception {
    var client = new ElasticsearchClient(
        new RestClientTransport(restClient, new JacksonJsonpMapper()));
    var item = new Item("book", "a small book");
    var bulk = new BulkRequest.Builder();
    bulk.operations(op -> op.index(index -> index.index(INDEX_NAME).document(item)));
    var response = client.bulk(bulk.build());
  }

  @Test
  void failsWithIndent() throws Exception {
    var mapper = new ObjectMapper()
        .configure(SerializationFeature.INDENT_OUTPUT, true);
    var client = new ElasticsearchClient(
        new RestClientTransport(restClient, new JacksonJsonpMapper(mapper)));
    var item = new Item("book", "a small book");
    var bulk = new BulkRequest.Builder();
    bulk.operations(op -> op.index(index -> index.index(INDEX_NAME).document(item)));
    var response = client.bulk(bulk.build());
  }
}
@l-trotta l-trotta added the Category: Bug Something isn't working label Apr 22, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Category: Bug Something isn't working
Projects
None yet
Development

No branches or pull requests

2 participants