Elasticsearch聚合,用于将文档字段与多个存储桶的存储桶密钥进行比较

时间:2016-03-17 17:04:58

标签: elasticsearch

我有订单索引。索引中的每个文档都包含订单完成的日期。我正在尝试构建一个聚合,为我提供日期直方图聚合的历史工作(wip)。通过将完成日期与日期直方图中的每个日期进行比较来计算wip。如果完成日期>当前的桶日期然后该订单被认为正在进行中并且应该包含在桶中。

从我的研究中我可以确定的最好的是使用值脚本的date_histogram会给我我需要的结果。但是我无法弄清楚如何构建我的脚本。

目前我的查询如下:

{
    "query": {
        "match_all": {}
    },
    "aggs": {
        "wip": {
            "date_histogram": {
                "field": "com_ord_created_ddate",
                "script": "doc['com_ord_completed_ddate'] > _value",
                "interval": "day",
                "format": "yyyy-MM-dd"
            }
        }
    }
}

此查询返回以下异常

{
  "error": {
    "root_cause": [
      {
        "type": "script_exception",
        "reason": "failed to run inline script [doc['com_ord_completed_ddate'] > _value] using lang [groovy]"
      }
    ],
    "type": "search_phase_execution_exception",
    "reason": "all shards failed",
    "phase": "query",
    "grouped": true,
    "failed_shards": [
      {
        "shard": 0,
        "index": "orders",
        "node": "eYYqpuNSQ0KOt04JEztTDg",
        "reason": {
          "type": "script_exception",
          "reason": "failed to run inline script [doc['com_ord_completed_ddate'] > _value] using lang [groovy]",
          "caused_by": {
            "type": "groovy_runtime_exception",
            "reason": "Cannot compare org.elasticsearch.index.fielddata.ScriptDocValues$Longs with value '[1445864743000]' and java.lang.Long with value '1,445,618,646,000'"
          }
        }
      }
    ]
  },
  "status": 500
}

我知道剧本写得不好。我无法找到明确概述脚本范围内可用变量的文档。我从qbox教程https://qbox.io/blog/elasticsearch-scripting-aggregations得到_value 但是关于_value是什么以及其他可用于操作的变量还不够。

有人能指出我清楚汇总内联价值脚本的文档,还是可以通过提供一个可以获得我需要的结果的脚本来帮助我?

更新 我能够用这个来得到我问题的第一部分:

{
    "query": {
        "match_all": {}
    },
    "aggs": {
        "wip": {
            "date_histogram": {
                "field": "com_ord_created_ddate",
                "script": "if(_value < doc['com_ord_completed_ddate'].value) {_value} else {0}",
                "interval": "day",
                "format": "yyyy-MM-dd"
            }
        }
    }
}

但是,脚本仅限于比较已汇总到存储桶的文档。我需要比较每个桶的结果中的所有文档。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

请尝试以下查询

{
"query": {
    "match_all": {}
},
"aggs": {
    "wip": {
        "date_histogram": {
            "field": "com_ord_created_ddate",
            "script": "doc['com_ord_completed_ddate'].value > _value",
            "interval": "day",
            "format": "yyyy-MM-dd"
        }
    }
}

请注意doc['com_ord_completed_ddate']

之后的.value

Script aggregation

的文档

答案 1 :(得分:0)

我非常接近使用看起来像这样的scripted_metric聚合来获得我需要的东西。

"aggs": {
    "wip": {
        "scripted_metric": {
            "init_script": "_agg['created_dates'] = []; _agg['documents'] = []",
            "map_script": "_agg.created_dates.add(doc['com_ord_created_ddate'].value); document = [:]; document.created_date = doc['com_ord_created_ddate']; document.completed_date = doc['com_ord_completed_ddate']; _agg.documents.add(document); return _agg;",
            "combine_script": "_agg.created_dates.unique()",
            "reduce_script": "results = []; wip = [:];for (agg in _aggs) { for (d in agg.created_dates) {wip.key = d; wip.doc_count = 0; for(o in agg.documents) { if (d < o.completed_date && d >= o.created_date) { wip.doc_count++ } }; results.add(wip); }; }; return results;"
        }
    }
}

不幸的是,脚本的优化程度很低,查询耗时10-15秒,对于ES来说这是永恒的,并且不符合项目的性能要求。

最后,我通过进行多个ES查询得到了我所需的结果。我首先查询上面提到的date_histogram聚合,没有脚本参数。然后,我在服务器端循环遍历聚合中返回的每个日期,并执行另一个查询以获取该特定日期的历史记录。它不漂亮,但令人惊讶的是它比scripted_metric更快。最终用户的总加载时间约为2-3秒,这是我用例中可接受的时间范围。