使用C# NEST API查询Elasticsearch复杂数据类型的问题
我在使用Elasticsearch的C# NEST API查询包含复杂数据类型(嵌套数组)的文档时遇到了问题。我的Elasticsearch中的文档结构示例如下:
"hits": [ { "_index": "post", "_type": "postmodel", "_source": { "projectId": "2", "language": "en", "postDate": "2017-06-11T08:39:32Z", "profiles": [ { "label": "Emotional", "confidence": 1 } ] } }, { "_index": "post", "_type": "postmodel", "_source": { "projectId": "3", "language": "en", "postDate": "2017-06-11T08:05:01Z", "profiles": [ { "label": "Fact oriented", "confidence": 0.69 }, { "label": "Rational", "confidence": 1 } ] } } ]
我希望通过C# NEST API获取projectId=3且profiles数组中包含label为"Rational"的PostModel文档。目前我已经写了部分查询代码,但不知道如何扩展它来实现对Profiles字段的查询:
var postModels = await _elasticClient.SearchAsync<PostModel>(s => s .Index("post") .Query(q => { QueryContainer query = new QueryContainer(); query = query && q.Match(m => m.Field(f => f.ProjectId) .Query("3")); return query; }));
恳请大家帮忙扩展这段代码以实现需求。
要实现你的需求,你需要针对嵌套的profiles数组字段使用合适的查询方式,这里分两种常见场景来处理:
场景1:Profiles是普通对象数组(非嵌套映射)
如果你的profiles字段在Elasticsearch中是普通的对象数组(没有配置为nested类型),可以直接用Term查询匹配label字段,再和projectId的查询组合:
var postModels = await _elasticClient.SearchAsync<PostModel>(s => s .Index("post") .Query(q => q.Match(m => m.Field(f => f.ProjectId).Query("3")) && q.Term(t => t.Field(f => f.Profiles.First().Label).Value("Rational")) ));
这里用Profiles.First().Label是因为NEST需要一个具体的属性路径来生成正确的查询DSL,最终会被转换成Elasticsearch能识别的profiles.label字段路径。
场景2:Profiles配置为嵌套类型(推荐方案)
如果你的profiles字段在Elasticsearch中被映射为nested类型(这是处理对象数组的最佳实践,能避免跨对象的错误匹配),就需要用Nested查询来精准匹配数组中的单个对象。
首先确保你的PostModel类有正确的映射标记:
public class PostModel { public string ProjectId { get; set; } public string Language { get; set; } public DateTime PostDate { get; set; } [Nested] // 标记该属性为嵌套类型 public List<Profile> Profiles { get; set; } } public class Profile { public string Label { get; set; } public double Confidence { get; set; } }
然后使用Nested查询组合条件:
var postModels = await _elasticClient.SearchAsync<PostModel>(s => s .Index("post") .Query(q => q.Match(m => m.Field(f => f.ProjectId).Query("3")) && q.Nested(n => n .Path(p => p.Profiles) .Query(nq => nq.Term(t => t.Field(f => f.Profiles.First().Label).Value("Rational"))) ) ));
为什么推荐嵌套类型?
如果不使用嵌套类型,Elasticsearch会把对象数组扁平化存储,可能导致错误匹配——比如一个对象的label是"Fact oriented",另一个的confidence是1,查询label:Fact oriented AND confidence:1会错误匹配到该文档,但实际上没有单个对象同时满足这两个条件。嵌套类型能确保查询条件是针对数组中单个对象的。
内容的提问来源于stack exchange,提问作者Mikail

