问题描述
所以我有一组索引产品,其中包含一个带有单个键和一个值列表的字典,我试图用它来构建分面搜索。然而,我是一个非常有弹性的新手。
Product Product {
Dictionary<string,List<string>> Properties
//extra fields removed for simplicity
}
其中属性可能类似于
["Color":["Blue","Yellow","Red"],"Size":["Small","Medium","Large"]
或
["Material":["Wood"],"Shape":["Circle","Square"],"Size":["Tiny","Large","Huge"]
我希望编写一些聚合,它们将返回键以及这些键的值。
即如果上面的例子要被索引,第一个聚合将返回一个包含 "Color","Size","Material","Shape"
并且第二个聚合将返回 4 个桶,每个桶都有每个键的唯一值。
即Size:["Tiny","small","medium","large","huge"]
等
我意识到我需要为此进行嵌套聚合,但是我的尝试都没有带回桶中的任何东西。任何指针将不胜感激。这是我目前所拥有的。
var ProductsQuery = client.Search<Product>(s => s
.Index("products")
.Query(q => q.MatchAll())
.Aggregations(a => a
.nested("properties",n => n
.Path(p => p.Properties.Suffix("keyword"))
.Aggregations(a => a
.Terms("property-keys",t => t
.Field(f => f.Properties.Keys.Suffix("keyword"))))));
编辑一些要求的细节:
当前的属性映射(它似乎为每个 Key 创建一个新映射,我不确定这是否是典型的?)我没有把整个对象映射放在这里,因为它相当大。产品有很多字段:
"properties" : {
"properties" : {
"Colour" : {
"type" : "text","fields" : {
"keyword" : {
"type" : "keyword","ignore_above" : 256
}
}
},"Equipment" : {
"type" : "text","Football Age" : {
"type" : "text","Football Size" : {
"type" : "text","Frame Weight" : {
"type" : "text","Garment" : {
"type" : "text","Head Shape" : {
"type" : "text","Level" : {
"type" : "text","Product" : {
"type" : "text","Size" : {
"type" : "text","Sport" : {
"type" : "text","Surface" : {
"type" : "text","Type" : {
"type" : "text","Unit" : {
"type" : "text","Weight" : {
"type" : "text","comparer" : {
"type" : "object"
},"count" : {
"type" : "integer"
},"item" : {
"type" : "text","keys" : {
"properties" : {
"count" : {
"type" : "integer"
}
}
},"values" : {
"properties" : {
"count" : {
"type" : "integer"
}
}
}
}
}
和一些索引文档
"hits" : [
{
"_index" : "products-20-01-2021-13-49-08","_type" : "_doc","_id" : "134550","_score" : 1.0,"_source" : {
"properties" : {
"Type" : [
"Sleds"
],"Product" : [
"Sleds"
],"Colour" : [
"Black"
]
}
}
},{
"_index" : "products-20-01-2021-13-49-08","_id" : "134566","_source" : {
"properties" : {
"Sport" : [
"fitness"
],"Type" : [
"Corner","Edge","Middle"
],"Size" : [
"10mm","15mm","20mm"
],"Product" : [
"Floor Matting"
]
}
}
},"_id" : "134576","_source" : {
"properties" : {
"Sport" : [
"Rugby"
],"Type" : [
"Skills Training"
],"Equipment" : [
"Rugby Balls"
],"Size" : [
"4","5"
],"Level" : [
"Skills"
]
}
}
},"_id" : "134579","Type" : [
"Match Union"
],"Level" : [
"Club"," School"
],"Unit" : [
"12 Pack","Each"
],"Colour" : [
"Blue","Red","White"
]
}
}
},"_id" : "134600","Size" : [
"Large","Small","X/Large","X/Small","XX/Small","XXX/Small"
],"Garment" : [
"gloves"
],"Colour" : [
"Red"
]
}
}
},"_id" : "134601","_source" : {
"properties" : {
"Sport" : [
"Netball"
],"_id" : "134609","Colour" : [
"Black","Green"
]
}
}
},"_id" : "134617","_source" : {
"properties" : {
"Sport" : [
"Football"
],"Type" : [
"Training"
],"Football Size" : [
"2"
],"Equipment" : [
"Footballs"
],"Weight" : [
"290","360"
],"Surface" : [
"Grass"," Astroturf"
],"Football Age" : [
"9-14 years"," 14+ years"
]
}
}
},"_id" : "134548","Grey"
]
}
}
},"_id" : "134558","_source" : {
"properties" : {
"Sport" : [
"Squash"
],"Equipment" : [
"Squash Rackets"
],"Size" : [
"27\""
],"Head Shape" : [
"Bridged Closed Throat"
],"Frame Weight" : [
"Over 160g"
]
}
}
}
]
解决方法
首先,为了获得这些存储桶,您可以使用 Query DSL 说明以下内容:
POST products-*/_search
{
"size": 0,"aggs": {
"by_Colour": {
"terms": {
"field": "properties.Colour.keyword"
}
},"by_Size": {
"terms": {
"field": "properties.Size.keyword"
}
}
}
}
然后需要将其翻译成 NEST 代码 -- 我相信那里有很多示例。
但您的观察是正确的——ES 自动创建了大量映射。 我建议不要使用当前的数据格式,而是使用:
{
"properties": [
{
"key": "Type","values": ["Sleds"]
},{
"key": "Product",{
"key": "Colour","values": ["Black"]
}
]
}
并使 properties
类型为 nested
。
这样您将查询共享路径 properties.key
并在 properties.values.keyword
上聚合。
请记住,nested
字段类型需要它们自己的实际 nested
mapping -- 如果没有正确的映射,您将无法使用嵌套查询。
查看此 related question 和 this answer 以获取更多上下文。