我有为了简化具有两个字段Id和ProductAttributes的定义如下面的嵌套目标产物指数:
public class ProductType
{
public Guid Id { get; set; }
public List<ProductAttribute> ProductAttributes { get; set; }
}
public class ProductAttribute
{
public Guid Id { get; set; }
public string Name { get; set; }
public string Value { get; set; }
}
而下面的映射:
elasticClient.CreateIndex("product", i => i
.Settings(s => s
.NumberOfShards(2)
.NumberOfReplicas(0)
)
.Mappings(m => m
.Map<ProductType>(map => map
.AutoMap()
.Properties(p => p
.Nested<ProductAttribute>(n => n
.Name(c => c.ProductAttributes)
.AutoMap()
.Properties(nc => nc
.Keyword(t => t
.Name(nn => nn.Name)
)
.Keyword(t => t
.Name(nn => nn.Value)
)
)
)
现在我想更新嵌套的对象内部名称字段,我已经尝试实现一个使用脚本更新如下:
var scriptParams = new Dictionary<string, object>
{
{"name", "new name"}
};
var result = elasticClient.UpdateByQuery<ProductType>(u => u
.Script(sn => sn
.Inline(
$"ctx._source.productAttributes= params.name;"
)
.Params(scriptParams)
)
.Conflicts(Conflicts.Proceed)
.Refresh(true)
);
但是,使用上面的查询我无法更新嵌套的对象,请你告诉我怎么可以更新使用使用巢ES _update_by_query API嵌套的对象?
喜欢看问题就出在这里$“ctx._source.productAttributes = params.name;”
productAttributes是一个对象(嵌套对象)和params.name是一个值(字符串),并且什么ES在查询响应的投诉。
不知道正是你想做的事,如果你的要求是对所有productAttributes元素,你可以试试这个更新的名称是什么:
var result = elasticClient.UpdateByQuery<ProductType>(u => u
.Index("product")
.Script(ss => ss.Source("for(int i=0; i<ctx._source.productAttributes.size(); i++){HashMap myKV = ctx._source.productAttributes.get(i);myKV.put(params.item.fieldName, params.item.fieldValue);}")
.Params(d => d.Add("item", new Dictionary<string, object>()
{
{"fieldName", "name" },
{"fieldValue", "new name" }
})).Lang("painless")));
最后,我已经找到了如何更新名称属性取决于它们的ID如下只有特定的嵌套的对象:
var result = elasticClient.UpdateByQuery<ProductType>(u => u
.Query(q => q
.Nested(n => n
.Path(Infer.Field<ProductType>(ff => ff.ProductAttributes))
.Query(nq => nq
.Term(Infer.Field<ProductType>(ff => ff.ProductAttributes.First().Id), productAttributeId)
)
)
)
.Script(ss => ss.Inline("if (ctx._source.productAttributes != null){for (item in ctx._source.productAttributes){if (item.id == params.id) {item.name = params.name;}}}")
.Params(new Dictionary<string, object>()
{
{"id", productAttributeId},
{"name", productAttributeName}
}).Lang("painless")
)
.Conflicts(Conflicts.Proceed)
.Refresh(true)
);
这里生成的查询:
POST product/producttype/_update_by_query?conflicts=proceed&refresh=true
{
"query": {
"bool": {
"must": [
{
"nested": {
"query": {
"term": {
"productAttributes.id": {
"value": "563243f0-8fbb-4adf-a78d-1339e5971a43"
}
}
},
"path": "productAttributes"
}
}
]
}
},
"script": {
"params": {
"id":"563243f0-8fbb-4adf-a78d-1339e5971a43",
"name": "CPU"
},
"lang": "painless",
"inline": "if (ctx._source.productAttributes != null){for (item in ctx._source.productAttributes){if (item.id == params.id) {item.name = params.name;}}}"
}
}
那么,是什么上面的查询做:
这对于具有productAttribute与563243f0-8fbb-4adf-A78D-1339e5971a43 ID,然后遍历productAttributes嵌套对象只更新与ID属性,然后再重新索引文件的产品首先搜索。
我希望我面临更新的Elasticsearch嵌套对象问题的答案帮助别人。