Elasticsearch.NET 中的复合查询
Compound query in Elasticsearch.NET
假设我有一个索引,里面有一堆 Order
个对象
class Order
{
int CustomerId { get; set; }
DateTime OrderDate { get; set; }
// Other fields
}
对于特定的客户 ID,我可以通过以下查询找出该客户的最后一个订单:
IElasticClient client;
async Task<Order> GetLastOrder(int customerId)
{
var searchResponse = await client.SearchAsync<Order>(s => s
.Query(q => q
.Term(f => f
.Field(e => e.CustomerId)
.Term(customerId)) && q
.DateRange(r => r
.Field(e => e.OrderDate)
.LessThan(DateMath.Now)))
.Sort(o => o
.Descending(e => e.OrderDate))
.Size(1));
return searchResponse.ApiCall.Success
? searchResponse.Documents.First()
: null;
}
但是,为了支持数据加载器模式,我想查询多个客户的最后一个订单,由一组客户 ID 给出。我是这样开始的:
async Task<IDictionary<int, Order>> GetLastOrders(IEnumerable<int> customerIds)
{
var searchResponse = await client.SearchAsync<Order>(s => s
.Query(q => q
.Terms(f => f
.Field(e => e.CustomerId)
.Terms(customerIds)) && q
.DateRange(r => r
.Field(e => e.OrderDate)
.LessThan(DateMath.Now)))
.Sort(o => o
.Descending(e => e.OrderDate))
.Size(1));
return searchResponse.ApiCall.Success
? searchResponse.Documents.ToDictionary(i => i.CustomerId)
: new Dictionary<string, Order>();
}
不幸的是,这不起作用,因为它只是 return 整个查询的第一条记录,它只会 return 一条 Order
。我如何将此查询修改为 return 每个客户 ID 一个 Order
?
Collapse 可用于 return 字段的最高记录
await _client.SearchAsync<Order>(s => s
.Query(q => q
.Terms(f => f
.Field(e => e.CustomerId)
.Terms(cuIds)) && q
.DateRange(r => r
.Field(e => e.OrderDate)
.LessThan(DateMath.Now)))
.Sort(o => o
.Descending(e => e.OrderDate))
.Collapse(c => c.Field(e => e.CustomerId))
.Size(10)
);
DSL 中的相应查询
{
"collapse": {
"field": "customerId"
},
"query": {
"bool": {
"must": [
{
"terms": {
"customerId": [
1,
2
]
}
},
{
"range": {
"orderDate": {
"lt": "now"
}
}
}
]
}
},
"size": 10,
"sort": [
{
"orderDate": {
"order": "desc"
}
}
]
}
假设我有一个索引,里面有一堆 Order
个对象
class Order
{
int CustomerId { get; set; }
DateTime OrderDate { get; set; }
// Other fields
}
对于特定的客户 ID,我可以通过以下查询找出该客户的最后一个订单:
IElasticClient client;
async Task<Order> GetLastOrder(int customerId)
{
var searchResponse = await client.SearchAsync<Order>(s => s
.Query(q => q
.Term(f => f
.Field(e => e.CustomerId)
.Term(customerId)) && q
.DateRange(r => r
.Field(e => e.OrderDate)
.LessThan(DateMath.Now)))
.Sort(o => o
.Descending(e => e.OrderDate))
.Size(1));
return searchResponse.ApiCall.Success
? searchResponse.Documents.First()
: null;
}
但是,为了支持数据加载器模式,我想查询多个客户的最后一个订单,由一组客户 ID 给出。我是这样开始的:
async Task<IDictionary<int, Order>> GetLastOrders(IEnumerable<int> customerIds)
{
var searchResponse = await client.SearchAsync<Order>(s => s
.Query(q => q
.Terms(f => f
.Field(e => e.CustomerId)
.Terms(customerIds)) && q
.DateRange(r => r
.Field(e => e.OrderDate)
.LessThan(DateMath.Now)))
.Sort(o => o
.Descending(e => e.OrderDate))
.Size(1));
return searchResponse.ApiCall.Success
? searchResponse.Documents.ToDictionary(i => i.CustomerId)
: new Dictionary<string, Order>();
}
不幸的是,这不起作用,因为它只是 return 整个查询的第一条记录,它只会 return 一条 Order
。我如何将此查询修改为 return 每个客户 ID 一个 Order
?
Collapse 可用于 return 字段的最高记录
await _client.SearchAsync<Order>(s => s
.Query(q => q
.Terms(f => f
.Field(e => e.CustomerId)
.Terms(cuIds)) && q
.DateRange(r => r
.Field(e => e.OrderDate)
.LessThan(DateMath.Now)))
.Sort(o => o
.Descending(e => e.OrderDate))
.Collapse(c => c.Field(e => e.CustomerId))
.Size(10)
);
DSL 中的相应查询
{
"collapse": {
"field": "customerId"
},
"query": {
"bool": {
"must": [
{
"terms": {
"customerId": [
1,
2
]
}
},
{
"range": {
"orderDate": {
"lt": "now"
}
}
}
]
}
},
"size": 10,
"sort": [
{
"orderDate": {
"order": "desc"
}
}
]
}