3

I'm develop a microservice for manage locations with Java/Spring Boot using spring-data-elasticsearch and when try to enter new data to ES using my controller the data input is not mapped properly to a document into ES, specifically the Geopoint attribute "location".

I'm tried using GeoPoint from import org.springframework.data.elasticsearch.core.geo.GeoPoint and from org.springframework.data.elasticsearch.core.geo.GeoPoint, in both cases data saved to ES is not typed as geo_point

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.Field;
import org.springframework.data.elasticsearch.annotations.FieldType;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;

import io.swagger.annotations.ApiModelProperty;

@Document(indexName = "location", type="location")
public class Location {

    @Id
    @ApiModelProperty(hidden = true)
    private String id;

    private String appId;

    private String resourceId;

    @GeoPointField
    private GeoPoint location;

    private String street;

    private String city;

    // more attr and method was ommited

}

After save data into ES using ElasticSearchRepository when I get mapping data is showed like:

{
  "location" : {
    "mappings" : {
      "location" : {
        "properties" : {
          "appId" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "city" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
          },
          "country" : {
            "properties" : {
              "countryCcFips" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              },
              "countryCcIso" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              },
              "countryName" : {
                "type" : "text",
                "fields" : {
                  "keyword" : {
                    "type" : "keyword",
                    "ignore_above" : 256
                  }
                }
              }
            }
          },
          "location" : {
            "properties" : {
              "lat" : {
                "type" : "float"
              },
              "lon" : {
                "type" : "float"
              }
            }
          },
          "parish" : {
            "type" : "text",
            "fields" : {
              "keyword" : {
                "type" : "keyword",
                "ignore_above" : 256
              }
            }
// ommited more json data

Please, I need that GeoPoint field (location) will mapped to geo_point into ES, is important to execute Geoqueries properly.

I'm , using Spring Data ElasticSearch, with Spring Boot 2.1.3.RELEASE and ElasticSearch driver 6.4.3 with ElasticSearch server 6.4

1
  • That's strange indeed, I just checked the code, normally you would just need to have either the GeoPoint class or the GeoPointField annotation to have the field typed as "geo_point". This place in the code hasn't changed for years. I will try to reproduce this with a local example, but can't promise that I will find the time today. Commented Apr 8, 2019 at 15:59

5 Answers 5

3

I have created a minimal application with a repository, a controller and am running this with Spring Boot 2.1.3.RELEASE, Spring Data Elasticsearch 3.1.5.RELEASE, elasticsearch client 6.4.3 and an Elasticsearch server 6.4.0.

I am using a Person pojo class that has two geo_point fields, one is a normal spring GeoPoint and one a custom MyGeoPoint that uses the GeoPointFieldannotation.

After starting the application and inserting a record by calling the RestController's init method, the mapping in the index are alright:

{
  "person": {
    "aliases": {},
    "mappings": {
      "person": {
        "properties": {
          "firstName": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "geoPoint": {
            "type": "geo_point"
          },
          "id": {
            "type": "long"
          },
          "lastName": {
            "type": "text",
            "fields": {
              "keyword": {
                "type": "keyword",
                "ignore_above": 256
              }
            }
          },
          "myGeoPoint": {
            "type": "geo_point"
          }
        }
      }
    },
    "settings": {
      "index": {
        "refresh_interval": "1s",
        "number_of_shards": "5",
        "provided_name": "person",
        "creation_date": "1554750620775",
        "store": {
          "type": "fs"
        },
        "number_of_replicas": "1",
        "uuid": "w1L279wOQUmvDPMu4iYXtg",
        "version": {
          "created": "6040099"
        }
      }
    }
  }
}

Person.java

/*
 * (c) Copyright 2019 sothawo
 */
package com.sothawo.springdataelastictest;

import org.springframework.data.annotation.Id;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.annotations.GeoPointField;
import org.springframework.data.elasticsearch.core.geo.GeoPoint;

/**
 * @author P.J. Meisch ([email protected])
 */
@Document(indexName = "person", type = "person")
public class Person {
    @Id private Long id;
    private String lastName;
    private String firstName;

    private GeoPoint geoPoint;

    @GeoPointField private MyGeoPoint myGeoPoint;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getLastName() {
        return lastName;
    }

    public void setLastName(String lastName) {
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public void setFirstName(String firstName) {
        this.firstName = firstName;
    }

    public GeoPoint getGeoPoint() {
        return geoPoint;
    }

    public void setGeoPoint(GeoPoint geoPoint) {
        this.geoPoint = geoPoint;
    }

    public MyGeoPoint getMyGeoPoint() {
        return myGeoPoint;
    }

    public void setMyGeoPoint(MyGeoPoint myGeoPoint) {
        this.myGeoPoint = myGeoPoint;
    }

    @Override
    public String toString() {
        return "Person{" +
                "id=" + id +
                ", lastName='" + lastName + '\'' +
                ", firstName='" + firstName + '\'' +
                ", geoPoint=" + geoPoint +
                ", myGeoPoint=" + myGeoPoint +
                '}';
    }

    public static class MyGeoPoint {
        private double lat;
        private double lon;

        public double getLat() {
            return lat;
        }

        public void setLat(double lat) {
            this.lat = lat;
        }

        public double getLon() {
            return lon;
        }

        public void setLon(double lon) {
            this.lon = lon;
        }

        @Override
        public String toString() {
            return "MyGeoPoint{" + "lat=" + lat + ", lon=" + lon + '}';
        }
    }
}

PersonRepository.java:

package com.sothawo.springdataelastictest;

import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;

public interface PersonRepository extends ElasticsearchRepository<Person, Long> {}

ElasticsearchRepositoryController.java:

package com.sothawo.springdataelastictest;

import org.springframework.data.elasticsearch.core.geo.GeoPoint;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/repo")
public class ElasticsearchRepositoryController {

    private PersonRepository personRepository;

    public ElasticsearchRepositoryController(PersonRepository personRepository) {
        this.personRepository = personRepository;
    }

    @GetMapping("/init")
    public Long initPerson() {
        final Person person = new Person();
        person.setId(42L);
        person.setFirstName("John");
        person.setLastName("Doe");

        GeoPoint geoPoint = new GeoPoint(12.34, 56.78);
        person.setGeoPoint(geoPoint);

        Person.MyGeoPoint myGeoPoint = new Person.MyGeoPoint();
        myGeoPoint.setLat(43.21);
        myGeoPoint.setLon(87.65);
        person.setMyGeoPoint(myGeoPoint);

        return personRepository.save(person).getId();

    }
}

SpringdataElasticTestApplication.java:

package com.sothawo.springdataelastictest;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.elasticsearch.repository.config.EnableElasticsearchRepositories;

@SpringBootApplication
@EnableElasticsearchRepositories
public class SpringdataElasticTestApplication {

    public static void main(String[] args) {
        SpringApplication.run(SpringdataElasticTestApplication.class, args);
    }
}

So I cannot find a problem with this code and the versions I used. Can you reproduce the error with these classes or build a minimal example that reproduces the error?

Are you sure, that the mapping is created by the Repository class and not somewhere else?

And can you please check the mapping after the application is started, but before any data is inserted into the index?

Sign up to request clarification or add additional context in comments.

3 Comments

How did you create your index? For me it creates in a way which does not have geo_point!!
The index is created automatically on startup if it does not exist
I found out that for Geo Point, dynamic mapping does not work and has to be done manually or enforced through code. Also, I tried your provided solution with specified versions and it did not solve the problem.
2

I had the same issue, after I deleted an Index during the runtime of the application (spring-boot 2.2.1.RELEASE with spring-data-elasticserach 4.0.0.DATAES-690-SNAPSHOT).

After I saved a document, the index hat the wrong mapping for the location property:

... other properites...

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

I could not solve it during the runtime of the application, the mapping was always wrong.

This solution worked for me:

  1. delete the index
  2. restart the application

Now the index was created with JUST the location field, all other field-mappings missing. After indexing documents (with ElasticSearchRepository.save), everything was fine, the other mappings where added.

{
    "properties": {
        "location": {
            "type": "geo_point"
        }
    }
}

1 Comment

Worked for me ! Thousands Thanks !
0

I had a similar problem but I solved it this way: On the ES side, create the index like this:

PUT my_index
{
  "mappings": {
    "properties": {
      "doc.location": {
        "type": "geo_point"
      }
    }
  }
}

In location is the field that I want to be geo_point type. Excuse my English. Of course, ES must follow the following structure for its persistence:

"location": { 
    "lat": 41.12,
    "lon": -71.34
}

You said it here.

1 Comment

Explain your answer.
0

I had a similar problem but after some documentation surfing I had to use the following code snippet to get the Elasticsearch to create my GeoPoint property as a geo_point typed field.

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

@PostConstruct
public void init() {
    IndexOperations indexOperations = elasticsearchRestTemplate.indexOps(PropertySearch.class);
    indexOperations.putMapping(indexOperations.createMapping());
    indexOperations.refresh();
}

For more information you can refer post

Comments

0
if (elasticsearchRestTemplate.indexOps(MerchantModel.class).exists()) {
    elasticsearchRestTemplate.indexOps(MerchantModel.class).delete();
}
// fix geo_point mapping
CreateIndexRequest createIndexRequest = new CreateIndexRequest("merchant");
createIndexRequest.mapping("{\n" +
        "      \"properties\": {\n" +
        "        \"location\": {\n" +
        "          \"type\": \"geo_point\"\n" +
        "        }\n" +
        "      }\n" +
        "    }", XContentType.JSON);
IndicesClient indicesClient = restHighLevelClient.indices();
CreateIndexResponse createIndexResponse = indicesClient.create(createIndexRequest, RequestOptions.DEFAULT);
log.info("create ES merchant mapping:[isAcknowledged={}]", createIndexResponse.isAcknowledged());

1 Comment

Please don't post only code as answer, but also provide an explanation what your code does and how it solves the problem of the question. Answers with an explanation are usually more helpful and of better quality, and are more likely to attract upvotes.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.