使用elasticsearch-repository时如何隐藏自动mapping的_class字段

以下代码相关示例,使用elasticsearch 7.6.2 + spring-boot 2.3.2-RELEASE

  spring-data-elasticsearch提供的ElasticsearchRepository很好用,能有效的对数据进行简单CRUD的同时,还对@Document修饰的model类字段在初始化时进行动态生成。
  例如如下被@Document生成的实体类,在使用@Field声明了相关字段,并且创建了对应ElasticsearchRepository的实现类后,启动项目时,实体类对应的es索引就会被自动创建出来:


@Document(indexName = "demo-product", refreshInterval = "5s")
@Getter
@Setter
@NoArgsConstructor
@ToString
public class Product {
    @Id
    private Long id;

    //商品名
    @MultiField(mainField = @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart"), otherFields = @InnerField(type = FieldType.Keyword, suffix = "raw", ignoreAbove = 256))
    private String productName;

    //商品描述
    @Field(type = FieldType.Text, analyzer = "ik_smart")
    private String description;

    //数据更新时间
    @Field(type = FieldType.Date_Nanos, index = false)
    private Long utime;

    //品牌名称
    @Field(type = FieldType.Keyword)
    private String brandName;

    //分类名称
    @Field(type = FieldType.Keyword)
    private String categoryName;
}


public interface ProductRepository extends ElasticsearchRepository {
}

  使用GET /demo-product/_mapping命令可查看到自动生成的索引字段结构:

{
  "demo-product" : {
    "mappings" : {
      "properties" : {
        "brandName" : {
          "type" : "keyword"
        },
        "categoryName" : {
          "type" : "keyword"
        },
        "description" : {
          "type" : "text",
          "analyzer" : "ik_smart"
        },
        "productName" : {
          "type" : "text",
          "fields" : {
            "raw" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          },
          "analyzer" : "ik_max_word",
          "search_analyzer" : "ik_smart"
        },
        "utime" : {
          "type" : "date_nanos",
          "index" : false
        }
      }
    }
  }
}

  然而如何让它能自动生成一些实体类字段额外的属性呢?
  比如Product这个实体类对应的索引虽然创建完成了,但是后续使用ProductRepository的save方法往索引中推数据时,会发现索引结构发生了变化:

    @Test
    void save() {
        Product product = new Product();
        product.setProductName("test product1");
        product.setBrandName("test brand1");
        product.setCategoryName("test category1");
        product.setId(1l);
        product.setDescription("test product description1");
        product.setUtime(Instant.now().getEpochSecond());
        productRepository.save(product);
    }

  再次使用GET /demo-product/_mapping命令查看索引字段结构:

{
  "demo-product" : {
    "mappings" : {
      "properties" : {
        "_class" : {
          "type" : "text",
          "fields" : {
            "keyword" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          }
        },
        "brandName" : {
          "type" : "keyword"
        },
        "categoryName" : {
          "type" : "keyword"
        },
        "description" : {
          "type" : "text",
          "analyzer" : "ik_smart"
        },
        "id" : {
          "type" : "long"
        },
        "productName" : {
          "type" : "text",
          "fields" : {
            "raw" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          },
          "analyzer" : "ik_max_word",
          "search_analyzer" : "ik_smart"
        },
        "utime" : {
          "type" : "date_nanos",
          "index" : false
        }
      }
    }
  }
}

  多出来的_class字段从哪里来的呢?

  其实是因为Product实例被保存到es时,会被序列化处理为json结构字符串(jackson),而类信息会被放置在固定字段_class上,用以在取回数据时反序列化为对应类实例,而由于我们没有在es中定义过_class这个字段,因此es在接收到数据后会按照默认方案,生成string字段对应的text+keyword结构。
  如果想自己在实体类中定义好这个字段,不让es自动生成,要怎么处理?
  我的方案是在实体类中定义一个不能被操作的占位字段:

    //在Product类中追加如下内容:

    //预配置索引的_class字段
    @Field(name = "_class", type = FieldType.Keyword, index = false)
    //配置Ignore,使jackson在序列化示例时跳过该字段
    @JsonIgnore
    //下面配置使得lombok不会为该字段生成getter、setter方法,也就不会有数据操作
    @Getter(value = AccessLevel.NONE)
    @Setter(value = AccessLevel.NONE)
    private String clazz;

  然后清理掉es索引,重启应用后,会发现在新的索引结构中已经存在了_class字段:

{
  "demo-product" : {
    "mappings" : {
      "properties" : {
        "_class" : {
          "type" : "keyword",
          "index" : false
        },
        "brandName" : {
          "type" : "keyword"
        },
        "categoryName" : {
          "type" : "keyword"
        },
        "description" : {
          "type" : "text",
          "analyzer" : "ik_smart"
        },
        "id" : {
          "type" : "long"
        },
        "productName" : {
          "type" : "text",
          "fields" : {
            "raw" : {
              "type" : "keyword",
              "ignore_above" : 256
            }
          },
          "analyzer" : "ik_max_word",
          "search_analyzer" : "ik_smart"
        },
        "utime" : {
          "type" : "date_nanos",
          "index" : false
        }
      }
    }
  }
}

  不过说实话,这么做的意义不是很大 ,我只是强迫症犯了罢了...
  如果朋友们有什么更好的方法,欢迎留言告知~

你可能感兴趣的:(使用elasticsearch-repository时如何隐藏自动mapping的_class字段)