美文网首页程序员ElasticSearch
ElasticSearch 怎样更新list中的元素

ElasticSearch 怎样更新list中的元素

作者: 追杀丘比特 | 来源:发表于2018-03-06 09:20 被阅读0次
    {
      "_index": "school",
      "_type": "student",
      "_id": "id_4",
      "_version": 1,
      "_score": 1,
      "_source": {
        "name": "this name is name",
        "id": 4,
        "tags": [
          "班长",
          "学习委员",
          "文艺委员"
        ]
      }
    }
    

    可以看到在以上数据中tags为list类型,假设在一个业务场景中,我们需要对这个list中的值进行更新(删除或者添加),按照常规的操作方式,我们可能需要先取出tags的所有值,然后利用elastic search的Partial更新来更新tags的值。其实相比较与这种更新方式,es提供的构建Script来实现这种操作可能更加符合业务需求,如下:

    1.建立一个TransPortClient

    public class OldTransportClient {
        private Logger logger = Logger.getLogger(OldTransportClient.class);
    
        private TransportClient client;
        private IndicesAdminClient adminClient;
    
        @Value("${es.host}")
        private String host;
    
        @PostConstruct
        @SuppressWarnings({ "unchecked", "resource" })
        public synchronized TransportClient setupTransportClient() throws UnknownHostException {
            if (client == null) {
                Settings settings = Settings.builder().put("cluster.name", "ceiec-test")
                        .put("client.transport.sniff", true).build();
                client = new PreBuiltTransportClient(settings)
                        .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), 9300));
                logger.info("====== transport client set up! =======");
            }
            return client;
        }
    
        public synchronized IndicesAdminClient setupAdminClient() {
            if (client != null) {
                if (adminClient == null) {
                    adminClient = client.admin().indices();
                    logger.info("===== admin client set up ======");
                }
            }else {
                logger.error("transport client is not set up,please set up it!");
            }
            return adminClient;
        }
    }
    

    2.新建一个Script

     /**
         * update item with array in elasticSearch
         * @param index
         * @param type
         * @param id
         * @param value
         * @param delete : (default false)
         *          -----> true  delete an element from array
         *          -----> false add an element to array
         * @throws Exception
         */
    public void updateExistList(String index,String type,String id,String field,String value,boolean isDelete) throws Exception{
            client = oldclient.setupTransportClient();
            Map<String,Object> params = new HashMap<>();
            params.put(field,value);
            String script_str;
            if (isDelete){
               script_str = "if (ctx._source."+field+".indexOf(params."+field+") != -1){" +
                        "ctx._source."+field+".remove(ctx._source."+field+".indexOf(params."+field+"))}";
            }else {
              //表示如果该doc不包含该字段,在该doc新建字段并赋值value,
              //如果存在该字段,会比较传入的值是否存在于list中,如果不存在就添加
                script_str = "if(!ctx._source.containsKey('"+field+"')){ctx._source."+field+"=[params."+field+"]}else{" +
                        "if (ctx._source."+field+".indexOf(params."+field+") == -1){ ctx._source."+field+".add(params."+field+")}}";
            }
            Script script = new Script(ScriptType.INLINE,Script.DEFAULT_SCRIPT_LANG,script_str,params);
            logger.info("script:\n"+script);
            UpdateResponse updateResponse = client.prepareUpdate(index,type,id)
                    .setScript(script)
                    .get();
            System.out.println(updateResponse.status());
        }
    

    通过以上操作,我们就可以对es中的list数据进行增加和删除.

    以上是针对es的list存储的是简单类型比如String,number等类型进行的操作,那么假如list里面存储的是Object类型该怎么做呢,现在有如下的数据:

    {
      "_index": "school",
      "_type": "student",
      "_id": "id_2",
      "_version": 9,
      "_score": 1,
      "_source": {
        "name": "this name is name",
        "id": 2,
        "tags": [
          "班长",
          "学习委员",
          "文艺委员"
        ],
        "permission": [
          {
            "user": "user1",
            "name": "zhangsan2"
          },
          {
            "user": "user2",
            "name": "zhangsan2"
          },
          {
            "user": "user3",
            "name": "zhangsan3"
          },
          {
            "user": "user3",
            "name": "zhangsan3"
          },
          {
            "user": "user4",
            "name": "zhangsan3"
          }
        ]
      }
    }
    

    我们可以看到permission字段是存储着Object的list,那我们想更新其中的元素该怎么操作呢?
    其实方法很类似,我们只需要构建不同的script就可以实现啦,如下:

    /**
    * @param index
    * @param type
    * @param id
    * @param field 需更新的字段
    * @param value
    * @param delete : (default false)
    *          -----> true  delete an element from array
    *          -----> false add an element to array
    * @throws Exception
    */
    public void updateExistListObject(String index,String type,String doc_id,Object o,String field,boolean isDelete) throws Exception{
            client = oldclient.setupTransportClient();
            Map<String,String> map = (Map<String, String>) o;
            String property = (String) map.keySet().toArray()[0];
            Map<String,Object> params = new HashMap<>();
            params.put(field,o);
            String script_str;
            if (isDelete){
               script_str = "for (int i=0;i<ctx._source."+field +".size();i++)" +
                        "{ if(ctx._source."+field+"[i]['"+property+"'] == params."+field+"."+property+")"+
                        "{ctx._source."+field+".remove(i)}}";
            }else {
              //表示如果该doc不包含该字段,在该doc新建字段并赋值value,
              //如果存在该字段,会比较传入的对象是否存在于list中存在的对象相等,如果不相等就添加,相等就更新
               script_str = "if(!ctx._source.containsKey('"+field+"'))" + "{ctx._source."+field+"=[params."+field+"]} " +
                        "else { for(int i=0; i<ctx._source."+ field +".size(); i++)"+
                        "{ if (ctx._source."+field+"[i]['"+property+ "'] != params."+ field+"."+property+")
                         {ctx._source."+field+".add(params."+field+");break;}}}";
            }
            Script script = new Script(ScriptType.INLINE,Script.DEFAULT_SCRIPT_LANG,script_str,params);
            logger.info("script:\n"+script);
            UpdateResponse updateResponse = client.prepareUpdate(index,type,doc_id)
                    .setScript(script)
                    .get();
            System.out.println(updateResponse.status());
        }
    

    script可以实现相当复杂的功能,因此需要大家在实践中去构建符合自己业务逻辑的script。

    相关文章

      网友评论

        本文标题:ElasticSearch 怎样更新list中的元素

        本文链接:https://www.haomeiwen.com/subject/luclfftx.html