Spring Data Elasticsearch 的@Field 注释不起作用
Spring Data Elasticsearch's @Field annotation not working
我有一个 Spring 启动应用程序,在 pom.xml 中带有 Spring Data Elasticsearch 插件。我创建了一个文档 class,我想将其编入索引:
@Document(indexName = "operations", type = "operation")
public class OperationDocument {
@Id
private Long id;
@Field(
type = FieldType.String,
index = FieldIndex.analyzed,
searchAnalyzer = "standard",
indexAnalyzer = "standard",
store = true
)
private String operationName;
@Field(
type = FieldType.Date,
index = FieldIndex.not_analyzed,
store = true,
format = DateFormat.custom, pattern = "dd.MM.yyyy hh:mm"
)
private Date dateUp;
@Field(
type = FieldType.String,
index = FieldIndex.not_analyzed,
store = false
)
private String someTransientData;
@Field(type = FieldType.Nested)
private List<Sector> sectors;
//Getter and setters
我还为此创建了一个存储库 class:
public interface OperationDocumentRepository
extends ElasticsearchRepository<OperationDocument, Long> {
}
我做了一个测试,使用存储库索引了三个示例对象。它很长,所以我 post 只需要它。事实是ES服务器中创建的映射忽略了@Field注解设置的配置:
"mappings": {
"operation": {
"properties": {
"operationName": {
"type": "string"
},
"dateUp": {
"type": "long"
},
"someTransientData": {
"type": "string"
},
"sectors": {
"properties": {
"id": {
"type": "long"
},
"sectorName": {
"type": "string"
}
}
}
}
}
}
没有关于分析器的信息,"someTransientData" 被存储和索引,dateUp 被键入为 Long 而不是 Date。
直接从服务器请求的示例文档:
{
"_index": "operations",
"_type": "operation",
"_id": "AUyUk2cY3nXeOFxdOlQW",
"_version": 1,
"_score": 1,
"_source": {
"id": null,
"operationName": "Second Operation Name",
"dateUp": 1428421827091,
"someTransientData": "Do not index or store",
"sectors": [
{
"id": 2,
"sectorName": "Health Care"
},
{
"id": 3,
"sectorName": "Construction"
}
]
}
}
我还注意到,当我第二次 运行 应用程序时,在启动时出现此错误,仅在索引已存在时打印:
ERROR 19452 --- [main] .d.e.r.s.AbstractElasticsearchRepository : failed to load elasticsearch nodes : org.elasticsearch.index.mapper.MergeMappingException: Merge failed with failures {[mapper [someTransientData] has different index values, mapper [someTransientData] has different tokenize values, mapper [someTransientData] has different index_analyzer, object mapping [sectors] can't be changed from non-nested to nested, mapper [operationName] has different store values, mapper [operationName] has different index_analyzer, mapper [dateUp] of different type, current_type [long], merged_type [date]]}
这是 Spring Data Elastic Search 的错误还是我做错了什么?
我尝试了 spring 引导提供的稳定版本和 spring-data-elasticsearch 的最后一个快照。我还尝试了插件提供的嵌入式 Elasticsearch 服务器和当前版本的外部服务器。我总是得到相同的结果。
我尝试使用 spring data elasticsearch 示例应用程序来复制问题,但根据您的配置,我得到了如上所述的预期结果。
全部代码提交到这里 --> link
查看在 spring 上下文加载时生成索引并应用映射的 TestCase--> link
这是 TestCase 生成的映射:
{
"operations" : {
"aliases" : { },
"mappings" : {
"operation" : {
"properties" : {
"dateUp" : {
"type" : "date",
"store" : true,
"format" : "dd.MM.yyyy hh:mm"
},
"operationName" : {
"type" : "string",
"store" : true,
"analyzer" : "standard"
},
"sectors" : {
"type" : "nested"
},
"someTransientData" : {
"type" : "string",
"index" : "not_analyzed"
}
}
}
},
"settings" : {
"index" : {
"refresh_interval" : "1s",
"number_of_shards" : "5",
"store" : {
"type" : "fs"
},
"creation_date" : "1428677234773",
"number_of_replicas" : "1",
"version" : {
"created" : "1040499"
},
"uuid" : "-djzLu-IQ0CBs-M6R0-R6Q"
}
},
"warmers" : { }
}
}
你能用 spring boot using https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-data-elasticsearch
创建类似的例子吗
并提交 public 分享?
我终于可以复制并解决问题了。事实上,我使用 ElasticTemplate 来索引和搜索文档而不是存储库,因为我的业务逻辑变得更加复杂(使用聚合等)。
之后,我删除了未使用的 OperationDocumentRespository。似乎需要存储库才能在启动时将类型映射发布到 ES 服务器。我认为拥有 @Document class 应该就足够了,但事实并非如此。
所以我们这里有两个选择:
- 保留 OperationDocumentRepository
将此行添加到应用程序启动:
elasticsearchTemplate.putMapping(OperationDocument.class);
我在使用 spring-data-elasticsearch 时也遇到了这个错误并得到了解决方案。只需将代码放在下面,请查看评论。
ES 禁止在创建索引后更改字段类型。但是您可以更改其他属性,例如 fielddata
.
- Spring 数据弹性搜索 3.2.x
- 弹性搜索 6.8.4
- Spring 引导 2.2.x
package com.xxxx.xx.es.entity;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
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.Mapping;
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@Document(indexName = "gaming-laptop", indexStoreType = "fs")
@Mapping(mappingPath = "/gaming-laptop-mappings.json") // use custom json to configure data structure in ES, default spring data won't work although using @Field(type = FieldType.Keyword)
public class GamingLaptop extends BaseEntity {
@Id
private String id;
@Field
private String cpu;
@Field(type = FieldType.Keyword) // this only works in ES 7.6.2+, Spring Data Elasticsearch 4.0.X+
private String brandName;
@Field
private Integer cores;
@Field
private Integer threads;
@Field
private String coreFrequency;
@Field
private String ssd;
@Field
private String ram;
@Field
private String produceDate;
@Field
private Integer version;
@Field
private Double price;
@Field(type = FieldType.Keyword)
private String description;
}
resources/gaming-laptop-mappings.json
{
"properties":{
"_class":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"brandName":{
"type":"keyword"
},
"coreFrequency":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"cores":{
"type":"long"
},
"cpu":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"description":{
"type":"keyword"
},
"gmtCreated":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"gmtModified":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"price":{
"type":"float"
},
"produceDate":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"ram":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"ssd":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"threads":{
"type":"long"
},
"version":{
"type":"long"
}
}
}
或者,您可以使用 rest 高级客户端来调整 Javier Alvarez 的方法:
elasticsearchTemplate.putMapping(OperationDocument.class);
我有一个 Spring 启动应用程序,在 pom.xml 中带有 Spring Data Elasticsearch 插件。我创建了一个文档 class,我想将其编入索引:
@Document(indexName = "operations", type = "operation")
public class OperationDocument {
@Id
private Long id;
@Field(
type = FieldType.String,
index = FieldIndex.analyzed,
searchAnalyzer = "standard",
indexAnalyzer = "standard",
store = true
)
private String operationName;
@Field(
type = FieldType.Date,
index = FieldIndex.not_analyzed,
store = true,
format = DateFormat.custom, pattern = "dd.MM.yyyy hh:mm"
)
private Date dateUp;
@Field(
type = FieldType.String,
index = FieldIndex.not_analyzed,
store = false
)
private String someTransientData;
@Field(type = FieldType.Nested)
private List<Sector> sectors;
//Getter and setters
我还为此创建了一个存储库 class:
public interface OperationDocumentRepository
extends ElasticsearchRepository<OperationDocument, Long> {
}
我做了一个测试,使用存储库索引了三个示例对象。它很长,所以我 post 只需要它。事实是ES服务器中创建的映射忽略了@Field注解设置的配置:
"mappings": {
"operation": {
"properties": {
"operationName": {
"type": "string"
},
"dateUp": {
"type": "long"
},
"someTransientData": {
"type": "string"
},
"sectors": {
"properties": {
"id": {
"type": "long"
},
"sectorName": {
"type": "string"
}
}
}
}
}
}
没有关于分析器的信息,"someTransientData" 被存储和索引,dateUp 被键入为 Long 而不是 Date。
直接从服务器请求的示例文档:
{
"_index": "operations",
"_type": "operation",
"_id": "AUyUk2cY3nXeOFxdOlQW",
"_version": 1,
"_score": 1,
"_source": {
"id": null,
"operationName": "Second Operation Name",
"dateUp": 1428421827091,
"someTransientData": "Do not index or store",
"sectors": [
{
"id": 2,
"sectorName": "Health Care"
},
{
"id": 3,
"sectorName": "Construction"
}
]
}
}
我还注意到,当我第二次 运行 应用程序时,在启动时出现此错误,仅在索引已存在时打印:
ERROR 19452 --- [main] .d.e.r.s.AbstractElasticsearchRepository : failed to load elasticsearch nodes : org.elasticsearch.index.mapper.MergeMappingException: Merge failed with failures {[mapper [someTransientData] has different index values, mapper [someTransientData] has different tokenize values, mapper [someTransientData] has different index_analyzer, object mapping [sectors] can't be changed from non-nested to nested, mapper [operationName] has different store values, mapper [operationName] has different index_analyzer, mapper [dateUp] of different type, current_type [long], merged_type [date]]}
这是 Spring Data Elastic Search 的错误还是我做错了什么?
我尝试了 spring 引导提供的稳定版本和 spring-data-elasticsearch 的最后一个快照。我还尝试了插件提供的嵌入式 Elasticsearch 服务器和当前版本的外部服务器。我总是得到相同的结果。
我尝试使用 spring data elasticsearch 示例应用程序来复制问题,但根据您的配置,我得到了如上所述的预期结果。
全部代码提交到这里 --> link
查看在 spring 上下文加载时生成索引并应用映射的 TestCase--> link
这是 TestCase 生成的映射:
{
"operations" : {
"aliases" : { },
"mappings" : {
"operation" : {
"properties" : {
"dateUp" : {
"type" : "date",
"store" : true,
"format" : "dd.MM.yyyy hh:mm"
},
"operationName" : {
"type" : "string",
"store" : true,
"analyzer" : "standard"
},
"sectors" : {
"type" : "nested"
},
"someTransientData" : {
"type" : "string",
"index" : "not_analyzed"
}
}
}
},
"settings" : {
"index" : {
"refresh_interval" : "1s",
"number_of_shards" : "5",
"store" : {
"type" : "fs"
},
"creation_date" : "1428677234773",
"number_of_replicas" : "1",
"version" : {
"created" : "1040499"
},
"uuid" : "-djzLu-IQ0CBs-M6R0-R6Q"
}
},
"warmers" : { }
}
}
你能用 spring boot using https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples/spring-boot-sample-data-elasticsearch
创建类似的例子吗并提交 public 分享?
我终于可以复制并解决问题了。事实上,我使用 ElasticTemplate 来索引和搜索文档而不是存储库,因为我的业务逻辑变得更加复杂(使用聚合等)。
之后,我删除了未使用的 OperationDocumentRespository。似乎需要存储库才能在启动时将类型映射发布到 ES 服务器。我认为拥有 @Document class 应该就足够了,但事实并非如此。
所以我们这里有两个选择:
- 保留 OperationDocumentRepository
将此行添加到应用程序启动:
elasticsearchTemplate.putMapping(OperationDocument.class);
我在使用 spring-data-elasticsearch 时也遇到了这个错误并得到了解决方案。只需将代码放在下面,请查看评论。
ES 禁止在创建索引后更改字段类型。但是您可以更改其他属性,例如 fielddata
.
- Spring 数据弹性搜索 3.2.x
- 弹性搜索 6.8.4
- Spring 引导 2.2.x
package com.xxxx.xx.es.entity;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
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.Mapping;
@EqualsAndHashCode(callSuper = true)
@Data
@Builder
@Document(indexName = "gaming-laptop", indexStoreType = "fs")
@Mapping(mappingPath = "/gaming-laptop-mappings.json") // use custom json to configure data structure in ES, default spring data won't work although using @Field(type = FieldType.Keyword)
public class GamingLaptop extends BaseEntity {
@Id
private String id;
@Field
private String cpu;
@Field(type = FieldType.Keyword) // this only works in ES 7.6.2+, Spring Data Elasticsearch 4.0.X+
private String brandName;
@Field
private Integer cores;
@Field
private Integer threads;
@Field
private String coreFrequency;
@Field
private String ssd;
@Field
private String ram;
@Field
private String produceDate;
@Field
private Integer version;
@Field
private Double price;
@Field(type = FieldType.Keyword)
private String description;
}
resources/gaming-laptop-mappings.json
{
"properties":{
"_class":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"brandName":{
"type":"keyword"
},
"coreFrequency":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"cores":{
"type":"long"
},
"cpu":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"description":{
"type":"keyword"
},
"gmtCreated":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"gmtModified":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"price":{
"type":"float"
},
"produceDate":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"ram":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"ssd":{
"type":"text",
"fields":{
"keyword":{
"type":"keyword",
"ignore_above":256
}
}
},
"threads":{
"type":"long"
},
"version":{
"type":"long"
}
}
}
或者,您可以使用 rest 高级客户端来调整 Javier Alvarez 的方法:
elasticsearchTemplate.putMapping(OperationDocument.class);