针对我的 spring 项目的不同部署生成不同的 Elasticsearch 映射

Elasticsearch mappings generated differently for different deployments for my spring project

在我的spring项目中,我使用注解来定义elasticsearch字段。据我了解,elasticsearch 映射是在应用程序启动时根据这些注释生成的。但是,生成的映射对于不同的部署是不同的。

我是 运行 spring 项目 Java 8 和 ElasticSearch 5.5.0。

注释:

@Size(min = MINIMUM_LENGTH_NAME, max = MAXIMUM_LENGTH_NAME)
@NotNull
@Column(name = "name", nullable = false)
@Field(store = Store.YES)
@Field(name = "name_forSort", normalizer = @Normalizer(definition = "lowercase"))
@SortableField(forField = "name_forSort")
private String name;

名称的预期映射:

{
  "mappings": {
    "properties": {
      "name" : {
        "type" : "text",
        "store" : true
      },
      "name_forSort" : {
        "type" : "keyword",
        "norms" : true,
        "normalizer" : "lowercase"
      }
    }
  }
}

有问题的部署的映射:

{
  "mappings": {
    "properties": {
       "name" : {
         "type" : "text",
         "fields" : {
           "keyword" : {
             "type" : "keyword",
             "ignore_above" : 256
           }
         }
       },
       "name_forSort" : {
         "type" : "text",
         "fields" : {
           "keyword" : {
             "type" : "keyword",
             "ignore_above" : 256
           }
         }
       },
    }
  }
}

Elasticsearch 5.5.0 是旧版本,您没有指定您很少使用哪个 Spring Data Elasticsearch(为简洁起见,我将其称为 SDE)版本。我在这个答案中展示的解决方案是使用支持 Elasticsearch 6.8.2 的当前 SDE 3.2.0.RC1 进行测试的,但是正如在 SDE 的源代码中看到的那样,此功能在旧版本中可用并且应该适用于您的版本也是如此。

您的代码存在问题:

  • 您正在混合放在 属性 上的不同注释,但只有第二个 @Field 注释来自 SDE。 @Field(store = Store.YES) 不是来自 SDE,正确的注释具有类型为 booleanstore 属性。 @Column@SortableField 都不为 SDE 所知,因此在构建映射时将被忽略。

  • 在具有不同设置的索引中多次使用一个字段的正确方法是 using fields mapping(正如您在 link 中看到的那样,这已经在 5.5 中了)。 SDE 通过 @MultiField 注释支持这一点。

我有 运行 一个包含以下文件的最小示例:

normalizer.json

{
    "index": {
        "analysis": {
            "normalizer": {
                "lowercase": {
                    "type": "custom",
                    "char_filter": [],
                    "filter": [ "lowercase" ]
                }
            }
        }
    }
}

Person.java

package com.sothawo.springdataelastictest;

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.InnerField;
import org.springframework.data.elasticsearch.annotations.MultiField;
import org.springframework.data.elasticsearch.annotations.Setting;

@Document(indexName = "person-test")
@Setting(settingPath = "normalizer.json")
public class Person {
    @Id private Long id;

    @MultiField(mainField = @Field(store = true, type = FieldType.Text),
                otherFields = {
                    @InnerField(suffix = "forSort", 
                                normalizer = "lowercase", 
                                type = FieldType.Keyword)
                })
    private String name;

    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

PersonRepository.java

package com.sothawo.springdataelastictest;

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

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

使用这些 类 启动 Spring 引导应用程序会创建以下索引:

{
  "person-test": {
    "aliases": {},
    "mappings": {
      "person": {
        "properties": {
          "name": {
            "type": "text",
            "store": true,
            "fields": {
              "forSort": {
                "type": "keyword",
                "normalizer": "lowercase"
              }
            }
          }
        }
      }
    },
    "settings": {
      "index": {
        "number_of_shards": "5",
        "provided_name": "person-test",
        "creation_date": "1563903601344",
        "analysis": {
          "normalizer": {
            "lowercase": {
              "filter": [
                "lowercase"
              ],
              "type": "custom",
              "char_filter": []
            }
          }
        },
        "number_of_replicas": "1",
        "uuid": "WhSFtV-xQ8acXxX6R0gLyg",
        "version": {
          "created": "6070299"
        }
      }
    }
  }
}

问题已通过启动一个新的 ES 实例然后重新索引来解决。奇怪的映射似乎是由先前失败的重建索引和损坏的数据引起的。