elasticsearch reindex和sort的使用

本文详细介绍如何在Elasticsearch中优化排序过程,特别是针对数值型字段的排序,通过reindexing和调整索引设置来提高效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

背景

使用sort的时候需要注意,如果排序字段是字符串类型的(text、string),那么会按照排序字段的值的字典顺序进行排序。

而有时候我们需要按照实际数值进行排序,这时候就需要重建索引reindex,重建索引的时候使用新的模板或指定mapping,以便将排序字段的类型修改为integer之类的数值型。

步骤

1.新建模板

PUT _template/sort_template
{
  "order": 1,
  "index_patterns": "springboot*",
  "settings": {
    "number_of_shards": 5,
    "number_of_replicas": 1
  },
  "mappings": {
    "data":{
      "dynamic_templates" : [ {  
        "keyword_field" : {  
          "match" : "*Name",  
          "match_mapping_type" : "string",  
           "mapping" : {  
            "type" : "text",
            "fields": {
              "raw": {
                "type": "keyword"
              }
            }
          }  
        }  
      }],  
      "properties": {
        "execTime":
        {
          "type":"integer"
        },
        "message":{
          "type":"text"
        }
      }
    }
  }
}

因为要对execTime字段进行排序,因此指定其类型为integer。

注意:es默认情况下进行自动类型解析的时候,会将string类型映射成text,且子类型名称和对应的类型都为keyword。因此为了保持自定义模板与默认的类型解析在这方面保持一致,上面的模板最好将子类型名称raw改成keyword。

2.创建新索引

PUT springboot-testsort

创建一个新的索引,用于reindex。根据此索引的名字可以映射到刚才创建的模板。

3.修改索引配置

PUT springboot-testsort/_settings
{
     "number_of_replicas": 0,
     "refresh_interval": -1
}

因为原索引的数据量很大,通过修改配置来提高reindex的效率。这里将副本数设为0(禁用副本),刷新间隔为-1(禁止刷新)。具体可参考https://blog.youkuaiyun.com/laoyang360/article/details/81589459

注意:在reindex的过程中出现gateway timeout的异常,其实并不是报错,还是正常在复制数据。

4.reindex

post _reindex?slices=20//&refresh这里如何加上了refresh则会导致setting中的-1失效
{
  "source": {
    "index": "springboot-2020.04.20",
    "type":"applog",
    "size":10000
  },
  "dest": {
    "index": "springboot-testsort",
    "type":"data"
  }
}

注意:reindex的时候有个细节,就是source中的index+type的组合必须是存在的,比如这里如果index对应的type不是applog,那么就没有数据。同理对于dest来说,index+type的组合也必须是存在的,否则也没有数据。除此之外,对于dest来说,如果使用的是动态模板mapping,模板中指定了type,那么reindex的时候dest中的type需要与模板中的保持一致。

这个复制的过程可能会持续几分钟。

reindex完成之后,需要修改settings,因为没有refresh,需要修改成1s或其他指定时间,让它refresh到os内存,之后才能检索到。

PUT springboot-testsort/_settings
{
     "number_of_replicas": 2,
     "refresh_interval": "1s"
}

5.进行top N排序

GET springboot-testsort/data/_search
{
  "_source": ["execTime"],
  "query": {
    "bool": {
      "must":[
      {
        "exists":{
              "field": "className"
            }},
            {
        "term":{
          "className.raw":"log.utils.LogUtil"
        }
      }
    ]
    }
  }, 
    "sort" : [
        { "execTime" : {"order" : "desc"}}
    ],
    "from": 0,
    "size": 20
}

 

以下是使用Java高级客户端通过别名,根据批次号页码列表批量修改index-202305索引中的数据中的一个字段的示例代码: ```java import org.elasticsearch.action.bulk.BulkRequest; import org.elasticsearch.action.bulk.BulkResponse; import org.elasticsearch.action.index.IndexRequest; import org.elasticsearch.action.update.UpdateRequest; import org.elasticsearch.client.RequestOptions; import org.elasticsearch.client.RestHighLevelClient; import org.elasticsearch.common.xcontent.XContentBuilder; import org.elasticsearch.common.xcontent.XContentFactory; import org.elasticsearch.index.query.BoolQueryBuilder; import org.elasticsearch.index.query.QueryBuilders; import org.elasticsearch.index.reindex.DeleteByQueryRequest; import org.elasticsearch.index.reindex.ScrollableHitSource; import org.elasticsearch.index.reindex.UpdateByQueryRequest; import org.elasticsearch.index.reindex.UpdateByQueryResponse; import org.elasticsearch.rest.RestStatus; import org.elasticsearch.search.builder.SearchSourceBuilder; import org.elasticsearch.search.sort.SortOrder; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class ESIndexUpdateExample { private RestHighLevelClient client; public ESIndexUpdateExample(RestHighLevelClient client) { this.client = client; } public void updateIndex(String alias, int batchNo, List<Integer> pageList, String fieldName, String fieldValue) throws IOException { // 1. 构建查询条件 BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery(); queryBuilder.must(QueryBuilders.termQuery("batch_no", batchNo)); queryBuilder.must(QueryBuilders.termsQuery("page_no", pageList)); // 2. 构建更新请求 XContentBuilder builder = XContentFactory.jsonBuilder(); builder.startObject().field(fieldName, fieldValue).endObject(); UpdateRequest updateRequest = new UpdateRequest().doc(builder); // 3. 使用Scroll API检索所有文档 SearchSourceBuilder sourceBuilder = new SearchSourceBuilder(); sourceBuilder.query(queryBuilder); sourceBuilder.sort("timestamp", SortOrder.DESC); ScrollableHitSource scrollableHitSource = new ScrollableHitSource(client, alias, sourceBuilder); BulkRequest bulkRequest = new BulkRequest(); // 4. 批量更新文档 while (scrollableHitSource.hasNext()) { scrollableHitSource.next().ifPresent(hit -> { updateRequest.index(hit.getIndex()); updateRequest.id(hit.getId()); bulkRequest.add(updateRequest); }); } BulkResponse bulkResponse = client.bulk(bulkRequest, RequestOptions.DEFAULT); if (bulkResponse.hasFailures()) { System.out.println("Bulk update failed: " + bulkResponse.buildFailureMessage()); } else { System.out.println("Bulk update succeeded: " + bulkResponse.status()); } // 5. 刷新索引 client.indices().refresh(RequestOptions.DEFAULT, alias); // 6. 删除旧索引中的所有文档 DeleteByQueryRequest deleteRequest = new DeleteByQueryRequest(); deleteRequest.setQuery(QueryBuilders.boolQuery() .must(QueryBuilders.termQuery("batch_no", batchNo)) .must(QueryBuilders.termsQuery("page_no", pageList))); deleteRequest.setIndices("index-" + batchNo + "*"); deleteRequest.setRefresh(true); client.deleteByQuery(deleteRequest, RequestOptions.DEFAULT); } public static void main(String[] args) throws IOException { RestHighLevelClient client = new RestHighLevelClient(); ESIndexUpdateExample example = new ESIndexUpdateExample(client); int batchNo = 202305; List<Integer> pageList = new ArrayList<>(); pageList.add(1); pageList.add(2); example.updateIndex("indexAlias", batchNo, pageList, "field_name", "new_field_value"); client.close(); } } ``` 在代码中,我们首先构建了一个BoolQueryBuilder对象,用于构建查询条件。然后,我们使用XContentBuilder构建了UpdateRequest对象,用于更新特定字段的值。接下来,我们使用Scroll API检索所有满足查询条件的文档,并使用Bulk API批量更新文档。最后,我们使用Delete By Query API删除旧索引中的所有文档,以确保只有新索引中的数据可用。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值