实际项目开发中要求记录下用户的操作日志,创建一个时间轴展示相关操作日志信息,要求按时间降序显示。其中,操作日志采用ES存储。

二、实际代码

import com.alibaba.fastjson.JSONObject;
import com.google.gson.Gson;
import com.taobao.rigel.rap.model.CustomOperationLog;
import com.taobao.rigel.rap.utils.PrettyTimeTool;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.elasticsearch.search.sort.FieldSortBuilder;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
@RestController
@RequestMapping(value = "api/umeapiplus/log")
public class CustomOperationLogController {
    private static final Gson gson = new Gson();
    @Autowired
    private RestHighLevelClient client;
    public SearchHit[] findSearchHits(){
        SearchSourceBuilder sourceBuilder = new SearchSourceBuilder();
        sourceBuilder.fetchSource(new String[]{"log_operation_datetime", "log_operation_object"}, new String[]{});
        sourceBuilder.size(10000); //设置确定搜素命中返回数的size选项,默认为10
        sourceBuilder.sort(new FieldSortBuilder("log_operation_datetime").order(SortOrder.DESC));
//        sourceBuilder.sort(new ScoreSortBuilder().order(SortOrder.DESC));
        SearchRequest searchRequest = new SearchRequest("umeapi-logstash");
        searchRequest.source(sourceBuilder);
            SearchResponse response = client.search(searchRequest, RequestOptions.DEFAULT);
            SearchHits hits = response.getHits();
            SearchHit[] searchHits = hits.getHits();
            System.out.println("searchHits数组长度:" + searchHits.length);
            return searchHits;
        }catch (IOException e){
            e.printStackTrace();
        return null;
    @RequestMapping(value = "/getDynamicInformation", method = RequestMethod.GET)
    public List<CustomOperationLog> getDynamicInformation(){
        List<CustomOperationLog> returnList = new ArrayList<>();
        SearchHit[] searchHits = findSearchHits();
        for(SearchHit hit : searchHits){
            System.out.println("search -> " + hit.getSourceAsString());
            JSONObject totalJson = JSONObject.parseObject(hit.getSourceAsString());
            String operationObjStr = (String)totalJson.get("log_operation_object");
            System.out.println("operationObjStr: " + operationObjStr);
            if(null != operationObjStr){
                try {
                    CustomOperationLog temp = gson.fromJson(operationObjStr, CustomOperationLog.class);
                    temp.setHowLongBefore(PrettyTimeTool.getLastUpdateTimeStr(temp.getDateTime()));
                    returnList.add(temp);
                }catch (Exception e){
                    e.printStackTrace();
        return returnList;

代码分析:

sourceBuilder.sort(new FieldSortBuilder("log_operation_datetime").order(SortOrder.DESC));

这行代码实现了按自定义字段“log_operation_datetime”降序排序的需求

三、ES排序

ES提供了默认排序和自定义排序,默认排序通常都是按_score来排序的。自定义排序通常是使用sourceBuilder.sort(new FieldSortBuilder("字段名").order(SortOrder.DESC));实现的。SearchSourceBuilder允许添加一个或多个SortBuilder实例。SortBuilder有四种特殊的实现,分别是:FieldSortBuilder、GeoDistanceSortBuilder、ScoreSortBuilder、ScriptSortBuilder

  • FieldSortBuilder:根据某个特殊字段排序
  • ScoreSortBuilder:根据score排序
  • GeoDistanceSortBuilder:根据地理位置排序
  • ScriptSortBuilder:根据自定义脚本排序

四、遇到问题

1、调用接口时,报如下错误
“Fielddata is disabled on text fields by default. Set fielddata=true on [name] in order to load fielddata in memory by uninverting the inverted index. Note that this can however use significant memory. Alternatively use a keyword field instead.”
这个问题是由于我指定的字段“log_operation_datetime”是 text 类型。在ES搜索排序中,字段的类型必须是:integer、double、long或者keyword。否则使用该字段进行查询、排序、聚合时候,就会出现Fielddata is disabled on text fields by default.

解决办法:

  1. 把字段的索引类型改成keyword或者数值型(实际使用了本方法,解决了问题)
  2. 索引字段类型还是text,但是在mapping中加上fielddata=true。这种不推荐,因为这样加载时候,会占用过多的内存(自己没试过这种方法,仅供参考)
一、应用场景实际项目开发中要求记录下用户的操作日志,创建一个时间轴展示相关操作日志信息,要求按时间降序显示二、实际代码import com.alibaba.fastjson.JSONObject;import com.google.gson.Gson;import com.taobao.rigel.rap.model.CustomOperationLog;import com.taobao.rigel.rap.utils.PrettyTimeTool;import org.elasticsea 之前写过一篇使用RestHighLevelClient进行多字段group by的(【原创】ElasticSearch使用Java代码group by多个字段查询统计数量_DCTANT的博客-CSDN博客_elasticsearch分组统计 java),其实那篇并不完美,最佳的group by方法应该用script,而不是像之前那篇博客一样去递归求和,虽然也不是不行,但是这个毕竟太暴力了,效率也不高。直接上代码: 初始化RestHighLevelClient我这边为了节省篇幅先跳过了,直接上核心:Se
网络上关于Elasticsearch搜索引擎的教程不少, 但大多数都是比较老旧的, 甚至包括Elasticsearch官网的教程也是很久没有更新, 再加上Elasticsearch本身升级过程中不断的抛弃老旧概念, 新版本完全不兼容旧版本, 所以老旧教程给新入门的童鞋带来很多困惑. 这里使用当前Elasticsearch最新版本7.10.2结合Springboot2.X版本, 使用http rest api接口和RestHighLevelClient高级客户端封装的一些常用接口给新到的童鞋一些参考. JavaREST客户端有两种模式: Java低级REST客户端和高级REST客户端。低级别的客户端通过http与Elasticearch集群通信,版本兼容性好。高级REST客户端是基于低级客户端API的封装,版本兼容性差。需要的Java1.8以上的版本。Elasticsearch需要6.0以上。 Maven依赖 由于ElasticSearch版本不同,可能导致一些问题。自己要选择好适合自...