1. 程式人生 > >Elasticsearch遷移資料方案(不停服重建索引)

Elasticsearch遷移資料方案(不停服重建索引)

背景

  • Elasticsearch是一個高擴充套件的開源全文搜尋和分析引擎,它允許儲存、搜尋和分析大量的資料。
  • ES 的索引建立之後的 mapping 結構是不能夠修改的,如果系統中的 ES 索引沒有使用別名指向真正的索引,那麼要達到增刪mapping欄位的需求,就需要對索引進行重建。

方案

流程圖

image

開啟臨時索引

  • 在系統中定義開關,讀取外部配置檔案,當開關置為 true 時,所有資料將交給臨時索引儲存,也就是index_temp 進行處理。
  • 在index_temp接收資料的過程中,index_old依舊可以提供查詢服務,但是之前程式如果使用的是index_old查詢的話,會造成新新增進 index_temp 的資料不可查詢

拷貝資料

  • 將index_old的資料拷貝到index_new中
 ReindexAction.INSTANCE
 .newRequestBuilder(elasticsearchTemplate.getClient())
                    .source("index_old")
                    .destination("index_new")
                    .get();

刪除老索引&建立別名

  • 目前index_old中的資料已經全部拷貝到index_new中了,現在就要把index_old刪掉,建立index_old的別名指向index_new,也就是說將 index_old 刪掉,再建立名叫index_old的別名指向 index_new, 此時index_old 和 index_new 都能提供服務
  if (elasticsearchTemplate.indexExists("index_old")) {
            elasticsearchTemplate.deleteIndex("index_old");
        }

        AliasQuery aliasQuery = new AliasQuery();
        aliasQuery.setIndexName("index_new");
        aliasQuery.setAliasName("index_old");
        elasticsearchTemplate.
addAlias(aliasQuery);

關閉臨時索引

  • 將開關置為 false,此時所有資料將儲存到index_new, 就算程式中使用的名字是 index_old,資料也會儲存到 index_new, 因為設定了別名指向 index_new

遷移臨時索引資料到新索引

int curPage = 0;
    while (true) {
        SearchQuery query = new NativeSearchQuery(QueryBuilders.matchAllQuery()).setPageable(PageRequest.of(curPage, 1000));
        Page<IndexTemp> indexTemp = elasticsearchTemplate.queryForPage(query, IndexTemp.class);
            if (!indexTemp.hasContent()) {
                logger.info("index_temp 沒有跟多資料");
                logger.info("index_temp 遷移完成");
                 return;
              }
             List<IndexNew> infoList = new ArrayList<>();
            for (IndexTemp temp : indexTemp) {
                   IndexNew indexNew = new IndexNew();
                BeanUtils.copyProperties(temp, indexNew);
                   infoList.add(indexNew);
             }
             List<IndexQuery> indexQueries = infoList.stream().map(e -> {
                  IndexQuery indexQuery = new IndexQuery();
                 indexQuery.setObject(e);
                 return indexQuery;
              }).collect(Collectors.toList());

            elasticsearchTemplate.bulkIndex(indexQueries);
              logger.info("遷移一頁, page:{}, infoListSize:{}", curPage, infoList.size());
             curPage++;
         }

刪除臨時索引

if (elasticsearchTemplate.indexExists("index_temp")) {
            elasticsearchTemplate.deleteIndex("index_temp");
            logger.info("index_temp 刪除完成");
        }

總結

最後還是建議大家使用別名來指向真正的索引,使用別名對於索引結構的變更非常方便,只要將更改別名指向就 OK 了,簡單快捷