使用Nest C#操作Elasticsearch按分类名分组报错及同请求取文档数据问题
Elasticsearch查询问题解答
问题1:使用cat_name作为分组字段返回400错误解决
原因
你索引配置中cat_name是text类型,该类型字段会被分词处理,Elasticsearch默认禁止直接对text类型字段执行terms聚合(强制开启fielddata会占用大量内存,官方不推荐)。
解决方法
直接使用cat_name自带的keyword子字段进行分组,该字段为不分词的精确匹配类型,完全适配terms聚合需求。
C#代码中只需修改terms聚合的字段配置,添加Suffix("keyword")即可:
.Terms("catname", t => t // 替换原来的categoryid字段,使用cat_name的keyword子字段 .Field(f => f.cat_name.Suffix("keyword")) .Size(1000) // 不推荐用int.MaxValue,根据实际分类数量设置合理值避免性能问题 .Aggregations(agg => agg .Max("maxprice", av => av.Field(f2 => f2.price)) .Average("avgprice", av => av.Field(f3 => f3.price)) .Max("maxweight", av => av.Field(f2 => f2.weight)) .Average("avgweight", av => av.Field(f3 => f3.weight)) ) )
问题2:同一次请求同时获取聚合结果和具体文档
两种场景对应不同实现方案:
场景1:获取全局匹配的所有文档数据
直接取消你代码中Size参数的注释即可,Elasticsearch默认会返回Size条匹配的原始文档,同时返回聚合结果。注意不要设置为int.MaxValue,单页查询建议最大不超过10000,超出请用from+size分页、search_after或者滚动查询实现。
场景2:获取每个分类分组下的对应文档
在terms聚合下新增TopHits子聚合,即可返回每个分组内的匹配文档,可自定义返回条数、字段、排序规则:
.Terms("catname", t => t .Field(f => f.cat_name.Suffix("keyword")) .Size(1000) .Aggregations(agg => agg .Max("maxprice", av => av.Field(f2 => f2.price)) .Average("avgprice", av => av.Field(f3 => f3.price)) .Max("maxweight", av => av.Field(f2 => f2.weight)) .Average("avgweight", av => av.Field(f3 => f3.weight)) // 新增TopHits聚合返回每个分类下的商品 .TopHits("group_products", th => th .Size(10) // 每个分类返回10条商品 .Source(s => s.IncludeAll()) // 可自定义要返回的字段 ) ) )
注意事项
cat_name.keyword的ignore_above参数为256,若分类名称长度超过256字符会被自动截断,导致分组结果不准,可根据业务需求调整该参数值。- 无论查询还是聚合的
Size参数都禁止设置为int.MaxValue,过大的返回值会导致Elasticsearch内存溢出、服务卡顿。
内容的提问来源于stack exchange,提问作者Divyaprakash Verma
相关产品推荐
相关产品推荐

