Elasticsearch嵌套对象管理
1. 索引包括嵌套对象、
嵌套对象可以表达关系型数据库中一对多关系,同时增强检索能力。下面定义human索引包括cats嵌套对象,定义mapping:
PUT human
{
"mappings": {
"properties": {
"name": {
"type": "text"
},
"cats": {
"type": "nested",
"properties": {
"colors": {
"type": "integer"
},
"name": {
"type": "text"
},
"breed": {
"type": "keyword"
}
}
}
}
}
}
Human有name
属性和嵌套对象cats
;cats包括下面三个属性:colors,name,breed
。
下面增加一个文档带有三个cat:
PUT /human/_doc/1
{
"name": "iridakos",
"cats": [
{
"colors": 1,
"name": "Irida",
"breed": "European Shorthair"
},
{
"colors": 2,
"name": "Phoebe",
"breed": "European"
},
{
"colors": 3,
"name": "Nino",
"breed": "Aegean"
}
]
}
查询文档确认添加:
GET /human/_doc/1
返回结果:
{
"_index" : "human",
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 0,
"_primary_term" : 1,
"found" : true,
"_source" : {
"name" : "iridakos",
"cats" : [
{
"colors" : 1,
"name" : "Irida",
"breed" : "European Shorthair"
},
{
"colors" : 2,
"name" : "Phoebe",
"breed" : "European"
},
{
"colors" : 3,
"name" : "Nino",
"breed" : "Aegean"
}
]
}
}
2. 维护嵌套对象
下面讨论如何对嵌套对象进行添加、修改、删除。
2.1. 添加嵌套对象
增加一个嵌套对象Leon
。使用_update
api:
POST /human/_update/1
{
"script": {
"source": "ctx._source.cats.add(params.cat)",
"params": {
"cat": {
"colors": 4,
"name": "Leon",
"breed": "Persian"
}
}
}
}
通过ctx._source.cats
访问嵌套对象,返回collection,执行add
方法增加新的cat。新cat属性通过params传入。
2.2. 删除嵌套对象
我们现在删除cat集合中删除Nino
:
POST /human/_update/1
{
"script": {
"source": "ctx._source.cats.removeIf(cat -> cat.name == params.cat_name)",
"params": {
"cat_name": "Nino"
}
}
}
通过ctx._source.cats
返回集合,通过removeIf方法有条件删除条目。removeIf方法参数为Predicate,确定是否要删除特定条目。predicate在集合中每个条目上执行,返回值为Boolean,true则删除,我们示例通过判断name属性使用与参数cat_name
相同。
2.3. 修改嵌套对象
修改所有cat的属性breeds 为 European 修改为 European Shorthair:
POST /human/_update/1
{
"script": {
"source": "def targets = ctx._source.cats.findAll(cat -> cat.breed == params.current_breed); for(cat in targets) { cat.breed = params.breed }",
"params": {
"current_breed": "European",
"breed": "European Shorthair"
}
}
}
ctx._source.cats
返回集合,在集合上执行findAll
方法选择想要的条目,Predicate参数设定条件。查询内容和修改内容都通过参数传入。
2.4. 运用多个条件更新多个属性
现在使用更加灵活脚本实现更复杂的示例。目标对象需要多个条件进行匹配,更新多个属性。
加入我们想修改cat属性breed为Persian,colors为3,修改为Aegean和3 。脚本如下:
POST /human/_update/1
{
"script": {
"source": "def targets = ctx._source.cats.findAll(cat -> { for (condition in params.conditions.entrySet()) { if (cat[condition.getKey()] != condition.getValue()) { return false; } } return true; }); for (cat in targets) { for (change in params.changes.entrySet()) { cat[change.getKey()] = change.getValue() } }",
"params": {
"conditions": {
"breed": "Persian",
"colors": 4
},
"changes": {
"breed": "Aegean",
"colors": 3
}
}
}
}
格式化代码:
def targets = ctx._source.cats.findAll(cat -> {
for (condition in params.conditions.entrySet()) {
if (cat[condition.getKey()] != condition.getValue()) {
return false;
}
}
return true; });
for (cat in targets) {
for (change in params.changes.entrySet()) {
cat[change.getKey()] = change.getValue()
}
}
通过params.conditions
参数确定条件查询目标对象,通过params.changes参数传入修改后的值。
3. 总结
本文介绍Elasticsearch的嵌套对象,通过示例说明如何使用脚本维护嵌套对象。