Spring boot 实现 Elasticsearch 动态创建索引

本文介绍了如何在Spring Boot 2.7.1应用中,利用Elasticsearch 7.17.3动态创建索引。通过实体ID自定义索引名称,避免了使用Spring Expression Language (SpEL)方式无法处理数据库生成序号的问题。文中详细展示了配置Bean、接口定义、实现类及调用方法。

查找了很多方法都是通过Spring EL表达式实现 @Document(IndexName="#{demo.getIndexName}")

这种方式的问题在于没法解决数据库里生成的序号,例如我希望通过公司ID生成索引编号。后来在外网上找到一个大佬提出的解决方案,这位大佬把两种方案都实现了一遍。

  • 通过entityId自定义index

Use an index name defined by the entity to store data in Spring Data Elasticsearch 4.0

  • 通过SpEL动态生成index

How to provide a dynamic index name in Spring Data Elasticsearch using SpEL

我这里按照entity的方式实现了需求

elasticsearch 版本7.17.3

springboot版本2.7.1

Bean


@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
@EqualsAndHashCode(callSuper = false)
@Document(indexName = ElasticSearchIndices.ES_INDEX_TROUBLES_COMPANY+"_*",createIndex = false)
public class CompanyTroubleshootingBean implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    @JsonSerialize(
            using = ToStringSerializer.class
    )
    @Field(type = FieldType.Keyword , store = true)
    private Long id;

    @Field(type = FieldType.Text, analyzer = "ik_smart")
    private String content;

    @Field(type = FieldType.Text, analyzer = "ik_smart")
    private String searchKeyword;
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String contentMaxWord;
    @Field(type = FieldType.Text, analyzer = "ik_max_word", searchAnalyzer = "ik_smart")
    private String searchKeywordMaxWord;

    private Integer useCounts;

    //也是内容  这个内容不能分词查询
    @Field(type = FieldType.Keyword)
    private String keywordContent;

    @Field(type = FieldType.Keyword)
    private Integer catalogId;

    public String getContentMaxWord() {
        return content;
    }
    //私有化set方法,让该属性只读
    private void setContentMaxWord(String contentMaxWord) {
        this.content = contentMaxWord;
    }

    public String getSearchKeywordMaxWord() {
        return searchKeyword;
    }
    //私有化set方法,让该属性只读
    private void setSearchKeywordMaxWord(String searchKeywordMaxWord) {
        this.searchKeyword = searchKeywordMaxWord;
    }


    /**
     * 公司ID
     */
    private Integer companyId;

    /**
     * 平台的解决方案ID
     */
    @JsonFormat(shape = JsonFormat.Shape.STRING)
    @JsonSerialize(
            using = ToStringSerializer.class
    )
    private Long platformTroubleshootingId;



}

接口

//相当于重新定义了一个repository
public interface CompanyTroubleshootElasticRepository<T> {
    <S extends T> S save(S entity);

    <S extends T> Iterable<S> save(Iterable<S> entities);
}

实现类

package online.ejiang.service.impl.troubleshooting;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import online.ejiang.enums.ElasticSearchIndices;
import online.ejiang.pojo.elasticsearch.CompanyTroubleshootingBean;
import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
import org.springframework.data.elasticsearch.core.IndexOperations;
import org.springframework.data.elasticsearch.core.document.Document;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.stereotype.Service;

import java.util.concurrent.ConcurrentHashMap;

/**
 * <p>
 * 公司故障排除及定价 服务实现类
 *
 * </p>clo
 *
 * @author Phil
 * @since 2020-07-22
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class CompanyTroubleshootingRepositoryImpl implements CompanyTroubleshootElasticRepository<CompanyTroubleshootingBean> {

    private final ElasticsearchOperations operations;

    @Nullable
    private Document mapping;

    @Override
    public <S extends CompanyTroubleshootingBean> S save(S entity) {
        IndexCoordinates indexCoordinates = getIndexCoordinates(entity);
        S saved = operations.save(entity, indexCoordinates);
        operations.indexOps(indexCoordinates).refresh();
        return saved;
    }

    @Override
    public <S extends CompanyTroubleshootingBean> Iterable<S> save(Iterable<S> entities) {
        if (entities != null && entities.iterator().hasNext()) {
            IndexCoordinates indexCoordinates = getIndexCoordinates(entities.iterator().next());
            Iterable<S> saved = operations.save(entities, indexCoordinates);
            operations.indexOps(indexCoordinates).refresh();
            return saved;
        }
        return null;
    }

    @NonNull
    private <S extends CompanyTroubleshootingBean> IndexCoordinates getIndexCoordinates(S entity) {
        String indexName = ElasticSearchIndices.ES_INDEX_TROUBLES_COMPANY + "_" + entity.getCompanyId();
        //把单实例的Map变成每次调用都初始化,解决重新同步时需要重启服务器的问题。
        ConcurrentHashMap<String, IndexCoordinates> knownIndexCoordinates = new ConcurrentHashMap<>();
        return knownIndexCoordinates.computeIfAbsent(indexName, i -> {
            IndexCoordinates indexCoordinates = IndexCoordinates.of(i);
            IndexOperations indexOps = operations.indexOps(indexCoordinates);
            if (!indexOps.exists()) {
                indexOps.create();
                if (mapping == null) {
                    mapping = indexOps.createMapping(CompanyTroubleshootingBean.class);
                }
                indexOps.putMapping(mapping);
            }
            return indexCoordinates;
        });
    }
}

调用

do {
            IPage<CompanyTroubleshootingBean> beanPage = this.pageByCustom(new MyPage<>(index, 800), companyId);
            pages = beanPage.getPages();

            Iterable<CompanyTroubleshootingBean> saved = companyTroubleshootElasticRepository.save(beanPage.getRecords());
            if (saved != null && saved.iterator().hasNext()) {
                index++;
            } else {
                break;
            }

        } while (index <= pages);

评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值