ElasticSearch动态索引名称

1. 需求背景

在使用springframework.data.elasticsearch时,@Document指定的索引名称indexName,都是固定的,但是有些需求,需要动态生成不同的索引名称,但是索引的映射是相同的。

2. 解决方案

3. 代码实现

  • 创建动态索引的类

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    package com.xxx.web.cloud.bot.es.config;

    import cn.hutool.core.util.StrUtil;
    import com.xxx.web.cloud.bot.enums.EnvironmentEnum;
    import com.xxx.web.cloud.bot.util.CustomConstant;

    /**
    * ES动态索引
    * @author iseven.yang
    * @date 2023/10/9 10:37
    */
    public class DynamicIndex {

    private static final ThreadLocal<String> THREAD_LOCAL = new ThreadLocal<>();

    /**
    * 设置当前机器人id,索引名必须是小写
    * @param botId
    */
    public static void setIndexName(String indexName) {
    THREAD_LOCAL.set(indexName);
    }

    /**
    * 获取当前机器人id
    * @return
    */
    public static String getIndexName() {
    return THREAD_LOCAL.get();
    }

    /**
    * 移除变量
    */
    public static void remove() {
    THREAD_LOCAL.remove();
    }

    /**
    * 获取意图索引名称
    * @param environmentEnum
    * @param botId
    * @return
    */
    public static String getIntentIndexName(EnvironmentEnum environmentEnum, Long botId) {
    return CustomConstant.INDEX_INTENT_PREFIX + environmentEnum.name().toLowerCase() + StrUtil.UNDERLINE + botId;
    }

    /**
    * 获取问题索引名称
    * @param environmentEnum
    * @param botId
    * @return
    */
    public static String getQuestionIndexName(EnvironmentEnum environmentEnum, Long botId) {
    return CustomConstant.INDEX_QUESTION_PREFIX + environmentEnum.name().toLowerCase() + StrUtil.UNDERLINE + botId;
    }
    }

  • 创建Document

    • createIndex = false,不能自动创建索引
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    package com.xxx.web.cloud.bot.es.doc;

    import lombok.Data;
    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.Score;

    /**
    * 问题对象
    * @author iseven.yang
    * @date 2023/10/8 19:03
    */
    @Data
    @Document(indexName = "#{T(com.xxx.web.cloud.bot.es.config.DynamicIndex).getIndexName()}",
    shards = 1, replicas = 0, createIndex = false)
    public class QuestionDOC {

    ...

    }

  • 创建索引

    • elasticsearchRestTemplate.createIndex创建索引不会自动创建映射Mapping
    • 创建完索引之后要再创建一下映射elasticsearchRestTemplate.putMapping
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    try {
    String questionIndexName = DynamicIndex.getQuestionIndexName(env, botId);
    DynamicIndex.setIndexName(questionIndexName);
    if (elasticsearchRestTemplate.indexExists(questionIndexName)) {
    questionEsDao.deleteAll();
    } else {
    elasticsearchRestTemplate.createIndex(QuestionDOC.class);
    elasticsearchRestTemplate.putMapping(QuestionDOC.class);
    }
    questionEsDao.saveAll(questionDOCS);
    } finally {
    DynamicIndex.remove();
    }
  • 使用

    • DynamicIndex.setIndexName(questionIndex);先设置当前索引名称
    • 操作完索引之后,需要清除线程本地变量DynamicIndex.remove();
    1
    2
    3
    4
    5
    6
    7
    8
    try {
    DynamicIndex.setIndexName(questionIndex);
    for (Long faqId : faqIds) {
    questionEsDao.deleteByIntentId(faqId);
    }
    } finally {
    DynamicIndex.remove();
    }