How to use XContentBuilder in Elasticsearch 8.0

Hi,

i found some examples how to use XContentBuilder in Elasticsearch 7.x but these examples do not work any more since ESJAC is completely new programmed. But as XContentBuilder still exists: XContentBuilder (elasticsearch-x-content 8.1.0 API)
i wonder if there are any working examples out there.

Thanks - Enomine

Here is what i tried so far:

		org.elasticsearch.xcontent.XContentBuilder xcb = XContentFactory.jsonBuilder();
		xcb.startObject();
		{
			xcb.startObject("properties");
			{
				xcb.startObject("Rechnungsdatum");
				{
					xcb.field("type", "date");
				}
				xcb.endObject();
			}
			xcb.endObject();
		}
		xcb.endObject();

		
		ByteArrayOutputStream baos = (ByteArrayOutputStream) xcb.getOutputStream();
		byte[] bytes = baos.toByteArray();
		System.out.println("b:" + bytes[0]);
		InputStream is = new ByteArrayInputStream(bytes);
		SourceField sf = new SourceField.Builder().withJson(is).build();
		PutMappingRequest pmr2 = new PutMappingRequest.Builder().index("rechnungen4").source(sf).build();
		client.indices().putMapping(pmr2);

But in the Line of the sysout the bytes-Array is already empty, which leads to a jakarta.json.JsonException: Cannot auto-detect encoding, not enough chars.

Thanks - Enomine

Okay so far so good, found this way:

org.elasticsearch.xcontent.XContentBuilder xcb = XContentFactory.jsonBuilder();
		xcb.startObject();
		{
			xcb.startObject("properties");
			{
				xcb.startObject("Rechnungsdatum");
				{
					xcb.field("type", "date");
				}
				xcb.endObject();
			}
			xcb.endObject();
		}
		xcb.endObject();
		String json = Strings.toString(xcb);
		System.out.println(json);
		SourceField sf = new SourceField.Builder().withJson(new StringReader(json)).build();
		PutMappingRequest pmr2 = new PutMappingRequest.Builder().index("rechnungen4").source(sf).build();
		client.indices().putMapping(pmr2);

by including an old dependency:

	<dependency>
      <groupId>org.elasticsearch.client</groupId>
      <artifactId>transport</artifactId>
      <version>7.17.6</version>
	</dependency>

But above code results in:

{"properties":{"Rechnungsdatum":{"type":"date"}}}
Exception in thread "main" co.elastic.clients.json.JsonpMappingException: Error deserializing co.elastic.clients.elastic
search._types.mapping.SourceField: Unknown field 'properties' (JSON path: properties) (line no=1, column no=14, offset=1
3)
	at co.elastic.clients.json.ObjectDeserializer.parseUnknownField(ObjectDeserializer.java:221)
	at co.elastic.clients.json.ObjectDeserializer.deserialize(ObjectDeserializer.java:178)
	at co.elastic.clients.util.WithJsonObjectBuilderBase.withJson(WithJsonObjectBuilderBase.java:54)
	at co.elastic.clients.json.WithJson.withJson(WithJson.java:57)

First line shows that JSON is correct. But SourceField seems not to like it. Why does it even care about my JSON? Its correct so just send it! =(

Thanks - Enomine

... Still working on that problem.
Now i figured out a "solution" without an exception but it does nothing to the index because SourceField is empty.

		XContentBuilder xcb = XContentFactory.jsonBuilder();
		xcb.startObject();
		xcb.startObject("properties");
		xcb.startObject("Rechnungsdatum");
		xcb.field("type", "date");
		xcb.endObject();
		xcb.endObject();
		xcb.endObject();
		String json = Strings.toString(xcb);
		System.out.println(json);
		jakarta.json.stream.JsonParser jp = Json.createParser(new StringReader(json));
		JsonpMapper jm = new JacksonJsonpMapper();
		// jm.ignoreUnknownFields();
		SourceField sf = new SourceField.Builder().withJson(jp, jm).build();
		System.out.println(sf.toString());
		PutMappingRequest pmr2 = new PutMappingRequest.Builder().index("rechnungen4").source(sf).build();
		client.indices().putMapping(pmr2);

Thanks - Enomine

Finally i figured it out. Well Elasticsearch is really not beginner friendly!

GetMappingRequest gmr = new GetMappingRequest.Builder().index("rechnungen5").build();
		GetMappingResponse gma = client.indices().getMapping(gmr);
		System.out.println(gma.toString());

		Map<String, Property> msp = new HashMap<String, Property>();
		msp.put("Rechnungsnummer", new Property.Builder().integer(new IntegerNumberProperty.Builder().build()).build());
		msp.put("Rechnungsbetrag", new Property.Builder().float_(f -> f).build());
		PutMappingRequest pmr = new PutMappingRequest.Builder().index("rechnungen5").properties(msp).build();
		PutMappingResponse pma = client.indices().putMapping(pmr);
		System.out.println(pma.toString());

		gma = client.indices().getMapping(gmr);
		System.out.println(gma.toString());

		XContentBuilder xcb = XContentFactory.jsonBuilder();
		xcb.startObject();
		xcb.startObject("properties");
		xcb.startObject("Rechnungsdatum");
		xcb.field("type", "date");
		xcb.endObject();
		xcb.endObject();
		xcb.endObject();
		String json = Strings.toString(xcb);
		System.out.println(json);
		jakarta.json.stream.JsonParser jp = Json.createParser(new StringReader(json));
		JsonpMapper jm = new JacksonJsonpMapper();
		// jm.ignoreUnknownFields();
		PutMappingRequest pmr2 = new PutMappingRequest.Builder().index("rechnungen5").withJson(jp, jm).build();
		PutMappingResponse pma2 = client.indices().putMapping(pmr2);
		System.out.println(pma2.toString());

		gma = client.indices().getMapping(gmr);
		System.out.println(gma.toString());

Thanks - Enomine

And you can get rid of JsonParser and JsonpMapper:

XContentBuilder xcb = XContentFactory.jsonBuilder();
		xcb.startObject();
		xcb.startObject("properties");
		xcb.startObject("Rechnungsdatum");
		xcb.field("type", "date");
		xcb.endObject();
		xcb.endObject();
		xcb.endObject();
		String json = Strings.toString(xcb);
		System.out.println(json);
		PutMappingRequest pmr2 = new PutMappingRequest.Builder().index("rechnungen7").withJson(new StringReader(json)).build();
		PutMappingResponse pma2 = client.indices().putMapping(pmr2);
		System.out.println(pma2.toString());

Thanks - Enomine

I think @swallez maybe was wrong in this?

Thanks - Enomine

You don't need XContent for what you want to achieve (create an index mapping).

The Java API client offers a fully typed API to create your mappings:

esClient.indices().putMapping(m -> m
    .index("rechnungen4")
    .properties("Rechnungsdatum", p -> p
        .date(d -> d) // d is a DateProperty.Builder on which we don't set any value, keeping all defaults.
    )
);

Hey swallez,

thanks for that information.

So i wrote this to manage the same task:

pma = client.indices().putMapping(m -> m.index(rechnungen12)
			.properties("Rechnungsnummer", p -> p.integer(i -> i))
			.properties("Rechnungsdatum", p -> p.date(d -> d))
			.properties("Rechnungsbetrag", p -> p.float_(f -> f))
			.properties("Gläubiger", p -> p.text(t -> t))
			.properties("Schuldner", p -> p.text(t -> t)));
		System.out.println(pma.toString());

Thanks - Enomine

This topic was automatically closed 28 days after the last reply. New replies are no longer allowed.