如何计算满足特定最小日期的不同值

时间:2015-09-04 14:13:52

标签: elasticsearch

我有以下结构的文件(简化):

curl -XPOST "http://localhost:9200/test/aggtest/1" -d "{
    \"user_id\": 123,
    \"date_created\": \"2015-05-12T10:29:49-04:00\"
}"

curl -XPOST "http://localhost:9200/test/aggtest/2" -d "{
    \"user_id\": 123,
    \"date_created\": \"2014-05-12T10:29:49-04:00\"
}"

curl -XPOST "http://localhost:9200/test/aggtest/3" -d "{
    \"user_id\": 123,
    \"date_created\": \"2013-05-12T10:29:49-04:00\"
}"

curl -XPOST "http://localhost:9200/test/aggtest/4" -d "{
    \"user_id\": 456,
    \"date_created\": \"2015-05-12T10:29:49-04:00\"
}"

curl -XPOST "http://localhost:9200/test/aggtest/5" -d "{
    \"user_id\": 456,
    \"date_created\": \"2012-05-12T10:29:49-04:00\"
}"

curl -XPOST "http://localhost:9200/test/aggtest/6" -d "{
    \"user_id\": 456,
    \"date_created\": \"2011-05-12T10:29:49-04:00\"
}"

如何计算在某个日期之前或之后创建的user_ids的计数?例如。在上述文件中,只有一个独特的user_id在2012年之后有记录。

在mongodb中,它相当简单。使用聚合框架,我可以转换文档,其中将是一个唯一的用户ID及其最小创建日期。然后只按日期和计数过滤结果。我无法在elasticsearch中编写类似的查询。任何帮助表示赞赏。

在SQL中,此查询应如下所示:

 SELECT COUNT(DISTINCT(user_id)) FROM aggtest WHERE date_created >= 2015 AND user_id NOT IN (SELECT user_id FROM aggtest WHERE date_created < 2015)

2 个答案:

答案 0 :(得分:1)

通过阅读评论,我认为我理解你所问的是什么,尽管原始问题并不完全清楚。

听起来你想要找到在某个日期之后有user_id s的唯一creation_date s,但之前没有。{/ p>

我想不出用你当前的数据结构做到这一点的方法,但如果你愿意使用parent/child relationship重新组织数据,那么设置你想要的查询就相当简单。 / p>

为了测试它,我设置了一个有两种类型的索引,如下所示:

PUT /test_index
{
   "mappings": {
      "user": {
         "_id": {
            "path": "user_id"
         },
         "properties": {
            "user_id": {
               "type": "integer"
            }
         }
      },
      "creation_date": {
         "_parent": {
            "type": "user"
         }, 
         "properties": {
            "date_created": {
               "type": "date",
               "format": "dateOptionalTime"
            }
         }
      }
   }
}

然后我使用新架构索引您提供的数据:

POST /test_index/_bulk
{"index":{"_type":"user"}}
{"user_id":123}
{"index":{"_type":"creation_date","_parent":123}}
{"date_created":"2015-05-12T10:29:49-04:00"}
{"index":{"_type":"creation_date","_parent":123}}
{"date_created":"2014-05-12T10:29:49-04:00"}
{"index":{"_type":"creation_date","_parent":123}}
{"date_created":"2013-05-12T10:29:49-04:00"}
{"index":{"_type":"user"}}
{"user_id":456}
{"index":{"_type":"creation_date","_parent":456}}
{"date_created":"2015-05-12T10:29:49-04:00"}
{"index":{"_type":"creation_date","_parent":456}}
{"date_created":"2012-05-12T10:29:49-04:00"}
{"index":{"_type":"creation_date","_parent":456}}
{"date_created":"2011-05-12T10:29:49-04:00"}

现在我可以通过以下查询回复您所问的内容(假设我理解正确)。换句话说,我希望那些至少有一个(孩子)user大于或等于creation_date的人过滤(父)"2012-05-12"文件,但是没有(孩子) )creation_date小于"2012-05-12",然后我想在聚合中显示这些ID(聚合在这里是多余的,但我假设你的真实索引更复杂,所以它可能是有用的是不返回完整的user文件):

POST /test_index/user/_search?search_type=count
{
   "query": {
      "filtered": {
         "filter": {
            "bool": {
               "must": [
                  {
                     "has_child": {
                        "type": "creation_date",
                        "filter": {
                           "range": {
                              "date_created": {
                                 "gte": "2012-05-12"
                              }
                           }
                        }
                     }
                  },
                  {
                     "not": {
                        "filter": {
                           "has_child": {
                              "type": "creation_date",
                              "filter": {
                                 "range": {
                                    "date_created": {
                                       "lt": "2012-05-12"
                                    }
                                 }
                              }
                           }
                        }
                     }
                  }
               ]
            }
         }
      }
   },
   "aggs": {
      "distinct_user_ids": {
         "terms": {
            "field": "user_id"
         }
      }
   }
}

返回:

{
   "took": 2,
   "timed_out": false,
   "_shards": {
      "total": 1,
      "successful": 1,
      "failed": 0
   },
   "hits": {
      "total": 1,
      "max_score": 0,
      "hits": []
   },
   "aggregations": {
      "distinct_user_ids": {
         "doc_count_error_upper_bound": 0,
         "sum_other_doc_count": 0,
         "buckets": [
            {
               "key": 123,
               "doc_count": 1
            }
         ]
      }
   }
}

以下是我用来测试它的所有代码:

http://sense.qbox.io/gist/1fbe448a85b9c74cb25cd5245d4e77f1eec46ea7

答案 1 :(得分:0)

使用基数聚合在字段中获取不同的值计数:https://www.elastic.co/guide/en/elasticsearch/guide/current/cardinality.html

将聚合与范围过滤器结合使用,将结果限制为时间范围:https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-filter.html

示例:

GET /test/aggtest/_search
{
  "size": 0,
  "query": {
    "filtered" : {
        "filter" : {
            "range" : {
                "date_created" : {
                    "gte": "2015-09-01"
                }
            }
        }
    }
  },
  "aggs" : {
    "distinct_user_ids" : {
      "cardinality" : {
        "field" : "user_id"
      }
    }
  }
}

您将获得doc_count聚合的distinct_user_ids聚合结果。