zoukankan      html  css  js  c++  java
  • Update API

    Update API可以根据提供的脚本更新文档。 该操作从索引获取文档,运行脚本(脚本语言和参数是可选的),并返回操作的结果(也允许删除或忽略该操作)。 使用版本控制来确保在“get”(查询文档)和“reindex”(重新索引文档)期间没有发生更新。

    值得注意的是,该操作会重新索引文档(也就是说更新操作会先查文档,对文档合并,删除之前的文档,重新添加合并的文档。),它只是减少了网络往返以及减少了get(获取文档)和index(索引文档)之间版本冲突的可能性。 需要启用_source字段才能使此特性生效。

    比如,索引一个简单的文档:

    PUT test/_doc/1
    {
        "counter" : 1,
        "tags" : ["red"]
    }

    Scripted updates

    以下示例演示了如何执行一个增加counter的脚本:

    POST test/_doc/1/_update
    {
        "script" : {
            "source": "ctx._source.counter += params.count",
            "lang": "painless",
            "params" : {
                "count" : 4
            }
        }
    }

    现在我们就可以往tags列表里添加一个tag(注意,如果tag存在,仍会添加,因为它是一个list)

    POST test/_doc/1/_update
    {
        "script" : {
            "source": "ctx._source.tags.add(params.tag)",
            "lang": "painless",
            "params" : {
                "tag" : "blue"
            }
        }
    }

    不止_source,以下变量也可以通过ctx来取得: _index, _type, _id, _version, _routing and _now(当前的时间戳)

    以下示例演示了如何获取_id,比如:

    POST test/_doc/1/_update
    {
        "script" : "ctx._source.tags.add(ctx._id)"
    }

    也可以向文档添加新字段:

    POST test/_doc/1/_update
    {
        "script" : "ctx._source.new_field = 'value_of_new_field'"
    }

    从文档移除某个字段:

    POST test/_doc/1/_update
    {
        "script" : "ctx._source.remove('new_field')"
    }

    甚至可以改变已执行的操作。 以下示例:如果标签字段包含green,将删除doc,否则它不执行任何操作(即该操作会被忽略,返回noop):

    POST test/_doc/1/_update
    {
        "script" : {
            "source": "if (ctx._source.tags.contains(params.tag)) { ctx.op = 'delete' } else { ctx.op = 'none' }",
            "lang": "painless",
            "params" : {
                "tag" : "green"
            }
        }
    }

    更新部分文档

    update API还支持传递部分文档,该部分文档将合并到现有文档中(简单的递归合并,对象的内部合并,替换核心"keys/values"和数组)。 要完全替换现有文档,应使用index API。 以下示例演示了如何使用部分更新向现有文档添加新字段:

    POST test/_doc/1/_update
    {
        "doc" : {
            "name" : "new_name"
        }
    }

    如果同时指定了doc和script,会报错。 最好是将部分文档的字段对放在脚本本身中(目前我还不知道该怎么操作)。

    POST test/_doc/1/_update
    {
      "doc" : {
            "age" : "18"
        },
        "script" : {
            "source": "ctx._source.counter += params.count",
            "lang": "painless",
            "params" : {
                "count" : 4
            }
        }
    }

    返回结果如下:

    {
      "error": {
        "root_cause": [
          {
            "type": "action_request_validation_exception",
            "reason": "Validation Failed: 1: can't provide both script and doc;"
          }
        ],
        "type": "action_request_validation_exception",
        "reason": "Validation Failed: 1: can't provide both script and doc;"
      },
      "status": 400
    }

    检测noop更新
    如果指定了doc,则其值将与现有_source合并。 默认情况下,不更改任何内容的更新,会检测到并会返回“result”:“noop”,如下所示:

    POST test/_doc/1/_update
    {
        "doc" : {
            "name" : "new_name"
        }
    }

    如果在发送请求之前name是new_name,则忽略整个更新请求。 如果请求被忽略,响应中的result元素将返回noop。

    {
      "_index": "test",
      "_type": "_doc",
      "_id": "1",
      "_version": 2,
      "result": "noop",
      "_shards": {
        "total": 0,
        "successful": 0,
        "failed": 0
      }
    }

    设置"detect_noop": false可以禁用这种默认行为:

    POST test/_doc/1/_update
    {
        "doc" : {
            "name" : "new_name"
        },
        "detect_noop": false
    }

    Upserts

     如果文档尚不存在,则upsert元素的内容将作为新文档插入。 如果文档确实存在,则执行脚本:

    POST test/_doc/1/_update
    {
        "script" : {
            "source": "ctx._source.counter += params.count",
            "lang": "painless",
            "params" : {
                "count" : 4
            }
        },
        "upsert" : {
            "counter" : 1
        }
    }

    当然,不一定非得脚本,下面这样也是可以的,文档不存在的时候执行upsert内容,文档存在的时候执行doc的内容:

    POST test/_doc/1/_update
    {
        "doc" : {
            "name" : "new_name"
        },
        "upsert" : {
            "counter" : 10
        }
    }

    scripted_upsert
    如果希望无论文档是否存在,都运行脚本(即使用脚本处理初始化文档而不是upsert元素)可以将scripted_upsert设置为true:

    POST sessions/session/dh3sgudg8gsrgl/_update
    {
        "scripted_upsert":true,
        "script" : {
            "id": "my_web_session_summariser",
            "params" : {
                "pageViewEvent" : {
                    "url":"foo.com/bar",
                    "response":404,
                    "time":"2014-01-01 12:32"
                }
            }
        },
        "upsert" : {}
    }

    下面来看看和直接写脚本不用upsert的区别,当文档不存在时,直接下面这样写会报错。

    POST test/_doc/1/_update
    {
        "scripted_upsert":true,
        "script" : {
            "source": "ctx._source.counter += params.count",
            "lang": "painless",
            "params" : {
                "count" : 4
            }
        }
    }

    返回错误消息如下:

    {
      "error": {
        "root_cause": [
          {
            "type": "document_missing_exception",
            "reason": "[_doc][1]: document missing",
            "index_uuid": "YgmlkeEERGm20yUBDJHKtQ",
            "shard": "3",
            "index": "test"
          }
        ],
        "type": "document_missing_exception",
        "reason": "[_doc][1]: document missing",
        "index_uuid": "YgmlkeEERGm20yUBDJHKtQ",
        "shard": "3",
        "index": "test"
      },
      "status": 404
    }

    设置scripted_upsert:true,当文档不存在时,执行下面的代码:

    POST test/_doc/1/_update
    {
        "scripted_upsert":true,
        "script" : {
            "source": "ctx._source.counter += params.count",
            "lang": "painless",
            "params" : {
                "count" : 4
            }
        },
        "upsert" : {
            "counter" : 10
        }
    }

    返回的结果如下:

    {
      "_index": "test",
      "_type": "_doc",
      "_id": "1",
      "_version": 1,
      "result": "created",
      "_shards": {
        "total": 2,
        "successful": 1,
        "failed": 0
      },
      "_seq_no": 6,
      "_primary_term": 1
    }

    可见,执行成功了,下面来看看文档:

    {
      "_index": "test",
      "_type": "_doc",
      "_id": "1",
      "_version": 1,
      "found": true,
      "_source": {
        "counter": 14
      }
    }

    counter的值为14,可见是先执行了upsert的内容,然后执行了脚本。

    doc_as_upsert
    将doc_as_upsert设置为true将使用doc的内容作为upsert值,而不是发送部分doc加上upsert文档:

    POST test/_doc/1/_update
    {
        "doc" : {
            "name" : "new_name"
        },
        "doc_as_upsert" : true
    }

    下面来看看和直接写doc的区别:

    POST test/_doc/1/_update
    {
        "doc" : {
            "name" : "new_name"
        }
    }

    当文档不存在时,设置doc_as_upsert为true,可以成功执行。而上面这种情况会报错,提示文档不存在。如果向下面这样写会出现什么情况呢?

    POST test/_doc/1/_update
    {
        "doc" : {
            "name" : "new_name"
        },
        "upsert" : {
            "counter" : 10
        },
        "doc_as_upsert" : true
    }

    结果是upsert永远不会被执行,不管文档存在不存在,始终执行的是doc的内容。

    Parameters

     update操作支持以下query-string(跟在请求url后面)参数:

    retry_on_conflict:在更新的get和indexing阶段之间,另一个进程可能已经更新了同一文档。 默认情况下,会更新失败,因为版本冲突异常。 retry_on_conflict参数控制在最终抛出异常之前重试更新的次数。

    routing:路由用于将更新请求路由到正确的分片,以及在将要更新的文档不存在时为upsert请求设置路由。 不能用于更新现有文档的路由。

    timeout:设置等待分片变为可用的时间。

    wait_for_active_shards:在继续更新操作之前需要处于活动状态的分片副本数。 详情请见此处

    refresh:控制何时该请求所做的更改对搜索可见。 看refresh

    _source:允许控制是否返回以及如何在响应中返回更新的源。 默认情况下,不会返回更新的源。 请参阅源过滤了解详细信息

    version:update API在内部使用Elasticsearch的versioning支持,以确保在更新期间文档不会更改。 可以使用version参数指定仅在文档版本与指定版本匹配时才更新文档。

    update API不支持internal以外的版本,也就是说update API不支持外部(版本类型external&external_gte)或强制(版本类型force)版本,因为它会导致Elasticsearch版本号与外部系统不同步。 请改用index API

    官方文档:https://www.elastic.co/guide/en/elasticsearch/reference/current/docs-update.html

  • 相关阅读:
    ThinkJava-复用类
    ThinkJava-访问权限控制
    ElasticSearch 5.0及head插件安装
    安装Elasticsearch5.0 部署Head插件
    Elasticsearch 5.1.1 head插件安装指南
    使用logstash+elasticsearch+kibana快速搭建日志平台
    logstash使用操作部分
    ELK 集中日志分析 windows部署实战
    关于异步,同步,阻塞与非阻塞
    Zookeeper的集群配置和Java测试程序
  • 原文地址:https://www.cnblogs.com/ginb/p/9413382.html
Copyright © 2011-2022 走看看