Geographic Coordinates and Java API Client in 8.6

Hello.
I'm trying to create documents from a Java app. Those documents includes geographic coordinates (lat and lon in decimal form).
Both Elasticsearch and the java client are in 8.6.0.
In the beginning, no index exists in ES.
If I only insert data, the index is created but the coordinates are not typed as coordinates.
I tried several types in my Java object : GeoPoint, GeoHash, GeoLocation.
I also tried to create the index at first with a specific mapping :

            CreateIndexResponse response = client.indices().create(c -> c
                    .index("my_index")
                    .mappings(map -> map
                            .properties("position", p -> p.geoPoint(g -> g))));

And then, I have errors when inserting data with a bulk request.
How can I do that operation ?
Thanks for your help.

1 Like

Bonjour Benjamin :blush:

Could you provide more information?

  • A typical document meant to be indexed
  • The exact error message

Hello David !
I have a
com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) (through reference chain: ch.hsr.geohash.GeoHash[0]

My documents are Java objects with String attributes and, on my last try, a Geohash for the position.
Each attribute has a getter and a setter.
The source data provides lat and lon.
I try to convert it with

GeoHash.withBitPrecision(lat, lon, 10);

Could you share your bean definition please?

In case it helps, this is how I'm doing this:

My first object looks like :

public class ElasticObject {

    private String id;
    private String num;
    private String streetName;
    private String postCode;
    private String city;
    private GeoHash position;

    public ElasticObject(String id, String num, String streetName, String postCode, String city, double lat, double lon) {
        this.id = id;
        this.num = num;
        this.streetName = streetName;
        this.postCode = postCode;
        this.city = city;
        this.position = GeoHash.withBitPrecision(lat, lon, 10);
    }

The bulk request looks like :

        BulkRequest.Builder br = new BulkRequest.Builder();

        for (ElasticObject esObject : data) {
            br.operations(op -> op
                    .index(idx -> idx.index("bano").id(esObject.getId()).document(esObject)));
        }
        BulkResponse result = client.bulk(br.build());

Could you try with a similar data structure I shared?
I don't think it's possible to have other inner fields than lat and lon in the JSON sent to Elasticsearch.

I succedded in what I wanted to do by using an ingest pipeline.
At first, I created it from a CSV import in Kibana.
And then, I saw how to recreate it programatically with the Java API client.

        ConvertProcessor latProcessor =
                new ConvertProcessor.Builder().field("lat").type(ConvertType.Double).build();
        ConvertProcessor lonProcessor =
                new ConvertProcessor.Builder().field("lon").type(ConvertType.Double).build();
        SetProcessor positionProcessor = new SetProcessor.Builder().field("location").copyFrom("{{lat}},{{lon}}").build();
        List<Processor> processors = List.of(new Processor.Builder().convert(cpProcessor).build(),
                new Processor.Builder().convert(latProcessor).build(),
                new Processor.Builder().convert(lonProcessor).build(),
                new Processor.Builder().set(positionProcessor).build());


        PutPipelineRequest pipelineRequest =
                new PutPipelineRequest.Builder().id("myPipeline").processors(processors).build();
        ElasticsearchIngestClient ingestClient = new ElasticsearchIngestClient(transport);
        PutPipelineResponse pipelineResponse = ingestClient.putPipeline(pipelineRequest);

        BulkRequest.Builder br = new BulkRequest.Builder();
        br.pipeline("myPipeline");

Why are you doing that server side (in Elasticsearch) and not Client side (in your application)?

I didn't find out how to do it on the client side.

Just change the ElasticObject. And use a data structure as I shared in my previous answer. Look at the GeoPoint class.

When I do as you did, the data is created but as double and distinct values :
In the mapping of the index, the location looks like (the index does not exist before I run the code, that's why I performed operations on the server side, to tell him how to create the index)

"location": {
        "properties": {
          "lat": {
            "type": "float"
          },
          "lon": {
            "type": "float"
          }
        }
      },

And after creating the data view, if I try to use it in a map, I have a message saying
Data view does not contain any geospatial fields

It's because you need to create the mapping before indexing any data.

Look at:

and

1 Like

Now that works.
Thanks !

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