Java解析ES查询结果的聚合JSONObject

Java解析ES查询结果的聚合JSONObject

最近在开发过程中需要用Java将从ES(ElasticSearch)查询中的聚合结果进行解析,考虑到聚合结果的JSONObject虽然会根据DSL的不同有所区别,但还是具有一定的特殊规则,因此写了一个较为公用的解析方法。

一、 需要解析的DSL查询结果

在这里遇到的实际业务场景是对一些客户信息进行查询,然后按照CUST_ID进行分桶,分桶后又对每个桶进一步的过滤和计算度量值,ES的返回结果最后封装成JSONObject。

注:ES的分桶和计算度量值类似于MySQL的group by后求sum,count等。

{
    "took": 3,
    "timed_out": false,
    "_shards": {
        "total": 3,
        "successful": 3,
        "failed": 0
    },
    "hits": {
        "total": 6,
        "max_score": 2.9459102,
        "hits": [
            {
                "_index": "gler-20190227190920",
                "_type": "main",
                "_id": "csdn_gler0001",
                "_score": 2.9459102,
                "_source": {
                    "OUT_SUM": "10000",
                    "ONWAY_STATE": "N",
                    "ALL_SUM": "10000",
                    "DATE": "2019-02-19",
                    "BUSI_CODE": "GLTEST",
                    "CUST_NAME": "XXX",
                    "IS_VALD ": "Y",
                    "C_SUM": "20000",
                    "G_ID": "XXXX ",
                    "ID": "test_gler0001",
                    "CUST_ID": "glertest"
                }
            },
{
	……
}
        ]
    },
    "aggregations": {
        "cust_data": {
            "doc_count_error_upper_bound": 0,
            "sum_other_doc_count": 0,
            "buckets": [
                {
                    "key": "glertest",
                    "doc_count": 4,
                    "all_count": {
                        "value": 4
                    },
                    "vald_data": {
                        "doc_count": 3,
                        "out_data ": {
                            "doc_count": 1,
                            "out_count": {
                                "value": 1
                            }
                        },
                        "vald_count": {
                            "value": 3
                        },
                        "out_sum": {
                            "value": 60000
                        },
                        "all_sum": {
                            "value": 70000
                        }
                    }
                },
                {
                    ……
                },
            ]
        }
    }
}

二、 实际解析需求

对于查询hit的记录是比较好处理的,只需要对于”hits”对象的”hits”数据依次进行解析,逐个获取”_source”的值即可。对于聚合结果“aggregations”对象,会根据DSL的写法返回不同格式的结果,但重要的聚合对象是固定的,如需要解析获得桶“buckets”下的信息,再获取桶下过滤后的度量值“value”,同时还需要获取分桶元素值CUST_ID,即每个桶的“key”。

三、 代码实现

/* 聚合结果解析 */
  public static void parseESAggResult(getJSONObject qryResult) {
    if (qryResult.containsKey("aggregations")) {
      JSONObject aggs = qryResult.getJSONObject("aggregations");
      /* 按CUST_ID分桶的数据 */
      List<JSONObject> esResults = esResults = getAggsBucketData("cust_data", aggs);
      /* 由于可能有多层桶,需要根据实际需求转为Map再获取想要的字段或直接获取字段 */
      for (JSONObject innerJo : esResults) {
        innerJo.get("cust_data-key");
        innerJo.get("all_count ");
        ......
      }
    }
  }

// 公用解析代码

/**
   * 遍历Buckets
   * 
   * @param bucketName 需要解析的聚合名
   * @param jo
   * @return
   */
  public static List<JSONObject> getAggsBucketData(String bucketName, JSONObject jo) {
    List<JSONObject> results = new ArrayList<JSONObject>();
    if (jo.containsKey(bucketName)) {
      JSONObject bucketAgg = jo.getJSONObject(bucketName);
      /* 获取桶中的bucket数组 */
      JSONArray buckets = bucketAgg.getJSONArray("buckets");
      /* 遍历每个数组对象 */
      for (Object object : buckets) {
        JSONObject innerJo = (JSONObject) object;
        JSONObject result = new JSONObject();
        parseJSON(innerJo, bucketName, result);
        results.add(result);
      }
    }
    return results;
  }

  /**
   * 解析JSONObject,返回桶bucket的value和度量值
   * 
   * @param jo
   * @param fieldName
   * @param result
   */
  public static void parseJSON(JSONObject jo, String fieldName, JSONObject result) {
    for (String key : jo.keySet()) {
      /* JSONObject,继续往底层解析 */
      if (jo.get(key) instanceof JSONObject) {
        /* 有桶buckets */
        if (jo.getJSONObject(key).get("buckets") != null) {
          JSONObject bucketJo = new JSONObject();
          bucketJo.put(key, jo.getJSONObject(key));
          result.put(key, getAggsBucketData(key, bucketJo));
        } else {
          parseJSON(jo.getJSONObject(key), key, result);
        }
      } else {
        /* 度量值 */
        if ("value".equals(key)) {
          result.put(fieldName, jo.get(key));
        } else if ("key".equals(key)) {
          /* 桶的key值 */
          result.put(fieldName + "-" + key, jo.get(key));
        }
      }
    }
  }

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值