假设我有一个访问索引,其中包含"visit"类型的文档,如下所示:
{
"id": "c223a991-b4e7-4333-ba45-a576010b568b",
// other properties
"buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e",
"arrivalDateTimeUtc": "2015-12-22T21:15:00Z"
}
以下函数将返回一个直方图,该直方图根据给定时区返回给定范围内每天的访问量。
public Bucket<HistogramItem> Execute(MyParameterType parameters)
{
var buildingFilter = Filter<VisitProjection>.Term(x => x.BuildingId, parameters.BuildingId);
var dateFilter = Filter<VisitProjection>.Range(r => r
.OnField(p => p.ArrivalDateTimeUtc)
.GreaterOrEquals(parameters.EarliestArrivalDateTimeUtc)
.LowerOrEquals(parameters.LatestArrivalDateTimeUtc)
);
var result = _elasticClient.Search<VisitProjection>(s => s
.Index("visits")
.Type("visit")
.Aggregations(a => a
.Filter("my_filter_agg", f => f
.Filter(fd => buildingFilter && dateFilter)
.Aggregations(ta => ta.DateHistogram("my_date_histogram", h => h
.Field(p => p.ArrivalDateTimeUtc)
.Interval(parameters.DateInterval) // "day"
.TimeZone(NodaTimeHelpers.WindowsToIana(parameters.TimeZoneInfo)) // This is a critical piece of the equation.
.MinimumDocumentCount(0)
)
)
)
)
);
return result.Aggs.Nested("my_filter_agg").DateHistogram("my_date_histogram");
}
}
// Returns [{Date: 12/22/2015 12:00:00 AM, DocCount: 1}]
现在想象一下,我改变了一点。假设我在文档中添加了一个新字段:
{
"id": "c223a991-b4e7-4333-ba45-a576010b568b",
// other properties
"buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e",
"arrivalDateTimeUtc": "2015-12-22T21:15:00Z",
"departureDateTimeUtc": "2015-12-23T22:00:00Z" // new property
}
并假设我想返回以下内容:
// Returns [{Date: 12/22/2015 12:00:00 AM, DocCount: 1}, {Date: 12/23/2015 12:00:00 AM, DocCount: 1}]
因为访问跨越了两天,我想要一个日期直方图,它记录访问跨越的每一天的一个单位。
如何使用 NEST/Elastic Search 执行此操作?
注1:除非有人说服我,否则我认为收集范围内的所有文档并在中间层(或C#层)执行聚合/存储桶化和日期直方图不是一个好主意。
注意2:这个问题的时区方面至关重要,因为我需要根据给定的时区对计数进行分组。
可能是使用scripted_metric
聚合并根据两个日期字段自己执行存储桶。非常复杂,性能并不高,具体取决于您有多少文档。
但是,另一种更简单的解决方案可能是使用单个日期字段并将间隔的所有日期放入数组中(首先到达,最后离开以及介于两者之间的所有其他日期),如下所示:
{
"id": "c223a991-b4e7-4333-ba45-a576010b568b",
"buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e",
"visitDateTimeUtc": ["2015-12-22T21:15:00Z", "2015-12-23T22:00:00Z" ]
}
如果访问跨越三/四/等天,您只需用到达和离开之间的天数"填充"数组
{
"id": "c223a991-b4e7-4333-ba45-a576010b568b",
"buildingId": "48da1a81-fa73-4d4f-aa22-a5750162ed1e",
"visitDateTimeUtc": ["2015-12-22T21:15:00Z", "2015-12-23T22:00:00Z", "2015-12-24T22:00:00Z", "2015-12-25T22:00:00Z" ]
}
这样,您的date_histogram
聚合将考虑间隔的所有日期。
考虑通过在 ES 模型上为 VisitDays
创建一个新的数组属性来解决此问题,因此,如果有人在 2015 年 1 月 1 日至 2015 年 1 月 5 日期间停留,那么您的模型将是这样的:
{
"id" : "c223a991-b4e7-4333-ba45-a576010b568b",
// other properties
"buildingId" : "48da1a81-fa73-4d4f-aa22-a5750162ed1e",
"arrivalDateTimeUtc" : "2015-01-01T21:15:00Z",
"departureDateTimeUtc" : "2015-01-05T22:00:00Z", // new property
"visitDays" : [
"2015-01-01",
"2015-01-02",
"2015-01-03",
"2015-01-04",
"2015-01-05"
]
}
如果您这样做,那么您的存储桶将非常容易且非常快速。 脚本字段不会很快。 而且您 100% 正确,尝试在 C# 中执行此操作是行不通的,因为它太慢了。