使用Nest与ElasticSearch查询符合生日条件的用户票据
解决Elasticsearch中通过Nest查询指定用户关联票据的问题
索引结构与对应.NET实体类
Elasticsearch索引定义
PUT /customers { "mappings": { "properties": { "customerId": { "type": "integer" }, "name": { "type": "keyword" }, "birthday": { "type": "date", "format": "yyyy-MM-dd" } } } } PUT /tickets { "mappings": { "properties": { "ticketId": { "type": "integer" }, "customerId": { "type": "integer" }, "winning": { "type": "float" } } } }
.NET实体类
public class Customer { public int CustomerId { get; } public string Name { get; } public DateTime Birthday { get; } public Customer(int customerId, string name, DateTime birthday) { CustomerId = customerId; Name = name; Birthday = birthday; } } public class Ticket { public int TicketId { get; } public int CustomerId { get; } // 适配ES中float类型的字段映射 [Number(NumberType.Float)] public decimal Winning { get; } public Ticket(int ticketId, int customerId, decimal winning) { TicketId = ticketId; CustomerId = customerId; Winning = winning; } }
需求
获取所有生日早于1990-01-01的用户所持有的票据。
原代码问题
原代码尝试跨索引做布尔查询,但未通过customerId关联用户和票据,逻辑上只是同时返回符合条件的用户和所有票据,无法得到用户与票据的关联结果;同时使用Search<object>会导致类型映射不安全,难以处理返回数据。
正确实现方案
方案一:分两步查询(逻辑清晰,性能稳定)
先筛选出符合条件的用户ID,再根据ID查询关联票据:
- 获取目标用户ID列表
// 查询生日早于1990-01-01的用户,仅返回customerId字段减少数据传输 var customerIdsResponse = client.Search<Customer>(s => s .Index("customers") .Source(src => src.Include(f => f.CustomerId)) .Query(q => q .DateRange(dr => dr .Field(f => f.Birthday) .LessThan(new DateTime(1990, 1, 1)) ) ) ); var targetCustomerIds = customerIdsResponse.Documents.Select(c => c.CustomerId).ToList();
- 根据用户ID查询关联票据
// 查询指定用户持有的所有票据 var ticketsResponse = client.Search<Ticket>(s => s .Index("tickets") .Query(q => q .Terms(t => t .Field(f => f.CustomerId) .Terms(targetCustomerIds) ) ) ); // 最终结果:符合条件的票据集合 var resultTickets = ticketsResponse.Documents;
方案二:单次子查询(合并为一次请求)
借助Nest的Terms Lookup直接关联用户条件,实现单次查询:
var ticketsResponse = client.Search<Ticket>(s => s .Index("tickets") .Query(q => q .Terms(t => t .Field(f => f.CustomerId) .Lookup(l => l .Index("customers") .Id("customerId") .Query(lq => lq .DateRange(dr => dr .Field("birthday") .LessThan(new DateTime(1990, 1, 1)) ) ) ) ) ) ); var resultTickets = ticketsResponse.Documents;
内容的提问来源于stack exchange,提问作者dimmits
相关产品推荐
相关产品推荐

