Java实体未映射到ElasticSearch GeoPoint属性

时间:2019-04-05 15:42:41

标签: elasticsearch geo spring-data-elasticsearch

我正在开发一个微服务,用于通过使用spring-data-elasticsearch使用Java / Spring Boot管理位置,并且当尝试使用我的控制器向ES输入新数据时,数据输入未正确映射到ES中的文档,特别是地理位置属性“位置”。

我尝试从导入org.springframework.data.elasticsearch.core.geo.GeoPoint和org.springframework.data.elasticsearch.core.geo.GeoPoint中使用GeoPoint,在两种情况下都不会键入保存到ES的数据作为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

}

当我获得映射数据时,使用ElasticSearchRepository将数据保存到ES中后,显示如下:

{
  "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

请,我需要将GeoPoint字段(位置)映射到geo_point到ES中,这对于正确执行Geoqueries非常重要。

我正在使用Spring Data ElasticSearch和Spring Boot 2.1.3.RELEASE和ElasticSearch驱动程序6.4.3和ElasticSearch Server 6.4

5 个答案:

答案 0 :(得分:0)

我创建了一个带有存储库,控制器的最小应用程序,并使用Spring Boot 2.1.3.RELEASE,Spring Data Elasticsearch 3.1.5.RELEASE,elasticsearch客户端6.4.3和Elasticsearch服务器6.4.0来运行它。

我使用的Person pojo类具有两个geo_point字段,一个是普通弹簧GeoPoint,一个是使用MyGeoPoint注释的自定义GeoPointField。 / p>

启动应用程序并通过调用RestController的init方法插入一条记录后,索引中的映射就可以了:

{
  "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 (pj.meisch@sothawo.com)
 */
@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);
    }
}

所以我找不到此代码和所用版本的问题。您可以使用这些类重现该错误,还是可以构建一个最小化该错误的示例?

您确定映射是由Repository类而非其他地方创建的吗?

您可以在应用程序启动后之后检查映射,但之前是否将任何数据插入索引?

答案 1 :(得分:0)

我有一个类似的问题,但是我是这样解决的: 在ES端,按如下方式创建索引:

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

location中,我要成为geo_point类型的字段。打扰一下我的英语。 当然,ES的持久性必须遵循以下结构:

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

您说过here

答案 2 :(得分:0)

在我删除应用程序运行期间的索引后,我遇到了同样的问题(spring-boot 2.2.1.RELEASEspring-data-elasticserach 4.0.0.DATAES-690-SNAPSHOT

保存文档后,索引位置属性的错误映射

... other properites...

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

在应用程序运行时无法解决它,映射始终是错误的。

此解决方案对我有用:

  1. 删除索引
  2. 重新启动应用程序

现在,索引是使用 Just 位置字段创建的,所有其他字段映射都丢失了。将文档编入索引(使用ElasticSearchRepository.save后,一切都很好,并添加了其他映射。

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

答案 3 :(得分:0)

我遇到了类似的问题,但是在浏览了一些文档之后,我不得不使用以下代码段来使Elasticsearch将我的GeoPoint属性创建为geo_point类型的字段。

@Autowired
private ElasticsearchRestTemplate elasticsearchRestTemplate;

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

有关更多信息,请参阅post

答案 4 :(得分:-1)

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());