巨人的肩膀

Update API | Elasticsearch Reference [7.11] | Elastic

Elasticsearch: remove/update field inside nested object

ES中使用nested类型的内嵌对象

需求

对nested(数组)进行操作:

  • 增加元素
  • 删除元素
  • 更新某个元素的值
  • 查询包含有指定特性(如id)的缓存

环境

Docker中启动的ES、Kibana,版本号均为:7.8.1,搭建教程

操作

方便起见,咱们使用分组(Group)与成员(Member)的关系构建测试数据:

  • 定义缓存结构体(重点关注nested):
PUT group/_mapping
{
  "properties": {
    "id": {
      "type": "long"
    },
    "name": {
      "type": "text"
    },
    "members": {
      "type": "nested",
      "properties": {
        "id": {
          "type": "long"
        },
        "name": {
          "type": "text"
        }
      }
    }
  }
}
  • 初始化缓存数据
PUT group/_doc/1
{
  "id": 1,
  "name": "Group1"
}

PUT group/_doc/2
{
  "id": 2,
  "name": "Group2",
  "members": [
    {
      "id": 3,
      "name": "王五"
    }
  ]
}
  • 在Group1的members(nested数组)中增加一个成员:郑十
POST group/_update/1
{
  "script": {
    "source": """
    	if (ctx._source.members == null) {
    		List ls = new ArrayList();
    		ls.add(params.member);
    		ctx._source.members = ls;
    	} else {
			ctx._source.members.add(params.member);
    	}
    """,
    "lang": "painless",
    "params": {
      "member": {
        "id": 10,
        "name": "郑十"
      }
    }
  }
}


【注意】:
务必增加if判断,因为member在doc创建时并没有该字段的值,故该字段此时为null,不能直接通过add追加元素,而应创建一个List并赋值过去。

# 确认member已增加:
GET group/_doc/1
{
  ...
  "_source" : {
    "id" : 1,
    "name" : "Group1",
    "members" : [
      {
        "name" : "郑十",
        "id" : 10
      }
    ]
  }
}
  • 在Group1的members(nested数组)中删除一个成员:id=10
POST group/_update/1
{
  "script": {
    "source": "ctx._source.members.removeIf(list_item -> list_item.id == params.member_id)",
    "lang": "painless",
    "params": {
      "member_id": 10
    }
  }
}

# 确认member已删除:
GET group/_doc/1
{
  ...
  "_source" : {
    "id" : 1,
    "name" : "Group1",
    "members" : [
      {
        "id" : 1,
        "name" : "张三"
      },
      {
        "id" : 2,
        "name" : "李四"
      }
    ]
  }
}
  • 在Group1的members(nested数组)中更新id=1的member.name为张三1
POST group/_update/1
{
	"script": {
	  "source": "for (item in ctx._source.members) {if(item['id']==params.member_id){item['name']=params.name_new}}",
	  "lang": "painless",
	  "params": {
	    "member_id":1,
	    "name_new": "张三1"
	  }
	}
}

# 确认member已更新:
GET group/_doc/1
{
  ...
  "_source" : {
    "id" : 1,
    "name" : "Group1",
    "members" : [
      {
        "id" : 1,
        "name" : "张三1"
      },
      {
        "id" : 2,
        "name" : "李四"
      }
    ]
  }
}
  • 查询含有id=1的member的Group(重点关注nested):
GET group/_search
{
  "query": {
    "nested": {
      "path": "members",
      "query": {
        "bool": {
          "must": [
            {
              "match": {
                "members.id": 1
              }
            }
          ]
        }
      }
    }
  }
}

# 查询结果:
{
  ...
  "hits" : {
    ...
    "hits" : [
      {
        "_index" : "group",
        "_type" : "_doc",
        "_id" : "1",
        "_score" : 1.0,
        "_source" : {
          "id" : 1,
          "name" : "Group1",
          "members" : [
            {
              "id" : 1,
              "name" : "张三1"
            },
            {
              "id" : 2,
              "name" : "李四"
            }
          ]
        }
      }
    ]
  }
}

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐